diff --git a/testing/run_tests.py b/testing/run_tests.py index f70a72c66fce1..c8d68bd979866 100755 --- a/testing/run_tests.py +++ b/testing/run_tests.py @@ -988,14 +988,7 @@ def build_dart_host_test_list(build_dir): ), (os.path.join('flutter', 'tools', 'build_bucket_golden_scraper'), []), (os.path.join('flutter', 'tools', 'clang_tidy'), []), - ( - os.path.join('flutter', 'tools', 'const_finder'), - [ - os.path.join(build_dir, 'gen', 'frontend_server_aot.dart.snapshot'), - os.path.join(build_dir, 'flutter_patched_sdk'), - os.path.join(build_dir, 'dart-sdk', 'lib', 'libraries.json'), - ], - ), + (os.path.join('flutter', 'tools', 'const_finder'), []), (os.path.join('flutter', 'tools', 'dir_contents_diff'), []), (os.path.join('flutter', 'tools', 'engine_tool'), []), (os.path.join('flutter', 'tools', 'githooks'), []), diff --git a/tools/const_finder/pubspec.yaml b/tools/const_finder/pubspec.yaml index 9ce8906977ae7..6d27db30abf72 100644 --- a/tools/const_finder/pubspec.yaml +++ b/tools/const_finder/pubspec.yaml @@ -18,4 +18,6 @@ dependencies: dev_dependencies: collection: any + engine_repo_tools: any path: any + test: any diff --git a/tools/const_finder/test/const_finder_test.dart b/tools/const_finder/test/const_finder_test.dart index 0731b17b8d915..5c5f314dceebc 100644 --- a/tools/const_finder/test/const_finder_test.dart +++ b/tools/const_finder/test/const_finder_test.dart @@ -2,489 +2,428 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ignore_for_file: avoid_dynamic_calls - import 'dart:convert'; -import 'dart:io'; +import 'dart:io' as io; -import 'package:collection/collection.dart'; +import 'package:engine_repo_tools/engine_repo_tools.dart'; import 'package:kernel/const_finder.dart'; import 'package:path/path.dart' as path; - -void expect(T value, T expected) { - if (value != expected) { - stderr.writeln('Expected: $expected'); - stderr.writeln('Actual: $value'); - exitCode = -1; - } -} - -void expectInstances(dynamic value, dynamic expected, Compiler compiler) { - // To ensure we ignore insertion order into maps as well as lists we use - // DeepCollectionEquality as well as sort the lists. - - int compareByStringValue(dynamic a, dynamic b) { - return a['stringValue'].compareTo(b['stringValue']) as int; - } - value['constantInstances'].sort(compareByStringValue); - expected['constantInstances'].sort(compareByStringValue); - - final Equality equality; - if (compiler == Compiler.dart2js) { - equality = const Dart2JSDeepCollectionEquality(); - } else { - equality = const DeepCollectionEquality(); +import 'package:test/test.dart'; + +void main() { + final engine = Engine.findWithin(); + var buildDir = io.Platform.environment['FLUTTER_BUILD_DIRECTORY']; + buildDir ??= engine.latestOutput()?.path.path; + if (buildDir == null) { + fail('No build directory found. Set FLUTTER_BUILD_DIRECTORY'); } - if (!equality.equals(value, expected)) { - stderr.writeln('Expected: ${jsonEncode(expected)}'); - stderr.writeln('Actual: ${jsonEncode(value)}'); - exitCode = -1; - } -} -// This test is assuming the `dart` used to invoke the tests is compatible -// with the version of package:kernel in //third-party/dart/pkg/kernel -final String dart = Platform.resolvedExecutable; -final String dartaotruntime = path.join(path.dirname(Platform.resolvedExecutable), 'dartaotruntime'); - -void _checkRecursion(String dillPath, Compiler compiler) { - stdout.writeln('Checking recursive calls.'); - final ConstFinder finder = ConstFinder( - kernelFilePath: dillPath, - classLibraryUri: 'package:const_finder_fixtures/box.dart', - className: 'Box', + final fixturesPath = path.join( + engine.flutterDir.path, + 'tools', + 'const_finder', + 'test', + 'fixtures', + ); + final String fixturesUrl = io.Platform.isWindows + ? '/$fixturesPath'.replaceAll(io.Platform.pathSeparator, '/') + : fixturesPath; + + final frontendServerSnapshot = path.join( + buildDir, + 'gen', + 'frontend_server_aot.dart.snapshot', + ); + final flutterPatchedSdk = path.join( + buildDir, + 'flutter_patched_sdk', + ); + final librariesDotJson = path.join( + flutterPatchedSdk, + 'lib', + 'libraries.json', + ); + final String packageConfig = path.join( + fixturesPath, + '.dart_tool', + 'package_config.json', ); - // Will timeout if we did things wrong. - jsonEncode(finder.findInstances()); -} -void _checkConsts(String dillPath, Compiler compiler) { - stdout.writeln('Checking for expected constants.'); - final ConstFinder finder = ConstFinder( - kernelFilePath: dillPath, - classLibraryUri: 'package:const_finder_fixtures/target.dart', - className: 'Target', + final dart = io.Platform.resolvedExecutable; + final dartaotruntime = path.join( + path.dirname(io.Platform.resolvedExecutable), + 'dartaotruntime', ); - final Map expectation = { - 'constantInstances': >[ - {'stringValue': '100', 'intValue': 100, 'targetValue': null}, - {'stringValue': '102', 'intValue': 102, 'targetValue': null}, - {'stringValue': '101', 'intValue': 101}, - {'stringValue': '103', 'intValue': 103, 'targetValue': null}, - {'stringValue': '105', 'intValue': 105, 'targetValue': null}, - {'stringValue': '104', 'intValue': 104}, - {'stringValue': '106', 'intValue': 106, 'targetValue': null}, - {'stringValue': '108', 'intValue': 108, 'targetValue': null}, - {'stringValue': '107', 'intValue': 107}, - {'stringValue': '1', 'intValue': 1, 'targetValue': null}, - {'stringValue': '4', 'intValue': 4, 'targetValue': null}, - {'stringValue': '2', 'intValue': 2}, - {'stringValue': '6', 'intValue': 6, 'targetValue': null}, - {'stringValue': '8', 'intValue': 8, 'targetValue': null}, - {'stringValue': '10', 'intValue': 10, 'targetValue': null}, - {'stringValue': '9', 'intValue': 9}, - {'stringValue': '7', 'intValue': 7, 'targetValue': null}, - {'stringValue': '11', 'intValue': 11, 'targetValue': null}, - {'stringValue': '12', 'intValue': 12, 'targetValue': null}, - {'stringValue': 'package', 'intValue':-1, 'targetValue': null}, + + void compileAOTDill({ + required String sourcePath, + required String dillPath, + }) { + final result = io.Process.runSync( + dartaotruntime, + [ + frontendServerSnapshot, + '--sdk-root=$flutterPatchedSdk', + '--target=flutter', + '--aot', + '--tfa', + '--packages=$packageConfig', + '--output-dill=$dillPath', + sourcePath, ], - 'nonConstantLocations': [], - }; - if (compiler == Compiler.aot) { - expectation['nonConstantLocations'] = []; - } else { - final String fixturesUrl = Platform.isWindows - ? '/$fixtures'.replaceAll(Platform.pathSeparator, '/') - : fixtures; - - // Without true tree-shaking, there is a non-const reference in a - // never-invoked function that will be present in the dill. - expectation['nonConstantLocations'] = [ - { - 'file': 'file://$fixturesUrl/pkg/package.dart', - 'line': 14, - 'column': 25, - }, - ]; + ); + printOnFailure(result.stdout.toString()); + printOnFailure(result.stderr.toString()); + if (result.exitCode != 0) { + fail('Failed to compile AOT dill'); + } + addTearDown(() => io.File(dillPath).deleteSync()); } - expectInstances( - finder.findInstances(), - expectation, - compiler, - ); - final ConstFinder finder2 = ConstFinder( - kernelFilePath: dillPath, - classLibraryUri: 'package:const_finder_fixtures/target.dart', - className: 'MixedInTarget', - ); - expectInstances( - finder2.findInstances(), - { - 'constantInstances': >[ - {'val': '13'}, + void compileDart2JSDill({ + required String sourcePath, + required String dillPath, + }) { + final result = io.Process.runSync( + dart, + [ + 'compile', + 'js', + '--libraries-spec=$librariesDotJson', + '-Ddart.vm.product=true', + '-o', + dillPath, + '--packages=$packageConfig', + '--cfe-only', + sourcePath, ], - 'nonConstantLocations': [], - }, - compiler, - ); -} + ); + printOnFailure(result.stdout.toString()); + printOnFailure(result.stderr.toString()); + if (result.exitCode != 0) { + fail('Failed to compile Dart2JS dill'); + } + addTearDown(() => io.File(dillPath).deleteSync()); + } -void _checkAnnotation(String dillPath, Compiler compiler) { - stdout.writeln('Checking constant instances in a class annotated with instance of StaticIconProvider are ignored with $compiler'); - final ConstFinder finder = ConstFinder( - kernelFilePath: dillPath, - classLibraryUri: 'package:const_finder_fixtures/target.dart', - className: 'Target', - annotationClassName: 'StaticIconProvider', - annotationClassLibraryUri: 'package:const_finder_fixtures/static_icon_provider.dart', - ); - final Map instances = finder.findInstances(); - expectInstances( - instances, - { - 'constantInstances': >[ - { + test('box_frontend (aot)', () { + final sourcePath = path.join(fixturesPath, 'lib', 'box.dart'); + final dillPath = path.join(fixturesPath, 'box_frontend.dill'); + compileAOTDill(sourcePath: sourcePath, dillPath: dillPath); + final finder = ConstFinder( + kernelFilePath: dillPath, + classLibraryUri: 'package:const_finder_fixtures/box.dart', + className: 'Box', + ); + + // Will timeout if we did things wrong. + jsonEncode(finder.findInstances()); + }); + + test('box_web (dart2js)', () { + final sourcePath = path.join(fixturesPath, 'lib', 'box.dart'); + final dillPath = path.join(fixturesPath, 'box_web.dill'); + compileDart2JSDill(sourcePath: sourcePath, dillPath: dillPath); + final finder = ConstFinder( + kernelFilePath: dillPath, + classLibraryUri: 'package:const_finder_fixtures/box.dart', + className: 'Box', + ); + + // Will timeout if we did things wrong. + jsonEncode(finder.findInstances()); + }); + + test('consts_frontend (aot)', () { + final sourcePath = path.join(fixturesPath, 'lib', 'consts.dart'); + final dillPath = path.join(fixturesPath, 'consts_frontend.dill'); + compileAOTDill(sourcePath: sourcePath, dillPath: dillPath); + + final { + 'constantInstances': List constantInstances, + 'nonConstantLocations': List nonConstantLocations, + } = ConstFinder( + kernelFilePath: dillPath, + classLibraryUri: 'package:const_finder_fixtures/target.dart', + className: 'Target', + ).findInstances(); + + expect( + constantInstances, + unorderedEquals([ + {'stringValue': '100', 'intValue': 100, 'targetValue': null}, + {'stringValue': '102', 'intValue': 102, 'targetValue': null}, + {'stringValue': '101', 'intValue': 101}, + {'stringValue': '103', 'intValue': 103, 'targetValue': null}, + {'stringValue': '105', 'intValue': 105, 'targetValue': null}, + {'stringValue': '104', 'intValue': 104}, + {'stringValue': '106', 'intValue': 106, 'targetValue': null}, + {'stringValue': '108', 'intValue': 108, 'targetValue': null}, + {'stringValue': '107', 'intValue': 107}, + {'stringValue': '1', 'intValue': 1, 'targetValue': null}, + {'stringValue': '4', 'intValue': 4, 'targetValue': null}, + {'stringValue': '2', 'intValue': 2}, + {'stringValue': '6', 'intValue': 6, 'targetValue': null}, + {'stringValue': '8', 'intValue': 8, 'targetValue': null}, + {'stringValue': '10', 'intValue': 10, 'targetValue': null}, + {'stringValue': '9', 'intValue': 9}, + {'stringValue': '7', 'intValue': 7, 'targetValue': null}, + {'stringValue': '11', 'intValue': 11, 'targetValue': null}, + {'stringValue': '12', 'intValue': 12, 'targetValue': null}, + {'stringValue': 'package', 'intValue': -1, 'targetValue': null}, + ]), + ); + expect(nonConstantLocations, isEmpty); + }); + + test('consts_web (dart2js)', () { + final sourcePath = path.join(fixturesPath, 'lib', 'consts.dart'); + final dillPath = path.join(fixturesPath, 'consts_web.dill'); + compileDart2JSDill(sourcePath: sourcePath, dillPath: dillPath); + + final { + 'constantInstances': List constantInstances, + 'nonConstantLocations': List nonConstantLocations, + } = ConstFinder( + kernelFilePath: dillPath, + classLibraryUri: 'package:const_finder_fixtures/target.dart', + className: 'Target', + ).findInstances(); + + expect( + constantInstances, + unorderedEquals([ + {'stringValue': '100', 'intValue': 100, 'targetValue': null}, + {'stringValue': '102', 'intValue': 102, 'targetValue': null}, + {'stringValue': '101', 'intValue': 101}, + {'stringValue': '103', 'intValue': 103, 'targetValue': null}, + {'stringValue': '105', 'intValue': 105, 'targetValue': null}, + {'stringValue': '104', 'intValue': 104}, + {'stringValue': '106', 'intValue': 106, 'targetValue': null}, + {'stringValue': '108', 'intValue': 108, 'targetValue': null}, + {'stringValue': '107', 'intValue': 107}, + {'stringValue': '1', 'intValue': 1, 'targetValue': null}, + {'stringValue': '4', 'intValue': 4, 'targetValue': null}, + {'stringValue': '2', 'intValue': 2}, + {'stringValue': '6', 'intValue': 6, 'targetValue': null}, + {'stringValue': '8', 'intValue': 8, 'targetValue': null}, + {'stringValue': '10', 'intValue': 10, 'targetValue': null}, + {'stringValue': '9', 'intValue': 9}, + {'stringValue': '7', 'intValue': 7, 'targetValue': null}, + {'stringValue': '11', 'intValue': 11, 'targetValue': null}, + {'stringValue': '12', 'intValue': 12, 'targetValue': null}, + {'stringValue': 'package', 'intValue': -1, 'targetValue': null}, + ]), + ); + + expect(nonConstantLocations, [ + { + 'file': 'file://$fixturesUrl/pkg/package.dart', + 'line': 14, + 'column': 25, + } + ]); + }); + + test('consts_and_non_frontend (aot)', () { + final sourcePath = path.join(fixturesPath, 'lib', 'consts_and_non.dart'); + final dillPath = path.join(fixturesPath, 'consts_and_non_frontend.dill'); + compileAOTDill(sourcePath: sourcePath, dillPath: dillPath); + + final { + 'constantInstances': List constantInstances, + 'nonConstantLocations': List nonConstantLocations, + } = ConstFinder( + kernelFilePath: dillPath, + classLibraryUri: 'package:const_finder_fixtures/target.dart', + className: 'Target', + ).findInstances(); + + expect( + constantInstances, + unorderedEquals([ + {'stringValue': '1', 'intValue': 1, 'targetValue': null}, + {'stringValue': '4', 'intValue': 4, 'targetValue': null}, + {'stringValue': '6', 'intValue': 6, 'targetValue': null}, + {'stringValue': '8', 'intValue': 8, 'targetValue': null}, + {'stringValue': '10', 'intValue': 10, 'targetValue': null}, + {'stringValue': '9', 'intValue': 9}, + {'stringValue': '7', 'intValue': 7, 'targetValue': null}, + ]), + ); + expect(nonConstantLocations, [ + { + 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', + 'line': 14, + 'column': 26, + }, + { + 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', + 'line': 16, + 'column': 26, + }, + { + 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', + 'line': 16, + 'column': 41, + }, + { + 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', + 'line': 17, + 'column': 26, + }, + { + 'file': 'file://$fixturesUrl/pkg/package.dart', + 'line': 14, + 'column': 25, + } + ]); + }); + + test('consts_and_non_web (dart2js)', () { + final sourcePath = path.join(fixturesPath, 'lib', 'consts_and_non.dart'); + final dillPath = path.join(fixturesPath, 'consts_and_non_web.dill'); + compileDart2JSDill(sourcePath: sourcePath, dillPath: dillPath); + + final { + 'constantInstances': List constantInstances, + 'nonConstantLocations': List nonConstantLocations, + } = ConstFinder( + kernelFilePath: dillPath, + classLibraryUri: 'package:const_finder_fixtures/target.dart', + className: 'Target', + ).findInstances(); + + expect( + constantInstances, + unorderedEquals([ + {'stringValue': '1', 'intValue': 1, 'targetValue': null}, + {'stringValue': '4', 'intValue': 4, 'targetValue': null}, + {'stringValue': '6', 'intValue': 6, 'targetValue': null}, + {'stringValue': '8', 'intValue': 8, 'targetValue': null}, + {'stringValue': '10', 'intValue': 10, 'targetValue': null}, + {'stringValue': '9', 'intValue': 9}, + {'stringValue': '7', 'intValue': 7, 'targetValue': null}, + {'stringValue': 'package', 'intValue': -1, 'targetValue': null}, + ]), + ); + + expect(nonConstantLocations, [ + { + 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', + 'line': 14, + 'column': 26, + }, + { + 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', + 'line': 16, + 'column': 26, + }, + { + 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', + 'line': 16, + 'column': 41, + }, + { + 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', + 'line': 17, + 'column': 26, + }, + { + 'file': 'file://$fixturesUrl/pkg/package.dart', + 'line': 14, + 'column': 25, + } + ]); + }); + + test('static_icon_provider_frontend (aot)', () { + final sourcePath = path.join( + fixturesPath, + 'lib', + 'static_icon_provider.dart', + ); + final dillPath = path.join( + fixturesPath, + 'static_icon_provider_frontend.dill', + ); + compileAOTDill(sourcePath: sourcePath, dillPath: dillPath); + final finder = ConstFinder( + kernelFilePath: dillPath, + classLibraryUri: 'package:const_finder_fixtures/target.dart', + className: 'Target', + annotationClassName: 'StaticIconProvider', + annotationClassLibraryUri: + 'package:const_finder_fixtures/static_icon_provider.dart', + ); + + final { + 'constantInstances': List constantInstances, + 'nonConstantLocations': List nonConstantLocations, + } = finder.findInstances(); + expect( + constantInstances, + unorderedEquals([ + { 'stringValue': 'used1', 'intValue': 1, 'targetValue': null, }, - { + { 'stringValue': 'used2', 'intValue': 2, 'targetValue': null, }, - ], - // TODO(fujino): This should have non-constant locations from the use of - // a tear-off, see https://github.com/flutter/flutter/issues/116797 - 'nonConstantLocations': [], - }, - compiler, - ); -} - -void _checkNonConstsFrontend(String dillPath, Compiler compiler) { - stdout.writeln('Checking for non-constant instances with $compiler'); - final ConstFinder finder = ConstFinder( - kernelFilePath: dillPath, - classLibraryUri: 'package:const_finder_fixtures/target.dart', - className: 'Target', - ); - final String fixturesUrl = Platform.isWindows - ? '/$fixtures'.replaceAll(Platform.pathSeparator, '/') - : fixtures; - - expectInstances( - finder.findInstances(), - { - 'constantInstances': [ - {'stringValue': '1', 'intValue': 1, 'targetValue': null}, - {'stringValue': '4', 'intValue': 4, 'targetValue': null}, - {'stringValue': '6', 'intValue': 6, 'targetValue': null}, - {'stringValue': '8', 'intValue': 8, 'targetValue': null}, - {'stringValue': '10', 'intValue': 10, 'targetValue': null}, - {'stringValue': '9', 'intValue': 9}, - {'stringValue': '7', 'intValue': 7, 'targetValue': null}, - ], - 'nonConstantLocations': [ - { - 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', - 'line': 14, - 'column': 26, - }, - { - 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', - 'line': 16, - 'column': 26, - }, - { - 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', - 'line': 16, - 'column': 41, - }, - { - 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', - 'line': 17, - 'column': 26, - }, - { - 'file': 'file://$fixturesUrl/pkg/package.dart', - 'line': 14, - 'column': 25, - } - ] - }, - compiler, - ); -} - -// Note, since web dills don't have tree shaking, we aren't able to eliminate -// an additional const versus _checkNonConstFrontend. -void _checkNonConstsWeb(String dillPath, Compiler compiler) { - assert(compiler == Compiler.dart2js); - stdout.writeln('Checking for non-constant instances with $compiler'); - final ConstFinder finder = ConstFinder( - kernelFilePath: dillPath, - classLibraryUri: 'package:const_finder_fixtures/target.dart', - className: 'Target', - ); - - final String fixturesUrl = Platform.isWindows - ? '/$fixtures'.replaceAll(Platform.pathSeparator, '/') - : fixtures; - expectInstances( - finder.findInstances(), - { - 'constantInstances': [ - {'stringValue': '1', 'intValue': 1, 'targetValue': null}, - {'stringValue': '4', 'intValue': 4, 'targetValue': null}, - {'stringValue': '6', 'intValue': 6, 'targetValue': null}, - {'stringValue': '8', 'intValue': 8, 'targetValue': null}, - {'stringValue': '10', 'intValue': 10, 'targetValue': null}, - {'stringValue': '9', 'intValue': 9}, - {'stringValue': '7', 'intValue': 7, 'targetValue': null}, - {'stringValue': 'package', 'intValue': -1, 'targetValue': null}, - ], - 'nonConstantLocations': [ - { - 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', - 'line': 14, - 'column': 26, - }, - { - 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', - 'line': 16, - 'column': 26, - }, - { - 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', - 'line': 16, - 'column': 41, + ]), + ); + + // TODO(fujino): This should have non-constant locations from the use of + // a tear-off, see https://github.com/flutter/flutter/issues/116797 + expect(nonConstantLocations, isEmpty); + }); + + test('static_icon_provider_web (dart2js)', () { + final sourcePath = path.join( + fixturesPath, + 'lib', + 'static_icon_provider.dart', + ); + final dillPath = path.join( + fixturesPath, + 'static_icon_provider_web.dill', + ); + compileDart2JSDill(sourcePath: sourcePath, dillPath: dillPath); + final finder = ConstFinder( + kernelFilePath: dillPath, + classLibraryUri: 'package:const_finder_fixtures/target.dart', + className: 'Target', + annotationClassName: 'StaticIconProvider', + annotationClassLibraryUri: + 'package:const_finder_fixtures/static_icon_provider.dart', + ); + + final { + 'constantInstances': List constantInstances, + 'nonConstantLocations': List nonConstantLocations, + } = finder.findInstances(); + expect( + constantInstances, + unorderedEquals([ + { + 'stringValue': 'used1', + 'intValue': 1, + 'targetValue': null, }, - { - 'file': 'file://$fixturesUrl/lib/consts_and_non.dart', - 'line': 17, - 'column': 26, + { + 'stringValue': 'used2', + 'intValue': 2, + 'targetValue': null, }, - { - 'file': 'file://$fixturesUrl/pkg/package.dart', - 'line': 14, - 'column': 25, - } - ], - }, - compiler, - ); -} + ]), + ); -void checkProcessResult(ProcessResult result) { - if (result.exitCode != 0) { - stdout.writeln(result.stdout); - stderr.writeln(result.stderr); - } - expect(result.exitCode, 0); -} - -final String basePath = - path.canonicalize(path.join(path.dirname(Platform.script.toFilePath()), '..')); -final String fixtures = path.join(basePath, 'test', 'fixtures'); -final String packageConfig = path.join(fixtures, '.dart_tool', 'package_config.json'); - -Future main(List args) async { - if (args.length != 3) { - stderr.writeln('The first argument must be the path to the frontend server dill.'); - stderr.writeln('The second argument must be the path to the flutter_patched_sdk'); - stderr.writeln('The third argument must be the path to libraries.json'); - exit(-1); - } - - final String frontendServer = args[0]; - final String sdkRoot = args[1]; - final String librariesSpec = args[2]; - - final List<_Test> tests = <_Test>[ - _Test( - name: 'box_frontend', - dartSource: path.join(fixtures, 'lib', 'box.dart'), - frontendServer: frontendServer, - sdkRoot: sdkRoot, - librariesSpec: librariesSpec, - verify: _checkRecursion, - compiler: Compiler.aot, - ), - _Test( - name: 'box_web', - dartSource: path.join(fixtures, 'lib', 'box.dart'), - frontendServer: frontendServer, - sdkRoot: sdkRoot, - librariesSpec: librariesSpec, - verify: _checkRecursion, - compiler: Compiler.dart2js, - ), - _Test( - name: 'consts_frontend', - dartSource: path.join(fixtures, 'lib', 'consts.dart'), - frontendServer: frontendServer, - sdkRoot: sdkRoot, - librariesSpec: librariesSpec, - verify: _checkConsts, - compiler: Compiler.aot, - ), - _Test( - name: 'consts_web', - dartSource: path.join(fixtures, 'lib', 'consts.dart'), - frontendServer: frontendServer, - sdkRoot: sdkRoot, - librariesSpec: librariesSpec, - verify: _checkConsts, - compiler: Compiler.dart2js, - ), - _Test( - name: 'consts_and_non_frontend', - dartSource: path.join(fixtures, 'lib', 'consts_and_non.dart'), - frontendServer: frontendServer, - sdkRoot: sdkRoot, - librariesSpec: librariesSpec, - verify: _checkNonConstsFrontend, - compiler: Compiler.aot, - ), - _Test( - name: 'consts_and_non_web', - dartSource: path.join(fixtures, 'lib', 'consts_and_non.dart'), - frontendServer: frontendServer, - sdkRoot: sdkRoot, - librariesSpec: librariesSpec, - verify: _checkNonConstsWeb, - compiler: Compiler.dart2js, - ), - _Test( - name: 'static_icon_provider_frontend', - dartSource: path.join(fixtures, 'lib', 'static_icon_provider.dart'), - frontendServer: frontendServer, - sdkRoot: sdkRoot, - librariesSpec: librariesSpec, - verify: _checkAnnotation, - compiler: Compiler.aot, - ), - _Test( - name: 'static_icon_provider_web', - dartSource: path.join(fixtures, 'lib', 'static_icon_provider.dart'), - frontendServer: frontendServer, - sdkRoot: sdkRoot, - librariesSpec: librariesSpec, - verify: _checkAnnotation, - compiler: Compiler.dart2js, - ), - ]; - try { - stdout.writeln('Generating kernel fixtures...'); - - for (final _Test test in tests) { - test.run(); - } - } finally { - try { - for (final _Test test in tests) { - test.dispose(); - } - } finally { - stdout.writeln('Tests ${exitCode == 0 ? 'succeeded' : 'failed'} - exit code: $exitCode'); - } - } -} - -enum Compiler { - // Uses TFA tree-shaking. - aot, - // Does not have TFA tree-shaking. - dart2js, -} - -class _Test { - _Test({ - required this.name, - required this.dartSource, - required this.sdkRoot, - required this.verify, - required this.frontendServer, - required this.librariesSpec, - required this.compiler, - }) : dillPath = path.join(fixtures, '$name.dill'); - - final String name; - final String dartSource; - final String sdkRoot; - final String frontendServer; - final String librariesSpec; - final String dillPath; - void Function(String, Compiler) verify; - final Compiler compiler; - - final List resourcesToDispose = []; - - void run() { - stdout.writeln('Compiling $dartSource to $dillPath with $compiler'); - - if (compiler == Compiler.aot) { - _compileAOTDill(); - } else { - _compileWebDill(); - } - - stdout.writeln('Testing $dillPath'); - - verify(dillPath, compiler); - } - - void dispose() { - for (final String resource in resourcesToDispose) { - stdout.writeln('Deleting $resource'); - File(resource).deleteSync(); - } - } - - void _compileAOTDill() { - checkProcessResult(Process.runSync(dartaotruntime, [ - frontendServer, - '--sdk-root=$sdkRoot', - '--target=flutter', - '--aot', - '--tfa', - '--packages=$packageConfig', - '--output-dill=$dillPath', - dartSource, - ])); - - resourcesToDispose.add(dillPath); - } - - void _compileWebDill() { - final ProcessResult result = Process.runSync(dart, [ - 'compile', - 'js', - '--libraries-spec=$librariesSpec', - '-Ddart.vm.product=true', - '-o', - dillPath, - '--packages=$packageConfig', - '--cfe-only', - dartSource, - ]); - checkProcessResult(result); - - resourcesToDispose.add(dillPath); - } -} - -/// Equality that casts all [num]'s to [double] before comparing. -class Dart2JSDeepCollectionEquality extends DeepCollectionEquality { - const Dart2JSDeepCollectionEquality(); - - @override - bool equals(Object? e1, Object? e2) { - if (e1 is num && e2 is num) { - return e1.toDouble() == e2.toDouble(); - } - return super.equals(e1, e2); - } + // TODO(fujino): This should have non-constant locations from the use of + // a tear-off, see https://github.com/flutter/flutter/issues/116797 + expect(nonConstantLocations, isEmpty); + }); }