flutter/packages/flutter_tools/test/general.shard/android/native_assets_test.dart
Daco Harkes 634b326efc
Reapply "Native assets: roll deps" (#141748) (#141864)
Fixes https://github.com/flutter/flutter/issues/141827

Reland: https://dart-review.googlesource.com/c/sdk/+/346960 has rolled into g3, so the imports should now resolve in g3 as well.

> [!CAUTION]
> _Do NOT merge if "Google Testing" bot didn't run!_

Rolls the packages from https://github.com/dart-lang/native in the native assets implementation.

Most notable we're refactoring `package:native_assets_cli` for `build.dart` use.
Therefore, all imports to that package for Flutter/Dart should be to the implementation internals that are no longer visible for `build.dart` writers. Hence all the import updates.

No behavior in Flutter apps should change.

This PR also updates the template to use the latests version of `package:native_assets_cli` which no longer exposes all the implementation details.
2024-01-22 10:42:15 +00:00

388 lines
13 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:file/file.dart';
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/android/native_assets.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:native_assets_cli/native_assets_cli_internal.dart'
as native_assets_cli;
import 'package:native_assets_cli/native_assets_cli_internal.dart'
hide BuildMode, Target;
import 'package:package_config/package_config_types.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('dry run with no package config', overrides: <Type, Generator>{
ProcessManager: () => FakeProcessManager.empty(),
}, () async {
expect(
await dryRunNativeAssetsAndroid(
projectUri: projectUri,
fileSystem: fileSystem,
buildRunner: FakeNativeAssetsBuildRunner(
hasPackageConfigResult: false,
),
),
null,
);
expect(
(globals.logger as BufferLogger).traceText,
contains('No package config found. Skipping native assets compilation.'),
);
});
testUsingContext('build with no package config', overrides: <Type, Generator>{
ProcessManager: () => FakeProcessManager.empty(),
}, () async {
await buildNativeAssetsAndroid(
androidArchs: <AndroidArch>[AndroidArch.arm64_v8a],
targetAndroidNdkApi: 21,
projectUri: projectUri,
buildMode: BuildMode.debug,
fileSystem: fileSystem,
yamlParentDirectory: environment.buildDir.uri,
buildRunner: FakeNativeAssetsBuildRunner(
hasPackageConfigResult: false,
),
);
expect(
(globals.logger as BufferLogger).traceText,
contains('No package config found. Skipping native assets compilation.'),
);
});
testUsingContext('dry run with assets but not enabled', 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(
() => dryRunNativeAssetsAndroid(
projectUri: projectUri,
fileSystem: fileSystem,
buildRunner: FakeNativeAssetsBuildRunner(
packagesWithNativeAssetsResult: <Package>[
Package('bar', projectUri),
],
),
),
throwsToolExit(
message: 'Package(s) bar require the native assets feature to be enabled. '
'Enable using `flutter config --enable-native-assets`.',
),
);
});
testUsingContext('dry run with assets', overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true),
ProcessManager: () => FakeProcessManager.empty(),
}, () async {
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
await packageConfig.parent.create();
await packageConfig.create();
final Uri? nativeAssetsYaml = await dryRunNativeAssetsAndroid(
projectUri: projectUri,
fileSystem: fileSystem,
buildRunner: FakeNativeAssetsBuildRunner(
packagesWithNativeAssetsResult: <Package>[
Package('bar', projectUri),
],
dryRunResult: FakeNativeAssetsBuilderResult(
assets: <Asset>[
Asset(
id: 'package:bar/bar.dart',
linkMode: LinkMode.dynamic,
target: native_assets_cli.Target.macOSArm64,
path: AssetAbsolutePath(Uri.file('libbar.so')),
),
Asset(
id: 'package:bar/bar.dart',
linkMode: LinkMode.dynamic,
target: native_assets_cli.Target.macOSX64,
path: AssetAbsolutePath(Uri.file('libbar.so')),
),
],
),
),
);
expect(
(globals.logger as BufferLogger).traceText,
stringContainsInOrder(<String>[
'Dry running native assets for android.',
'Dry running native assets for android done.',
]),
);
expect(
nativeAssetsYaml,
projectUri.resolve('build/native_assets/android/native_assets.yaml'),
);
expect(
await fileSystem.file(nativeAssetsYaml).readAsString(),
contains('package:bar/bar.dart'),
);
});
testUsingContext('build with assets but not enabled', () async {
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
await packageConfig.parent.create();
await packageConfig.create();
expect(
() => buildNativeAssetsAndroid(
androidArchs: <AndroidArch>[AndroidArch.arm64_v8a],
targetAndroidNdkApi: 21,
projectUri: projectUri,
buildMode: BuildMode.debug,
fileSystem: fileSystem,
yamlParentDirectory: environment.buildDir.uri,
buildRunner: FakeNativeAssetsBuildRunner(
packagesWithNativeAssetsResult: <Package>[
Package('bar', projectUri),
],
),
),
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>{
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true),
ProcessManager: () => FakeProcessManager.empty(),
}, () async {
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
await packageConfig.parent.create();
await packageConfig.create();
await buildNativeAssetsAndroid(
androidArchs: <AndroidArch>[AndroidArch.arm64_v8a],
targetAndroidNdkApi: 21,
projectUri: projectUri,
buildMode: BuildMode.debug,
fileSystem: fileSystem,
yamlParentDirectory: environment.buildDir.uri,
buildRunner: FakeNativeAssetsBuildRunner(
packagesWithNativeAssetsResult: <Package>[
Package('bar', projectUri),
],
),
);
expect(
environment.buildDir.childFile('native_assets.yaml'),
exists,
);
});
testUsingContext('build with assets',
skip: const LocalPlatform().isWindows, // [intended] Backslashes in commands, but we will never run these commands on Windows.
overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true),
ProcessManager: () => FakeProcessManager.empty(),
}, () async {
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
await packageConfig.parent.create();
await packageConfig.create();
final File dylibAfterCompiling = fileSystem.file('libbar.so');
// The mock doesn't create the file, so create it here.
await dylibAfterCompiling.create();
await buildNativeAssetsAndroid(
androidArchs: <AndroidArch>[AndroidArch.arm64_v8a],
targetAndroidNdkApi: 21,
projectUri: projectUri,
buildMode: BuildMode.debug,
fileSystem: fileSystem,
yamlParentDirectory: environment.buildDir.uri,
buildRunner: FakeNativeAssetsBuildRunner(
packagesWithNativeAssetsResult: <Package>[
Package('bar', projectUri),
],
buildResult: FakeNativeAssetsBuilderResult(
assets: <Asset>[
Asset(
id: 'package:bar/bar.dart',
linkMode: LinkMode.dynamic,
target: native_assets_cli.Target.androidArm64,
path: AssetAbsolutePath(Uri.file('libbar.so')),
),
],
),
),
);
expect(
(globals.logger as BufferLogger).traceText,
stringContainsInOrder(<String>[
'Building native assets for [android_arm64] debug.',
'Building native assets for [android_arm64] done.',
]),
);
expect(
environment.buildDir.childFile('native_assets.yaml'),
exists,
);
});
// Ensure no exceptions for a non installed NDK are thrown if no native
// assets have to be build.
testUsingContext(
'does not throw if NDK not present but no native assets present',
overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true),
ProcessManager: () => FakeProcessManager.empty(),
}, () async {
final File packageConfig =
environment.projectDir.childFile('.dart_tool/package_config.json');
await packageConfig.create(recursive: true);
await buildNativeAssetsAndroid(
androidArchs: <AndroidArch>[AndroidArch.x86_64],
targetAndroidNdkApi: 21,
projectUri: projectUri,
buildMode: BuildMode.debug,
fileSystem: fileSystem,
buildRunner: _BuildRunnerWithoutNdk(),
);
expect(
(globals.logger as BufferLogger).traceText,
isNot(contains('Building native assets for ')),
);
});
testUsingContext('throw if NDK not present and there are native assets',
overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true),
}, () async {
final File packageConfig =
environment.projectDir.childFile('.dart_tool/package_config.json');
await packageConfig.parent.create();
await packageConfig.create();
expect(
() => buildNativeAssetsAndroid(
androidArchs: <AndroidArch>[AndroidArch.arm64_v8a],
targetAndroidNdkApi: 21,
projectUri: projectUri,
buildMode: BuildMode.debug,
fileSystem: fileSystem,
yamlParentDirectory: environment.buildDir.uri,
buildRunner: _BuildRunnerWithoutNdk(
packagesWithNativeAssetsResult: <Package>[
Package('bar', projectUri),
],
),
),
throwsToolExit(
message: 'Android NDK Clang could not be found.',
),
);
});
testUsingContext('Native assets dry run error', overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true),
ProcessManager: () => FakeProcessManager.empty(),
}, () async {
final File packageConfig =
environment.projectDir.childFile('.dart_tool/package_config.json');
await packageConfig.parent.create();
await packageConfig.create();
expect(
() => dryRunNativeAssetsAndroid(
projectUri: projectUri,
fileSystem: fileSystem,
buildRunner: FakeNativeAssetsBuildRunner(
packagesWithNativeAssetsResult: <Package>[
Package('bar', projectUri),
],
dryRunResult: const FakeNativeAssetsBuilderResult(
success: false,
),
),
),
throwsToolExit(
message:
'Building native assets failed. See the logs for more details.',
),
);
});
testUsingContext('Native assets build error', overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true),
ProcessManager: () => FakeProcessManager.empty(),
}, () async {
final File packageConfig =
environment.projectDir.childFile('.dart_tool/package_config.json');
await packageConfig.parent.create();
await packageConfig.create();
expect(
() => buildNativeAssetsAndroid(
androidArchs: <AndroidArch>[AndroidArch.arm64_v8a],
targetAndroidNdkApi: 21,
projectUri: projectUri,
buildMode: BuildMode.debug,
fileSystem: fileSystem,
yamlParentDirectory: environment.buildDir.uri,
buildRunner: FakeNativeAssetsBuildRunner(
packagesWithNativeAssetsResult: <Package>[
Package('bar', projectUri),
],
buildResult: const FakeNativeAssetsBuilderResult(
success: false,
),
),
),
throwsToolExit(
message:
'Building native assets failed. See the logs for more details.',
),
);
});
}
class _BuildRunnerWithoutNdk extends FakeNativeAssetsBuildRunner {
_BuildRunnerWithoutNdk({
super.packagesWithNativeAssetsResult = const <Package>[],
});
@override
Future<CCompilerConfig> get ndkCCompilerConfig async =>
throwToolExit('Android NDK Clang could not be found.');
}