1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'dart:async';
6import 'dart:convert';
7import 'dart:io';
8
9import 'package:flutter/foundation.dart';
10import 'package:flutter/services.dart';
11import 'package:path/path.dart' as path;
12import 'package:test_api/scaffolding.dart' as test_package;
13
14import 'binding.dart';
15
16/// Ensure the appropriate test binding is initialized.
17TestWidgetsFlutterBinding ensureInitialized([@visibleForTesting Map<String, String>? environment]) {
18 environment ??= Platform.environment;
19 if (environment.containsKey('FLUTTER_TEST') && environment['FLUTTER_TEST'] != 'false') {
20 return AutomatedTestWidgetsFlutterBinding.ensureInitialized();
21 }
22 return LiveTestWidgetsFlutterBinding.ensureInitialized();
23}
24
25/// Setup mocking of the global [HttpClient].
26void setupHttpOverrides() {
27 HttpOverrides.global = _MockHttpOverrides();
28}
29
30/// Setup mocking of platform assets if `UNIT_TEST_ASSETS` is defined.
31void mockFlutterAssets() {
32 if (!Platform.environment.containsKey('UNIT_TEST_ASSETS')) {
33 return;
34 }
35 final String assetFolderPath = Platform.environment['UNIT_TEST_ASSETS']!;
36 assert(Platform.environment['APP_NAME'] != null);
37 final String prefix = 'packages/${Platform.environment['APP_NAME']!}/';
38
39 /// Navigation related actions (pop, push, replace) broadcasts these actions via
40 /// platform messages.
41 TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
42 SystemChannels.navigation,
43 (MethodCall methodCall) async {
44 return null;
45 },
46 );
47
48 TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMessageHandler(
49 'flutter/assets',
50 (ByteData? message) {
51 assert(message != null);
52 String key = utf8.decode(message!.buffer.asUint8List());
53 File asset = File(path.join(assetFolderPath, key));
54
55 if (!asset.existsSync()) {
56 // For tests in package, it will load assets with its own package prefix.
57 // In this case, we do a best-effort look up.
58 if (!key.startsWith(prefix)) {
59 return null;
60 }
61
62 key = key.replaceFirst(prefix, '');
63 asset = File(path.join(assetFolderPath, key));
64 if (!asset.existsSync()) {
65 return null;
66 }
67 }
68
69 final Uint8List encoded = Uint8List.fromList(asset.readAsBytesSync());
70 return SynchronousFuture<ByteData>(encoded.buffer.asByteData());
71 },
72 );
73}
74
75/// Provides a default [HttpClient] which always returns empty 400 responses.
76///
77/// If another [HttpClient] is provided using [HttpOverrides.runZoned], that will
78/// take precedence over this provider.
79class _MockHttpOverrides extends HttpOverrides {
80 bool warningPrinted = false;
81 @override
82 HttpClient createHttpClient(SecurityContext? context) {
83 if (!warningPrinted) {
84 test_package.printOnFailure(
85 'Warning: At least one test in this suite creates an HttpClient. When '
86 'running a test suite that uses TestWidgetsFlutterBinding, all HTTP '
87 'requests will return status code 400, and no network request will '
88 'actually be made. Any test expecting a real network connection and '
89 'status code will fail.\n'
90 'To test code that needs an HttpClient, provide your own HttpClient '
91 'implementation to the code under test, so that your test can '
92 'consistently provide a testable response to the code under test.'
93 .split('\n')
94 .expand<String>((String line) => debugWordWrap(line, FlutterError.wrapWidth))
95 .join('\n'),
96 );
97 warningPrinted = true;
98 }
99 return _MockHttpClient();
100 }
101}
102
103/// A mocked [HttpClient] which always returns a [_MockHttpRequest].
104class _MockHttpClient implements HttpClient {
105 @override
106 bool autoUncompress = true;
107
108 @override
109 Duration? connectionTimeout;
110
111 @override
112 Duration idleTimeout = const Duration(seconds: 15);
113
114 @override
115 int? maxConnectionsPerHost;
116
117 @override
118 String? userAgent;
119
120 @override
121 void addCredentials(Uri url, String realm, HttpClientCredentials credentials) {}
122
123 @override
124 void addProxyCredentials(
125 String host,
126 int port,
127 String realm,
128 HttpClientCredentials credentials,
129 ) {}
130
131 @override
132 Future<ConnectionTask<Socket>> Function(Uri url, String? proxyHost, int? proxyPort)?
133 connectionFactory;
134
135 @override
136 Future<bool> Function(Uri url, String scheme, String realm)? authenticate;
137
138 @override
139 Future<bool> Function(String host, int port, String scheme, String realm)? authenticateProxy;
140
141 @override
142 bool Function(X509Certificate cert, String host, int port)? badCertificateCallback;
143
144 @override
145 void Function(String line)? keyLog;
146
147 @override
148 void close({bool force = false}) {}
149
150 @override
151 Future<HttpClientRequest> delete(String host, int port, String path) {
152 return Future<HttpClientRequest>.value(_MockHttpRequest());
153 }
154
155 @override
156 Future<HttpClientRequest> deleteUrl(Uri url) {
157 return Future<HttpClientRequest>.value(_MockHttpRequest());
158 }
159
160 @override
161 String Function(Uri url)? findProxy;
162
163 @override
164 Future<HttpClientRequest> get(String host, int port, String path) {
165 return Future<HttpClientRequest>.value(_MockHttpRequest());
166 }
167
168 @override
169 Future<HttpClientRequest> getUrl(Uri url) {
170 return Future<HttpClientRequest>.value(_MockHttpRequest());
171 }
172
173 @override
174 Future<HttpClientRequest> head(String host, int port, String path) {
175 return Future<HttpClientRequest>.value(_MockHttpRequest());
176 }
177
178 @override
179 Future<HttpClientRequest> headUrl(Uri url) {
180 return Future<HttpClientRequest>.value(_MockHttpRequest());
181 }
182
183 @override
184 Future<HttpClientRequest> open(String method, String host, int port, String path) {
185 return Future<HttpClientRequest>.value(_MockHttpRequest());
186 }
187
188 @override
189 Future<HttpClientRequest> openUrl(String method, Uri url) {
190 return Future<HttpClientRequest>.value(_MockHttpRequest());
191 }
192
193 @override
194 Future<HttpClientRequest> patch(String host, int port, String path) {
195 return Future<HttpClientRequest>.value(_MockHttpRequest());
196 }
197
198 @override
199 Future<HttpClientRequest> patchUrl(Uri url) {
200 return Future<HttpClientRequest>.value(_MockHttpRequest());
201 }
202
203 @override
204 Future<HttpClientRequest> post(String host, int port, String path) {
205 return Future<HttpClientRequest>.value(_MockHttpRequest());
206 }
207
208 @override
209 Future<HttpClientRequest> postUrl(Uri url) {
210 return Future<HttpClientRequest>.value(_MockHttpRequest());
211 }
212
213 @override
214 Future<HttpClientRequest> put(String host, int port, String path) {
215 return Future<HttpClientRequest>.value(_MockHttpRequest());
216 }
217
218 @override
219 Future<HttpClientRequest> putUrl(Uri url) {
220 return Future<HttpClientRequest>.value(_MockHttpRequest());
221 }
222}
223
224/// A mocked [HttpClientRequest] which always returns a [_MockHttpResponse].
225class _MockHttpRequest implements HttpClientRequest {
226 @override
227 bool bufferOutput = true;
228
229 @override
230 int contentLength = -1;
231
232 @override
233 late Encoding encoding;
234
235 @override
236 bool followRedirects = true;
237
238 @override
239 final HttpHeaders headers = _MockHttpHeaders();
240
241 @override
242 void add(List<int> data) {}
243
244 @override
245 void addError(Object error, [StackTrace? stackTrace]) {}
246
247 @override
248 Future<void> addStream(Stream<List<int>> stream) {
249 return Future<void>.value();
250 }
251
252 @override
253 Future<HttpClientResponse> close() {
254 return Future<HttpClientResponse>.value(_MockHttpResponse());
255 }
256
257 @override
258 void abort([Object? exception, StackTrace? stackTrace]) {}
259
260 @override
261 HttpConnectionInfo? get connectionInfo => null;
262
263 @override
264 List<Cookie> get cookies => <Cookie>[];
265
266 @override
267 Future<HttpClientResponse> get done async => _MockHttpResponse();
268
269 @override
270 Future<void> flush() {
271 return Future<void>.value();
272 }
273
274 @override
275 int maxRedirects = 5;
276
277 @override
278 String get method => '';
279
280 @override
281 bool persistentConnection = true;
282
283 @override
284 Uri get uri => Uri();
285
286 @override
287 void write(Object? obj) {}
288
289 @override
290 void writeAll(Iterable<dynamic> objects, [String separator = '']) {}
291
292 @override
293 void writeCharCode(int charCode) {}
294
295 @override
296 void writeln([Object? obj = '']) {}
297}
298
299/// A mocked [HttpClientResponse] which is empty and has a [statusCode] of 400.
300// TODO(tvolkert): Change to `extends Stream` once
301// https://dart-review.googlesource.com/c/sdk/+/104525 is rolled into the framework.
302class _MockHttpResponse implements HttpClientResponse {
303 final Stream<Uint8List> _delegate = Stream<Uint8List>.fromIterable(
304 const Iterable<Uint8List>.empty(),
305 );
306
307 @override
308 final HttpHeaders headers = _MockHttpHeaders();
309
310 @override
311 X509Certificate? get certificate => null;
312
313 @override
314 HttpConnectionInfo? get connectionInfo => null;
315
316 @override
317 int get contentLength => -1;
318
319 @override
320 HttpClientResponseCompressionState get compressionState {
321 return HttpClientResponseCompressionState.decompressed;
322 }
323
324 @override
325 List<Cookie> get cookies => <Cookie>[];
326
327 @override
328 Future<Socket> detachSocket() {
329 return Future<Socket>.error(UnsupportedError('Mocked response'));
330 }
331
332 @override
333 bool get isRedirect => false;
334
335 @override
336 StreamSubscription<Uint8List> listen(
337 void Function(Uint8List event)? onData, {
338 Function? onError,
339 void Function()? onDone,
340 bool? cancelOnError,
341 }) {
342 return const Stream<Uint8List>.empty().listen(
343 onData,
344 onError: onError,
345 onDone: onDone,
346 cancelOnError: cancelOnError,
347 );
348 }
349
350 @override
351 bool get persistentConnection => false;
352
353 @override
354 String get reasonPhrase => '';
355
356 @override
357 Future<HttpClientResponse> redirect([String? method, Uri? url, bool? followLoops]) {
358 return Future<HttpClientResponse>.error(UnsupportedError('Mocked response'));
359 }
360
361 @override
362 List<RedirectInfo> get redirects => <RedirectInfo>[];
363
364 @override
365 int get statusCode => 400;
366
367 @override
368 Future<bool> any(bool Function(Uint8List element) test) {
369 return _delegate.any(test);
370 }
371
372 @override
373 Stream<Uint8List> asBroadcastStream({
374 void Function(StreamSubscription<Uint8List> subscription)? onListen,
375 void Function(StreamSubscription<Uint8List> subscription)? onCancel,
376 }) {
377 return _delegate.asBroadcastStream(onListen: onListen, onCancel: onCancel);
378 }
379
380 @override
381 Stream<E> asyncExpand<E>(Stream<E>? Function(Uint8List event) convert) {
382 return _delegate.asyncExpand<E>(convert);
383 }
384
385 @override
386 Stream<E> asyncMap<E>(FutureOr<E> Function(Uint8List event) convert) {
387 return _delegate.asyncMap<E>(convert);
388 }
389
390 @override
391 Stream<R> cast<R>() {
392 return _delegate.cast<R>();
393 }
394
395 @override
396 Future<bool> contains(Object? needle) {
397 return _delegate.contains(needle);
398 }
399
400 @override
401 Stream<Uint8List> distinct([bool Function(Uint8List previous, Uint8List next)? equals]) {
402 return _delegate.distinct(equals);
403 }
404
405 @override
406 Future<E> drain<E>([E? futureValue]) {
407 return _delegate.drain<E>(futureValue);
408 }
409
410 @override
411 Future<Uint8List> elementAt(int index) {
412 return _delegate.elementAt(index);
413 }
414
415 @override
416 Future<bool> every(bool Function(Uint8List element) test) {
417 return _delegate.every(test);
418 }
419
420 @override
421 Stream<S> expand<S>(Iterable<S> Function(Uint8List element) convert) {
422 return _delegate.expand(convert);
423 }
424
425 @override
426 Future<Uint8List> get first => _delegate.first;
427
428 @override
429 Future<Uint8List> firstWhere(
430 bool Function(Uint8List element) test, {
431 List<int> Function()? orElse,
432 }) {
433 return _delegate.firstWhere(
434 test,
435 orElse:
436 orElse == null
437 ? null
438 : () {
439 return Uint8List.fromList(orElse());
440 },
441 );
442 }
443
444 @override
445 Future<S> fold<S>(S initialValue, S Function(S previous, Uint8List element) combine) {
446 return _delegate.fold<S>(initialValue, combine);
447 }
448
449 @override
450 Future<dynamic> forEach(void Function(Uint8List element) action) {
451 return _delegate.forEach(action);
452 }
453
454 @override
455 Stream<Uint8List> handleError(Function onError, {bool Function(dynamic error)? test}) {
456 return _delegate.handleError(onError, test: test);
457 }
458
459 @override
460 bool get isBroadcast => _delegate.isBroadcast;
461
462 @override
463 Future<bool> get isEmpty => _delegate.isEmpty;
464
465 @override
466 Future<String> join([String separator = '']) {
467 return _delegate.join(separator);
468 }
469
470 @override
471 Future<Uint8List> get last => _delegate.last;
472
473 @override
474 Future<Uint8List> lastWhere(
475 bool Function(Uint8List element) test, {
476 List<int> Function()? orElse,
477 }) {
478 return _delegate.lastWhere(
479 test,
480 orElse:
481 orElse == null
482 ? null
483 : () {
484 return Uint8List.fromList(orElse());
485 },
486 );
487 }
488
489 @override
490 Future<int> get length => _delegate.length;
491
492 @override
493 Stream<S> map<S>(S Function(Uint8List event) convert) {
494 return _delegate.map<S>(convert);
495 }
496
497 @override
498 Future<dynamic> pipe(StreamConsumer<List<int>> streamConsumer) {
499 return _delegate.cast<List<int>>().pipe(streamConsumer);
500 }
501
502 @override
503 Future<Uint8List> reduce(List<int> Function(Uint8List previous, Uint8List element) combine) {
504 return _delegate.reduce((Uint8List previous, Uint8List element) {
505 return Uint8List.fromList(combine(previous, element));
506 });
507 }
508
509 @override
510 Future<Uint8List> get single => _delegate.single;
511
512 @override
513 Future<Uint8List> singleWhere(
514 bool Function(Uint8List element) test, {
515 List<int> Function()? orElse,
516 }) {
517 return _delegate.singleWhere(
518 test,
519 orElse:
520 orElse == null
521 ? null
522 : () {
523 return Uint8List.fromList(orElse());
524 },
525 );
526 }
527
528 @override
529 Stream<Uint8List> skip(int count) {
530 return _delegate.skip(count);
531 }
532
533 @override
534 Stream<Uint8List> skipWhile(bool Function(Uint8List element) test) {
535 return _delegate.skipWhile(test);
536 }
537
538 @override
539 Stream<Uint8List> take(int count) {
540 return _delegate.take(count);
541 }
542
543 @override
544 Stream<Uint8List> takeWhile(bool Function(Uint8List element) test) {
545 return _delegate.takeWhile(test);
546 }
547
548 @override
549 Stream<Uint8List> timeout(
550 Duration timeLimit, {
551 void Function(EventSink<Uint8List> sink)? onTimeout,
552 }) {
553 return _delegate.timeout(timeLimit, onTimeout: onTimeout);
554 }
555
556 @override
557 Future<List<Uint8List>> toList() {
558 return _delegate.toList();
559 }
560
561 @override
562 Future<Set<Uint8List>> toSet() {
563 return _delegate.toSet();
564 }
565
566 @override
567 Stream<S> transform<S>(StreamTransformer<List<int>, S> streamTransformer) {
568 return _delegate.cast<List<int>>().transform<S>(streamTransformer);
569 }
570
571 @override
572 Stream<Uint8List> where(bool Function(Uint8List event) test) {
573 return _delegate.where(test);
574 }
575}
576
577/// A mocked [HttpHeaders] that ignores all writes.
578class _MockHttpHeaders implements HttpHeaders {
579 @override
580 List<String>? operator [](String name) => <String>[];
581
582 @override
583 void add(String name, Object value, {bool preserveHeaderCase = false}) {}
584
585 @override
586 late bool chunkedTransferEncoding;
587
588 @override
589 void clear() {}
590
591 @override
592 int contentLength = -1;
593
594 @override
595 ContentType? contentType;
596
597 @override
598 DateTime? date;
599
600 @override
601 DateTime? expires;
602
603 @override
604 void forEach(void Function(String name, List<String> values) f) {}
605
606 @override
607 String? host;
608
609 @override
610 DateTime? ifModifiedSince;
611
612 @override
613 void noFolding(String name) {}
614
615 @override
616 late bool persistentConnection;
617
618 @override
619 int? port;
620
621 @override
622 void remove(String name, Object value) {}
623
624 @override
625 void removeAll(String name) {}
626
627 @override
628 void set(String name, Object value, {bool preserveHeaderCase = false}) {}
629
630 @override
631 String? value(String name) => null;
632}
633

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com