flutter/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart
Daco Harkes 534b250a56
[native assets] Graduate to preview (#169194)
This PR enables native assets on the main and dev channel by default,
and make native assets available on the beta channel.

This PR removes the flag from invocations.

The helper packages (`package:hooks` and `package:code_assets`) will
stay 0.x for now, until the SDK constraint can be bumped to a beta
release and we're happy with the Dart API.

Corresponding Dart CL:
https://dart-review.googlesource.com/c/sdk/+/429920

Issue:

* https://github.com/flutter/flutter/issues/129757

Project: https://github.com/orgs/dart-lang/projects/99/
2025-05-21 16:54:42 +00:00

244 lines
9.4 KiB
Dart

// 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.
import 'package:code_assets/code_assets.dart';
import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/build_system/targets/native_assets.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';
import 'fake_native_assets_build_runner.dart';
void main() {
late FakeProcessManager processManager;
late Environment environment;
late Artifacts artifacts;
late FileSystem fileSystem;
late BufferLogger logger;
late Uri projectUri;
setUp(() {
processManager = FakeProcessManager.empty();
logger = BufferLogger.test();
artifacts = Artifacts.test();
fileSystem = MemoryFileSystem.test();
environment = Environment.test(
fileSystem.currentDirectory,
inputs: <String, String>{},
artifacts: artifacts,
processManager: processManager,
fileSystem: fileSystem,
logger: logger,
);
environment.buildDir.createSync(recursive: true);
projectUri = environment.projectDir.uri;
});
testUsingContext(
'Native assets: non-bundled libraries require no copying',
overrides: <Type, Generator>{ProcessManager: () => FakeProcessManager.empty()},
() async {
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
final Uri nonFlutterTesterAssetUri = environment.buildDir.childFile('native_assets.json').uri;
await packageConfig.parent.create();
await packageConfig.create();
final File directSoFile = environment.projectDir.childFile('direct.so');
directSoFile.writeAsBytesSync(<int>[]);
CodeAsset makeCodeAsset(String name, LinkMode linkMode, [Uri? file]) =>
CodeAsset(package: 'bar', name: name, linkMode: linkMode, file: file);
final Map<String, String> environmentDefines = <String, String>{
kBuildMode: BuildMode.release.cliName,
};
final List<CodeAsset> codeAssets = <CodeAsset>[
makeCodeAsset('malloc', LookupInProcess()),
makeCodeAsset('free', LookupInExecutable()),
makeCodeAsset('draw', DynamicLoadingSystem(Uri.file('/usr/lib/skia.so'))),
];
final DartBuildResult dartBuildResult = await runFlutterSpecificDartBuild(
environmentDefines: environmentDefines,
targetPlatform: TargetPlatform.linux_x64,
projectUri: projectUri,
fileSystem: fileSystem,
buildRunner: FakeFlutterNativeAssetsBuildRunner(
packagesWithNativeAssetsResult: <String>['bar'],
buildResult: FakeFlutterNativeAssetsBuilderResult.fromAssets(),
linkResult: FakeFlutterNativeAssetsBuilderResult.fromAssets(codeAssets: codeAssets),
),
);
await installCodeAssets(
dartBuildResult: dartBuildResult,
environmentDefines: environmentDefines,
targetPlatform: TargetPlatform.windows_x64,
projectUri: projectUri,
fileSystem: fileSystem,
nativeAssetsFileUri: nonFlutterTesterAssetUri,
);
expect(testLogger.traceText, isNot(contains('Copying native assets to')));
},
);
testUsingContext(
'build with assets but not enabled',
overrides: <Type, Generator>{
// ignore: avoid_redundant_argument_values
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: false),
ProcessManager: () => FakeProcessManager.empty(),
},
() async {
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
await packageConfig.parent.create();
await packageConfig.create();
expect(
() => runFlutterSpecificDartBuild(
environmentDefines: <String, String>{kBuildMode: BuildMode.debug.cliName},
targetPlatform: TargetPlatform.windows_x64,
projectUri: projectUri,
fileSystem: fileSystem,
buildRunner: FakeFlutterNativeAssetsBuildRunner(
packagesWithNativeAssetsResult: <String>['bar'],
),
),
throwsToolExit(
message:
'Package(s) bar require the native assets feature to be enabled. '
'Enable using `flutter config --enable-native-assets`.',
),
);
},
);
testUsingContext(
'build no assets',
overrides: <Type, Generator>{ProcessManager: () => FakeProcessManager.empty()},
() async {
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
final Uri nonFlutterTesterAssetUri =
environment.buildDir.childFile(InstallCodeAssets.nativeAssetsFilename).uri;
await packageConfig.parent.create();
await packageConfig.create();
final Map<String, String> environmentDefines = <String, String>{
kBuildMode: BuildMode.debug.cliName,
};
final DartBuildResult dartBuildResult = await runFlutterSpecificDartBuild(
environmentDefines: environmentDefines,
targetPlatform: TargetPlatform.windows_x64,
projectUri: projectUri,
fileSystem: fileSystem,
buildRunner: FakeFlutterNativeAssetsBuildRunner(
packagesWithNativeAssetsResult: <String>['bar'],
),
);
await installCodeAssets(
dartBuildResult: dartBuildResult,
environmentDefines: environmentDefines,
targetPlatform: TargetPlatform.windows_x64,
projectUri: projectUri,
fileSystem: fileSystem,
nativeAssetsFileUri: nonFlutterTesterAssetUri,
);
expect(
await fileSystem.file(nonFlutterTesterAssetUri).readAsString(),
isNot(contains('package:bar/bar.dart')),
);
expect(
environment.projectDir
.childDirectory('build')
.childDirectory('native_assets')
.childDirectory('windows'),
exists,
);
},
);
testUsingContext(
'Native assets build error',
overrides: <Type, Generator>{ProcessManager: () => FakeProcessManager.empty()},
() async {
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
await packageConfig.parent.create();
await packageConfig.create();
expect(
() => runFlutterSpecificDartBuild(
environmentDefines: <String, String>{kBuildMode: BuildMode.debug.cliName},
targetPlatform: TargetPlatform.linux_x64,
projectUri: projectUri,
fileSystem: fileSystem,
buildRunner: FakeFlutterNativeAssetsBuildRunner(
packagesWithNativeAssetsResult: <String>['bar'],
buildResult: null,
),
),
throwsToolExit(message: 'Building native assets failed. See the logs for more details.'),
);
},
);
testUsingContext(
'Native assets: no duplicate assets with linking',
overrides: <Type, Generator>{ProcessManager: () => FakeProcessManager.empty()},
() async {
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
await packageConfig.parent.create();
await packageConfig.create();
final File directSoFile = environment.projectDir.childFile('direct.so');
directSoFile.writeAsBytesSync(<int>[]);
final File linkableAFile = environment.projectDir.childFile('linkable.a');
linkableAFile.writeAsBytesSync(<int>[]);
final File linkedSoFile = environment.projectDir.childFile('linked.so');
linkedSoFile.writeAsBytesSync(<int>[]);
CodeAsset makeCodeAsset(String name, Uri file, LinkMode linkMode) =>
CodeAsset(package: 'bar', name: name, linkMode: linkMode, file: file);
final DartBuildResult result = await runFlutterSpecificDartBuild(
environmentDefines: <String, String>{
// Release mode means the dart build has linking enabled.
kBuildMode: BuildMode.release.cliName,
},
targetPlatform: TargetPlatform.linux_x64,
projectUri: projectUri,
fileSystem: fileSystem,
buildRunner: FakeFlutterNativeAssetsBuildRunner(
packagesWithNativeAssetsResult: <String>['bar'],
buildResult: FakeFlutterNativeAssetsBuilderResult.fromAssets(
codeAssets: <CodeAsset>[
makeCodeAsset('direct', directSoFile.uri, DynamicLoadingBundled()),
],
codeAssetsForLinking: <String, List<CodeAsset>>{
'package:bar': <CodeAsset>[
makeCodeAsset('linkable', linkableAFile.uri, StaticLinking()),
],
},
),
linkResult: FakeFlutterNativeAssetsBuilderResult.fromAssets(
codeAssets: <CodeAsset>[
makeCodeAsset('linked', linkedSoFile.uri, DynamicLoadingBundled()),
],
),
),
);
expect(
result.codeAssets.map((FlutterCodeAsset c) => c.codeAsset.file!.toString()).toList()
..sort(),
<String>[directSoFile.uri.toString(), linkedSoFile.uri.toString()],
);
},
);
}