| // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| // @dart=2.18 |
| |
| import 'dart:convert'; |
| import 'dart:io'; |
| |
| import 'package:record_use/record_use.dart'; |
| import 'package:test/test.dart'; |
| |
| import '../utils.dart'; |
| import 'helpers.dart'; |
| |
| void main() async { |
| if (!nativeAssetsExperimentAvailableOnCurrentChannel) { |
| return; |
| } |
| |
| test('dart compile not supported', timeout: longTimeout, () async { |
| await nativeAssetsTest('dart_app', (dartAppUri) async { |
| final result = await runDart( |
| arguments: [ |
| 'compile', |
| 'exe', |
| 'bin/dart_app.dart', |
| ], |
| workingDirectory: dartAppUri, |
| logger: logger, |
| expectExitCodeZero: false, |
| ); |
| expect( |
| result.stderr, |
| stringContainsInOrder([ |
| "'dart compile' does not support build hooks, use 'dart build' instead.", |
| 'Packages with build hooks:', |
| ]), |
| ); |
| expect( |
| result.stderr, |
| contains('native_add'), |
| ); |
| expect( |
| result.stderr, |
| contains('native_subtract'), |
| ); |
| expect(result.exitCode, 255); |
| }); |
| }); |
| |
| test('dart compile only bails in bin/', timeout: longTimeout, () async { |
| await nativeAssetsTest('dart_app', (dartAppUri) async { |
| await runDart( |
| arguments: ['pub', 'get'], |
| workingDirectory: dartAppUri, |
| logger: logger, |
| ); |
| |
| // 1. Compiling in bin/ should fail. |
| final resultBin = await runDart( |
| arguments: [ |
| 'compile', |
| 'exe', |
| 'bin/dart_app.dart', |
| ], |
| workingDirectory: dartAppUri, |
| logger: logger, |
| expectExitCodeZero: false, |
| ); |
| expect(resultBin.exitCode, 255); |
| expect( |
| resultBin.stderr, |
| contains( |
| "'dart compile' does not support build hooks, use 'dart build' instead.", |
| ), |
| ); |
| |
| // 2. Compiling outside bin/ should succeed (even if it might fail at runtime). |
| final otherFile = File.fromUri(dartAppUri.resolve('tool/other.dart')); |
| await otherFile.parent.create(recursive: true); |
| await otherFile.writeAsString('void main() { print("hello"); }'); |
| |
| final resultOther = await runDart( |
| arguments: [ |
| '-v', |
| 'compile', |
| 'exe', |
| 'tool/other.dart', |
| ], |
| workingDirectory: dartAppUri, |
| logger: logger, |
| ); |
| expect(resultOther.exitCode, 0); |
| final exePath = dartAppUri.resolve('tool/other.exe').toFilePath(); |
| final resultRun = await runProcess( |
| executable: Uri.file(exePath), |
| logger: logger, |
| ); |
| expect(resultRun.stdout, contains('hello')); |
| }); |
| }); |
| |
| test('Recorded usages in dart2js', timeout: longTimeout, () async { |
| await recordUseTest('drop_data_asset', (dartAppUri) async { |
| await runDart( |
| arguments: ['pub', 'get'], |
| workingDirectory: dartAppUri, |
| logger: logger, |
| expectExitCodeZero: true, |
| ); |
| // Now try using the add symbol only, so the multiply library is |
| // tree-shaken. |
| |
| await runDart( |
| arguments: [ |
| 'compile', |
| 'js', |
| '--write-resources', |
| 'bin/drop_data_asset_calls.dart', |
| ], |
| workingDirectory: dartAppUri, |
| logger: logger, |
| expectExitCodeZero: true, |
| ); |
| |
| // The build directory exists |
| final recordedUsages = |
| File.fromUri(dartAppUri.resolve('out.js.resources.json')); |
| expect(recordedUsages.existsSync(), true); |
| |
| final actualRecordedUsages = recordedUsages.readAsStringSync(); |
| final u = Recordings.fromJson(jsonDecode(actualRecordedUsages)); |
| printOnFailure(actualRecordedUsages); |
| final constArguments = u.constArgumentsFor(Definition( |
| 'package:drop_data_asset/src/drop_data_asset.dart', |
| [ |
| Name( |
| kind: DefinitionKind.classKind, |
| 'MyMath', |
| ), |
| Name( |
| kind: DefinitionKind.methodKind, |
| 'add', |
| disambiguators: { |
| DefinitionDisambiguator.staticDisambiguator, |
| }, |
| ) |
| ], |
| )); |
| expect(constArguments.length, 1); |
| expect(constArguments.first.namedArguments.isEmpty, true); |
| expect(constArguments.first.positionalArguments, |
| const [IntConstant(3), IntConstant(4)]); |
| }); |
| }); |
| |
| // TODO(https://github.com/dart-lang/native/issues/2893): Implement instance |
| // support. |
| test('Recorded usages in dart2js - no instance support yet', |
| timeout: longTimeout, () async { |
| await recordUseTest('drop_data_asset', (dartAppUri) async { |
| await runDart( |
| arguments: ['pub', 'get'], |
| workingDirectory: dartAppUri, |
| logger: logger, |
| expectExitCodeZero: true, |
| ); |
| // Now try using the add symbol only, so the multiply library is |
| // tree-shaken. |
| await runDart( |
| arguments: [ |
| 'compile', |
| 'js', |
| '--write-resources', |
| 'bin/drop_data_asset_instances.dart', |
| ], |
| workingDirectory: dartAppUri, |
| logger: logger, |
| expectExitCodeZero: true, |
| ); |
| |
| // The build directory exists |
| final recordedUsages = |
| File.fromUri(dartAppUri.resolve('out.js.resources.json')); |
| expect(recordedUsages.existsSync(), true); |
| |
| final actualRecordedUsages = recordedUsages.readAsStringSync(); |
| final u = Recordings.fromJson(jsonDecode(actualRecordedUsages)); |
| final constantsOf = u.constantsOf(Definition( |
| 'package:drop_data_asset/src/drop_data_asset.dart', |
| [Name('RecordCallToC')], |
| )); |
| expect(constantsOf.length, 0); |
| }); |
| }); |
| } |
| |
| extension on Recordings { |
| List<CallWithArguments> constArgumentsFor(Definition definition) { |
| final result = <CallWithArguments>[]; |
| for (final entry in calls.entries) { |
| // ignore: invalid_use_of_visible_for_testing_member |
| if (entry.key.semanticEquals(definition)) { |
| for (final call in entry.value) { |
| if (call is CallWithArguments) { |
| result.add(call); |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| List<Constant> constantsOf(Definition definition) { |
| final result = <Constant>[]; |
| for (final entry in instances.entries) { |
| // ignore: invalid_use_of_visible_for_testing_member |
| if (entry.key.semanticEquals(definition)) { |
| for (final instance in entry.value) { |
| if (instance is InstanceConstantReference) { |
| result.add(instance.instanceConstant); |
| } |
| } |
| } |
| } |
| return result; |
| } |
| } |