forked from flutter/flutter
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest.dart
More file actions
660 lines (622 loc) · 23.4 KB
/
Copy pathtest.dart
File metadata and controls
660 lines (622 loc) · 23.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Runs the tests for the flutter/flutter repository.
//
// By default, test output is filtered and only errors are shown. (If a
// particular test takes longer than _quietTimeout in utils.dart, the output is
// shown then also, in case something has hung.)
//
// --verbose stops the output cleanup and just outputs everything verbatim.
//
// By default, errors are non-fatal; all tests are executed and the output
// ends with a summary of the errors that were detected.
//
// Exit code is 1 if there was an error.
//
// --abort-on-error causes the script to exit immediately when hitting an error.
//
// By default, all tests are run. However, the tests support being split by
// shard and subshard. Inspect the code to see what shards and subshards are
// supported, or run with `--dry-run` to get a list of tests that _would_ have
// been executed.
//
// For local testing you can just set the SHARD and SUBSHARD environment
// variables. For example, to run all the framework tests you can just set
// SHARD=framework_tests. Some shards support named subshards, like
// SHARD=framework_tests SUBSHARD=widgets. Others support arbitrary numbered
// subsharding, like SHARD=build_tests SUBSHARD=1_2 (where 1_2 means "one of
// two" as in run the first half of the tests).
//
// So for example to run specifically the third subshard of the Web tests you
// would set SHARD=web_tests SUBSHARD=2 (it's zero-based).
//
// By default, where supported, tests within a shard are executed in a random
// order to (eventually) catch inter-test dependencies.
//
// --test-randomize-ordering-seed=<n> sets the shuffle seed for reproducing runs.
//
// All other arguments are treated as arguments to pass to the flutter tool when
// running tests.
import 'dart:convert';
import 'dart:core' as system show print;
import 'dart:core' hide print;
import 'dart:io' as system show exit;
import 'dart:io' hide exit;
import 'dart:math' as math;
import 'package:path/path.dart' as path;
import 'run_command.dart';
import 'suite_runners/run_add_to_app_life_cycle_tests.dart';
import 'suite_runners/run_analyze_tests.dart';
import 'suite_runners/run_android_engine_tests.dart';
import 'suite_runners/run_android_java17_integration_tool_tests.dart';
import 'suite_runners/run_android_preview_integration_tool_tests.dart';
import 'suite_runners/run_customer_testing_tests.dart';
import 'suite_runners/run_docs_tests.dart';
import 'suite_runners/run_flutter_packages_tests.dart';
import 'suite_runners/run_framework_coverage_tests.dart';
import 'suite_runners/run_framework_tests.dart';
import 'suite_runners/run_fuchsia_precache.dart';
import 'suite_runners/run_skp_generator_tests.dart';
import 'suite_runners/run_test_harness_tests.dart';
import 'suite_runners/run_verify_binaries_codesigned_tests.dart';
import 'suite_runners/run_web_tests.dart';
import 'utils.dart';
typedef ShardRunner = Future<void> Function();
/// Environment variables to override the local engine when running `pub test`,
/// if such flags are provided to `test.dart`.
final Map<String, String> localEngineEnv = <String, String>{};
/// When you call this, you can pass additional arguments to pass custom
/// arguments to flutter test. For example, you might want to call this
/// script with the parameter --local-engine=host_debug_unopt to
/// use your own build of the engine.
///
/// To run the tool_tests part, run it with SHARD=tool_tests
///
/// Examples:
/// SHARD=tool_tests bin/cache/dart-sdk/bin/dart dev/bots/test.dart
/// bin/cache/dart-sdk/bin/dart dev/bots/test.dart --local-engine=host_debug_unopt --local-engine-host=host_debug_unopt
Future<void> main(List<String> args) async {
try {
printProgress('STARTING ANALYSIS');
var dryRunArgSet = false;
for (final arg in args) {
if (arg.startsWith('--local-engine=')) {
localEngineEnv['FLUTTER_LOCAL_ENGINE'] = arg.substring('--local-engine='.length);
flutterTestArgs.add(arg);
} else if (arg.startsWith('--local-engine-host=')) {
localEngineEnv['FLUTTER_LOCAL_ENGINE_HOST'] = arg.substring('--local-engine-host='.length);
flutterTestArgs.add(arg);
} else if (arg.startsWith('--local-engine-src-path=')) {
localEngineEnv['FLUTTER_LOCAL_ENGINE_SRC_PATH'] = arg.substring(
'--local-engine-src-path='.length,
);
flutterTestArgs.add(arg);
} else if (arg.startsWith('--test-randomize-ordering-seed=')) {
shuffleSeed = arg.substring('--test-randomize-ordering-seed='.length);
} else if (arg.startsWith('--verbose')) {
print = (Object? message) {
system.print(message);
};
} else if (arg.startsWith('--abort-on-error')) {
onError = () {
system.exit(1);
};
} else if (arg == '--dry-run') {
dryRunArgSet = true;
printProgress('--dry-run enabled. Tests will not actually be executed.');
} else {
flutterTestArgs.add(arg);
}
}
if (dryRunArgSet) {
enableDryRun();
}
final webTestsSuite = WebTestsSuite(flutterTestArgs);
await selectShard(<String, ShardRunner>{
'add_to_app_life_cycle_tests': addToAppLifeCycleRunner,
'build_tests': _runBuildTests,
'framework_coverage': frameworkCoverageRunner,
'framework_tests': frameworkTestsRunner,
'tool_tests': _runToolTests,
'tool_tests_commands': _runCommandsToolTests,
'web_tool_tests': _runWebToolTests,
'tool_integration_tests': _runIntegrationToolTests,
'android_preview_tool_integration_tests': androidPreviewIntegrationToolTestsRunner,
'android_java17_tool_integration_tests': androidJava17IntegrationToolTestsRunner,
'tool_host_cross_arch_tests': _runToolHostCrossArchTests,
// All the unit/widget tests run using `flutter test --platform=chrome`
'web_canvaskit_tests': webTestsSuite.runWebCanvasKitUnitTests,
// All the unit/widget tests run using `flutter test --platform=chrome --wasm`
'web_skwasm_tests': webTestsSuite.runWebSkwasmUnitTests,
// All web integration tests
'web_long_running_tests': webTestsSuite.webLongRunningTestsRunner,
'android_engine_vulkan_tests': () =>
runAndroidEngineTests(impellerBackend: ImpellerBackend.vulkan),
'android_engine_opengles_tests': () =>
runAndroidEngineTests(impellerBackend: ImpellerBackend.opengles),
'flutter_plugins': flutterPackagesRunner,
'skp_generator': skpGeneratorTestsRunner,
'customer_testing': customerTestingRunner,
'analyze': analyzeRunner,
'fuchsia_precache': fuchsiaPrecacheRunner,
'snippets': _runSnippetsTests,
'docs': docsRunner,
'verify_binaries_codesigned': verifyCodesignedTestRunner,
'verify_binaries_pre_codesigned': verifyPreCodesignedTestRunner,
kTestHarnessShardName:
testHarnessTestsRunner, // Used for testing this script; also run as part of SHARD=framework_tests, SUBSHARD=misc.
});
} catch (error, stackTrace) {
foundError(<String>[
'UNEXPECTED ERROR!',
error.toString(),
...stackTrace.toString().split('\n'),
'The test.dart script should be corrected to catch this error and call foundError().',
'${yellow}Some tests are likely to have been skipped.$reset',
]);
system.exit(255);
}
if (hasError) {
reportErrorsAndExit('${bold}Test failed.$reset');
}
reportSuccessAndExit('${bold}Test successful.$reset');
}
final String _toolsPath = path.join(flutterRoot, 'packages', 'flutter_tools');
Future<void> _runGeneralToolTests() async {
await runDartTest(
_toolsPath,
testPaths: <String>[path.join('test', 'general.shard')],
enableFlutterToolAsserts: false,
// Detect unit test time regressions (poor time delay handling, etc).
// This overrides the 15 minute default for tools tests.
// See the README.md and dart_test.yaml files in the flutter_tools package.
perTestTimeout: const Duration(seconds: 2),
);
}
Future<void> _runCommandsToolTests() async {
final List<File> allFiles = Directory(
path.join(_toolsPath, 'test', 'commands.shard'),
).listSync(recursive: true).whereType<File>().toList();
final allTests = <String>[];
for (final file in allFiles) {
if (file.path.endsWith('_test.dart')) {
allTests.add(file.path);
}
}
await runDartTest(
_toolsPath,
forceSingleCore: true,
testPaths: selectIndexOfTotalSubshard<String>(allTests),
);
}
Future<void> _runWebToolTests() async {
final List<File> allFiles = Directory(
path.join(_toolsPath, 'test', 'web.shard'),
).listSync(recursive: true).whereType<File>().toList();
final allTests = <String>[];
for (final file in allFiles) {
if (file.path.endsWith('_test.dart')) {
allTests.add(file.path);
}
}
await runDartTest(
_toolsPath,
forceSingleCore: true,
testPaths: selectIndexOfTotalSubshard<String>(allTests),
includeLocalEngineEnv: true,
);
}
Future<void> _runToolHostCrossArchTests() {
return runDartTest(
_toolsPath,
// These are integration tests
forceSingleCore: true,
testPaths: <String>[path.join('test', 'host_cross_arch.shard')],
);
}
Future<void> _runIntegrationToolTests() async {
final List<String> allTests = Directory(path.join(_toolsPath, 'test', 'integration.shard'))
.listSync(recursive: true)
.whereType<File>()
.map<String>((FileSystemEntity entry) => path.relative(entry.path, from: _toolsPath))
.where((String testPath) => path.basename(testPath).endsWith('_test.dart'))
.toList();
await runDartTest(
_toolsPath,
forceSingleCore: true,
testPaths: selectIndexOfTotalSubshard<String>(allTests),
collectMetrics: true,
);
await runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'hook_user_defines'));
await runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'link_hook'));
}
Future<void> _runWidgetPreviewScaffoldToolTests() async {
await runFlutterTest(
path.join(flutterRoot, 'dev', 'integration_tests', 'widget_preview_scaffold'),
);
}
Future<void> _runToolTests() async {
await selectSubshard(<String, ShardRunner>{
'general': _runGeneralToolTests,
'widget_preview_scaffold': _runWidgetPreviewScaffoldToolTests,
});
}
Future<void> _runSnippetsTests() async {
final String snippetsPath = path.join(flutterRoot, 'dev', 'snippets');
final List<String> allTests = Directory(path.join(snippetsPath, 'test'))
.listSync(recursive: true)
.whereType<File>()
.map<String>((FileSystemEntity entry) => path.relative(entry.path, from: _toolsPath))
.where((String testPath) => path.basename(testPath).endsWith('_test.dart'))
.toList();
await runDartTest(
snippetsPath,
forceSingleCore: true,
testPaths: selectIndexOfTotalSubshard<String>(allTests),
collectMetrics: true,
);
}
Future<void> runForbiddenFromReleaseTests() async {
// Build a release APK to get the snapshot json.
final Directory tempDirectory = Directory.systemTemp.createTempSync('flutter_forbidden_imports.');
final command = <String>[
'build',
'apk',
'--target-platform',
'android-arm64',
'--release',
'--analyze-size',
'--code-size-directory',
tempDirectory.path,
'-v',
];
await runCommand(
flutter,
command,
workingDirectory: path.join(flutterRoot, 'examples', 'hello_world'),
);
// First, a smoke test.
final smokeTestArgs = <String>[
path.join(flutterRoot, 'dev', 'forbidden_from_release_tests', 'bin', 'main.dart'),
'--snapshot',
path.join(tempDirectory.path, 'snapshot.arm64-v8a.json'),
'--package-config',
path.join(flutterRoot, '.dart_tool', 'package_config.json'),
'--forbidden-type',
'package:flutter/src/widgets/framework.dart::Widget',
];
await runCommand(dart, smokeTestArgs, workingDirectory: flutterRoot, expectNonZeroExit: true);
// Actual test.
final args = <String>[
path.join(flutterRoot, 'dev', 'forbidden_from_release_tests', 'bin', 'main.dart'),
'--snapshot',
path.join(tempDirectory.path, 'snapshot.arm64-v8a.json'),
'--package-config',
path.join(flutterRoot, '.dart_tool', 'package_config.json'),
'--forbidden-type',
'package:flutter/src/widgets/widget_inspector.dart::WidgetInspectorService',
'--forbidden-type',
'package:flutter/src/widgets/framework.dart::DebugCreator',
'--forbidden-type',
'package:flutter/src/foundation/print.dart::debugPrint',
];
await runCommand(dart, args, workingDirectory: flutterRoot);
}
/// Verifies that APK, and IPA (if on macOS), and native desktop builds the
/// examples apps without crashing. It does not actually launch the apps. That
/// happens later in the devicelab. This is just a smoke-test. In particular,
/// this will verify we can build when there are spaces in the path name for the
/// Flutter SDK and target app.
///
/// Also does some checking about types included in hello_world.
Future<void> _runBuildTests() async {
final List<Directory> exampleDirectories =
Directory(path.join(flutterRoot, 'examples'))
.listSync()
// API example builds will be tested in a separate shard.
.where(
(FileSystemEntity entity) => entity is Directory && path.basename(entity.path) != 'api',
)
.cast<Directory>()
.toList()
..add(Directory(path.join(flutterRoot, 'packages', 'integration_test', 'example')))
..add(
Directory(
path.join(flutterRoot, 'dev', 'integration_tests', 'android_semantics_testing'),
),
)
..add(Directory(path.join(flutterRoot, 'dev', 'integration_tests', 'android_views')))
..add(Directory(path.join(flutterRoot, 'dev', 'integration_tests', 'channels')))
..add(Directory(path.join(flutterRoot, 'dev', 'integration_tests', 'hybrid_android_views')))
..add(Directory(path.join(flutterRoot, 'dev', 'integration_tests', 'flutter_gallery')))
..add(
Directory(path.join(flutterRoot, 'dev', 'integration_tests', 'ios_platform_view_tests')),
)
..add(
Directory(path.join(flutterRoot, 'dev', 'integration_tests', 'ios_app_with_extensions')),
)
..add(Directory(path.join(flutterRoot, 'dev', 'integration_tests', 'platform_interaction')))
..add(Directory(path.join(flutterRoot, 'dev', 'integration_tests', 'spell_check')))
..add(Directory(path.join(flutterRoot, 'dev', 'integration_tests', 'ui')));
// The tests are randomly distributed into subshards so as to get a uniform
// distribution of costs, but the seed is fixed so that issues are reproducible.
final tests = <ShardRunner>[
for (final Directory exampleDirectory in exampleDirectories)
() => _runExampleProjectBuildTests(exampleDirectory),
...<ShardRunner>[
// Web compilation tests.
() => _flutterBuildDart2js(
path.join('dev', 'integration_tests', 'web'),
path.join('lib', 'main.dart'),
),
// Should not fail to compile with dart:io.
() => _flutterBuildDart2js(
path.join('dev', 'integration_tests', 'web_compile_tests'),
path.join('lib', 'dart_io_import.dart'),
),
// Should be able to compile with a call to:
// BackgroundIsolateBinaryMessenger.ensureInitialized.
() => _flutterBuildDart2js(
path.join('dev', 'integration_tests', 'web_compile_tests'),
path.join('lib', 'background_isolate_binary_messenger.dart'),
),
],
runForbiddenFromReleaseTests,
]..shuffle(math.Random(0));
await runShardRunnerIndexOfTotalSubshard(tests);
}
Future<void> _runExampleProjectBuildTests(Directory exampleDirectory, [File? mainFile]) async {
// Only verify caching with flutter gallery.
final bool verifyCaching = exampleDirectory.path.contains('flutter_gallery');
final String examplePath = path.relative(exampleDirectory.path, from: Directory.current.path);
final additionalArgs = <String>[
if (mainFile != null) path.relative(mainFile.path, from: exampleDirectory.absolute.path),
];
if (Directory(path.join(examplePath, 'android')).existsSync()) {
await _flutterBuildApk(
examplePath,
release: false,
additionalArgs: additionalArgs,
verifyCaching: verifyCaching,
);
await _flutterBuildApk(
examplePath,
release: true,
additionalArgs: additionalArgs,
verifyCaching: verifyCaching,
);
} else {
print('Example project ${path.basename(examplePath)} has no android directory, skipping apk');
}
if (Platform.isMacOS) {
if (Directory(path.join(examplePath, 'ios')).existsSync()) {
await _flutterBuildIpa(
examplePath,
release: false,
additionalArgs: additionalArgs,
verifyCaching: verifyCaching,
);
await _flutterBuildIpa(
examplePath,
release: true,
additionalArgs: additionalArgs,
verifyCaching: verifyCaching,
);
} else {
print('Example project ${path.basename(examplePath)} has no ios directory, skipping ipa');
}
}
if (Platform.isLinux) {
if (Directory(path.join(examplePath, 'linux')).existsSync()) {
await _flutterBuildLinux(
examplePath,
release: false,
additionalArgs: additionalArgs,
verifyCaching: verifyCaching,
);
await _flutterBuildLinux(
examplePath,
release: true,
additionalArgs: additionalArgs,
verifyCaching: verifyCaching,
);
} else {
print('Example project ${path.basename(examplePath)} has no linux directory, skipping Linux');
}
}
if (Platform.isMacOS) {
if (Directory(path.join(examplePath, 'macos')).existsSync()) {
await _flutterBuildMacOS(
examplePath,
release: false,
additionalArgs: additionalArgs,
verifyCaching: verifyCaching,
);
await _flutterBuildMacOS(
examplePath,
release: true,
additionalArgs: additionalArgs,
verifyCaching: verifyCaching,
);
} else {
print('Example project ${path.basename(examplePath)} has no macos directory, skipping macOS');
}
}
if (Platform.isWindows) {
if (Directory(path.join(examplePath, 'windows')).existsSync()) {
await _flutterBuildWin32(
examplePath,
release: false,
additionalArgs: additionalArgs,
verifyCaching: verifyCaching,
);
await _flutterBuildWin32(
examplePath,
release: true,
additionalArgs: additionalArgs,
verifyCaching: verifyCaching,
);
} else {
print(
'Example project ${path.basename(examplePath)} has no windows directory, skipping Win32',
);
}
}
}
Future<void> _flutterBuildApk(
String relativePathToApplication, {
required bool release,
bool verifyCaching = false,
List<String> additionalArgs = const <String>[],
}) async {
printProgress(
'${green}Testing APK ${release ? 'release' : 'debug'} build$reset for $cyan$relativePathToApplication$reset...',
);
await _flutterBuild(
relativePathToApplication,
'APK',
'apk',
release: release,
verifyCaching: verifyCaching,
additionalArgs: additionalArgs,
);
}
Future<void> _flutterBuildIpa(
String relativePathToApplication, {
required bool release,
List<String> additionalArgs = const <String>[],
bool verifyCaching = false,
}) async {
assert(Platform.isMacOS);
printProgress(
'${green}Testing IPA ${release ? 'release' : 'debug'} build$reset for $cyan$relativePathToApplication$reset...',
);
await _flutterBuild(
relativePathToApplication,
'IPA',
'ios',
release: release,
verifyCaching: verifyCaching,
additionalArgs: <String>[...additionalArgs, '--no-codesign'],
);
}
Future<void> _flutterBuildLinux(
String relativePathToApplication, {
required bool release,
bool verifyCaching = false,
List<String> additionalArgs = const <String>[],
}) async {
assert(Platform.isLinux);
await runCommand(flutter, <String>['config', '--enable-linux-desktop']);
printProgress(
'${green}Testing Linux ${release ? 'release' : 'debug'} build$reset for $cyan$relativePathToApplication$reset...',
);
await _flutterBuild(
relativePathToApplication,
'Linux',
'linux',
release: release,
verifyCaching: verifyCaching,
additionalArgs: additionalArgs,
);
}
Future<void> _flutterBuildMacOS(
String relativePathToApplication, {
required bool release,
bool verifyCaching = false,
List<String> additionalArgs = const <String>[],
}) async {
assert(Platform.isMacOS);
await runCommand(flutter, <String>['config', '--enable-macos-desktop']);
printProgress(
'${green}Testing macOS ${release ? 'release' : 'debug'} build$reset for $cyan$relativePathToApplication$reset...',
);
await _flutterBuild(
relativePathToApplication,
'macOS',
'macos',
release: release,
verifyCaching: verifyCaching,
additionalArgs: additionalArgs,
);
}
Future<void> _flutterBuildWin32(
String relativePathToApplication, {
required bool release,
bool verifyCaching = false,
List<String> additionalArgs = const <String>[],
}) async {
assert(Platform.isWindows);
printProgress(
'${green}Testing ${release ? 'release' : 'debug'} Windows build$reset for $cyan$relativePathToApplication$reset...',
);
await _flutterBuild(
relativePathToApplication,
'Windows',
'windows',
release: release,
verifyCaching: verifyCaching,
additionalArgs: additionalArgs,
);
}
Future<void> _flutterBuild(
String relativePathToApplication,
String platformLabel,
String platformBuildName, {
required bool release,
bool verifyCaching = false,
List<String> additionalArgs = const <String>[],
}) async {
await runCommand(flutter, <String>[
'build',
platformBuildName,
if (verifyCaching) '--performance-measurement-file=perf.json',
...additionalArgs,
if (release) '--release' else '--debug',
'-v',
], workingDirectory: path.join(flutterRoot, relativePathToApplication));
if (verifyCaching) {
printProgress(
'${green}Testing $platformLabel cache$reset for $cyan$relativePathToApplication$reset...',
);
await runCommand(flutter, <String>[
'build',
platformBuildName,
'--performance-measurement-file=perf.json',
...additionalArgs,
if (release) '--release' else '--debug',
'-v',
], workingDirectory: path.join(flutterRoot, relativePathToApplication));
final file = File(path.join(flutterRoot, relativePathToApplication, 'perf.json'));
if (!_allTargetsCached(file)) {
foundError(<String>[
'${red}Not all build targets cached after second run.$reset',
'The target performance data was: ${file.readAsStringSync().replaceAll('},', '},\n')}',
]);
}
}
}
bool _allTargetsCached(File performanceFile) {
if (dryRun) {
return true;
}
final data = json.decode(performanceFile.readAsStringSync()) as Map<String, Object?>;
final List<Map<String, Object?>> targets = (data['targets']! as List<Object?>)
.cast<Map<String, Object?>>();
return targets.every((Map<String, Object?> element) => element['skipped'] == true);
}
Future<void> _flutterBuildDart2js(
String relativePathToApplication,
String target, {
bool expectNonZeroExit = false,
}) async {
printProgress('${green}Testing Dart2JS build$reset for $cyan$relativePathToApplication$reset...');
await runCommand(
flutter,
<String>['build', 'web', '-v', '--target=$target'],
workingDirectory: path.join(flutterRoot, relativePathToApplication),
expectNonZeroExit: expectNonZeroExit,
environment: <String, String>{'FLUTTER_WEB': 'true'},
);
}