diff --git a/pkgs/native_assets_cli/CHANGELOG.md b/pkgs/native_assets_cli/CHANGELOG.md index 03e05bb5f7..20a84d7d75 100644 --- a/pkgs/native_assets_cli/CHANGELOG.md +++ b/pkgs/native_assets_cli/CHANGELOG.md @@ -9,6 +9,11 @@ it can be controlled in the build hook together with the `OptimizationLevel`. Most likely, every package should ship with `release`. `BuildMode.debug` should only be used while developing the package locally. +- **Breaking change**: Change the behavior of `testBuildHook` and + `testCodeBuildHook`; instead of defining tests, these methods should now be + called from within tests. +- Move the `package:test` dependency from a regular dependency (exported to + calling packages) to a dev_dependency. - Update pubspec.yaml of examples to use 0.9.0 of `package:native_assets_cli`. - Consolidate [CodeAsset] specific things into `lib/src/code_assets/*` diff --git a/pkgs/native_assets_cli/example/build/local_asset/test/build_test.dart b/pkgs/native_assets_cli/example/build/local_asset/test/build_test.dart index 8f2ea6180e..7b8ad34d69 100644 --- a/pkgs/native_assets_cli/example/build/local_asset/test/build_test.dart +++ b/pkgs/native_assets_cli/example/build/local_asset/test/build_test.dart @@ -8,16 +8,17 @@ import 'package:test/test.dart'; import '../hook/build.dart' as build; void main() async { - await testCodeBuildHook( - description: 'test my build hook', - mainMethod: build.main, - check: (_, output) { - expect(output.codeAssets, isNotEmpty); - expect( - output.codeAssets.first.id, - 'package:local_asset/asset.txt', - ); - }, - buildAssetTypes: [CodeAsset.type], - ); + test('test my build hook', () async { + await testCodeBuildHook( + mainMethod: build.main, + check: (_, output) { + expect(output.codeAssets, isNotEmpty); + expect( + output.codeAssets.first.id, + 'package:local_asset/asset.txt', + ); + }, + buildAssetTypes: [CodeAsset.type], + ); + }); } diff --git a/pkgs/native_assets_cli/lib/src/code_assets/testing.dart b/pkgs/native_assets_cli/lib/src/code_assets/testing.dart index 01a8a8c2dc..25f3741f11 100644 --- a/pkgs/native_assets_cli/lib/src/code_assets/testing.dart +++ b/pkgs/native_assets_cli/lib/src/code_assets/testing.dart @@ -4,15 +4,23 @@ import 'dart:async'; -import 'package:meta/meta.dart' show isTest; -import 'package:test/test.dart'; - import '../../code_assets_builder.dart'; import '../../test.dart'; +import '../validation.dart'; -@isTest +/// Validate a code build hook; this will throw an exception on validation +/// errors. +/// +/// This is intended to be used from tests, e.g.: +/// +/// ``` +/// test('test my build hook', () async { +/// await testCodeBuildHook( +/// ... +/// ); +/// }); +/// ``` Future testCodeBuildHook({ - required String description, // ignore: inference_failure_on_function_return_type required Function(List arguments) mainMethod, required FutureOr Function(BuildConfig, BuildOutput) check, @@ -28,7 +36,6 @@ Future testCodeBuildHook({ bool? linkingEnabled, }) async { await testBuildHook( - description: description, mainMethod: mainMethod, extraConfigSetup: (config) { config.setupCodeConfig( @@ -42,7 +49,13 @@ Future testCodeBuildHook({ ); }, check: (config, output) async { - expect(await validateCodeAssetBuildOutput(config, output), isEmpty); + final validationErrors = + await validateCodeAssetBuildOutput(config, output); + if (validationErrors.isNotEmpty) { + throw ValidationFailure( + 'encountered build output validation issues: $validationErrors'); + } + await check(config, output); }, targetOS: targetOS, diff --git a/pkgs/native_assets_cli/lib/src/validation.dart b/pkgs/native_assets_cli/lib/src/validation.dart index c20edd3fd7..72c01c7a3a 100644 --- a/pkgs/native_assets_cli/lib/src/validation.dart +++ b/pkgs/native_assets_cli/lib/src/validation.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:io'; + import '../native_assets_cli_builder.dart'; typedef ValidationErrors = List; @@ -99,3 +100,12 @@ List _validateAssetsForLinking( } return errors; } + +class ValidationFailure implements Exception { + final String? message; + + ValidationFailure(this.message); + + @override + String toString() => message.toString(); +} diff --git a/pkgs/native_assets_cli/lib/test.dart b/pkgs/native_assets_cli/lib/test.dart index 3f23d35bc9..21deb24907 100644 --- a/pkgs/native_assets_cli/lib/test.dart +++ b/pkgs/native_assets_cli/lib/test.dart @@ -6,18 +6,26 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:meta/meta.dart' show isTest; -import 'package:test/test.dart'; import 'package:yaml/yaml.dart'; import 'native_assets_cli_builder.dart'; import 'native_assets_cli_internal.dart' show Hook; +import 'src/validation.dart'; export 'native_assets_cli_builder.dart'; -@isTest +/// Validate a build hook; this will throw an exception on validation errors. +/// +/// This is intended to be used from tests, e.g.: +/// +/// ``` +/// test('test my build hook', () async { +/// await testCodeBuildHook( +/// ... +/// ); +/// }); +/// ``` Future testBuildHook({ - required String description, required void Function(BuildConfigBuilder) extraConfigSetup, required FutureOr Function(List arguments) mainMethod, required FutureOr Function(BuildConfig config, BuildOutput output) @@ -26,49 +34,61 @@ Future testBuildHook({ List? buildAssetTypes, bool? linkingEnabled, }) async { - test( - description, - () async { - final tempDir = await _tempDirForTest(); - final outputDirectory = tempDir.resolve('output/'); - final outputDirectoryShared = tempDir.resolve('output_shared/'); - - await Directory.fromUri(outputDirectory).create(); - await Directory.fromUri(outputDirectoryShared).create(); - - final configBuilder = BuildConfigBuilder(); - configBuilder - ..setupHookConfig( - packageRoot: Directory.current.uri, - packageName: _readPackageNameFromPubspec(), - targetOS: targetOS ?? OS.current, - buildAssetTypes: buildAssetTypes ?? [], - ) - ..setupBuildConfig( - dryRun: false, - linkingEnabled: true, - ) - ..setupBuildRunConfig( - outputDirectory: outputDirectory, - outputDirectoryShared: outputDirectoryShared, - ); - extraConfigSetup(configBuilder); - - final config = BuildConfig(configBuilder.json); - - final configUri = tempDir.resolve(Hook.build.outputName); - _writeJsonTo(configUri, config.json); - await mainMethod(['--config=${configUri.toFilePath()}']); - final output = BuildOutput( - _readJsonFrom(config.outputDirectory.resolve(Hook.build.outputName))); - - // Test conformance of protocol invariants. - expect(await validateBuildOutput(config, output), isEmpty); - - // Run user-defined tests. - check(config, output); - }, - ); + const keepTempKey = 'KEEP_TEMPORARY_DIRECTORIES'; + + final tempDir = await Directory.systemTemp.createTemp(); + + try { + // Deal with Windows temp folder aliases. + final tempUri = + Directory(await tempDir.resolveSymbolicLinks()).uri.normalizePath(); + final outputDirectory = tempUri.resolve('output/'); + final outputDirectoryShared = tempUri.resolve('output_shared/'); + + await Directory.fromUri(outputDirectory).create(); + await Directory.fromUri(outputDirectoryShared).create(); + + final configBuilder = BuildConfigBuilder(); + configBuilder + ..setupHookConfig( + packageRoot: Directory.current.uri, + packageName: _readPackageNameFromPubspec(), + targetOS: targetOS ?? OS.current, + buildAssetTypes: buildAssetTypes ?? [], + ) + ..setupBuildConfig( + dryRun: false, + linkingEnabled: true, + ) + ..setupBuildRunConfig( + outputDirectory: outputDirectory, + outputDirectoryShared: outputDirectoryShared, + ); + extraConfigSetup(configBuilder); + + final config = BuildConfig(configBuilder.json); + + final configUri = tempUri.resolve(Hook.build.outputName); + _writeJsonTo(configUri, config.json); + await mainMethod(['--config=${configUri.toFilePath()}']); + final output = BuildOutput( + _readJsonFrom(config.outputDirectory.resolve(Hook.build.outputName))); + + // Test conformance of protocol invariants. + final validationErrors = await validateBuildOutput(config, output); + if (validationErrors.isNotEmpty) { + throw ValidationFailure( + 'encountered build output validation issues: $validationErrors'); + } + + // Run user-defined tests. + await check(config, output); + } finally { + final keepTempDir = (Platform.environment[keepTempKey] ?? '').isNotEmpty; + if (!keepTempDir) { + tempDir.deleteSync(recursive: true); + } + } } void _writeJsonTo(Uri uri, Map json) { @@ -88,18 +108,3 @@ String _readPackageNameFromPubspec() { final yaml = loadYaml(readAsString) as YamlMap; return yaml['name'] as String; } - -const keepTempKey = 'KEEP_TEMPORARY_DIRECTORIES'; - -Future _tempDirForTest({String? prefix, bool keepTemp = false}) async { - final tempDir = await Directory.systemTemp.createTemp(prefix); - // Deal with Windows temp folder aliases. - final tempUri = - Directory(await tempDir.resolveSymbolicLinks()).uri.normalizePath(); - if ((!Platform.environment.containsKey(keepTempKey) || - Platform.environment[keepTempKey]!.isEmpty) && - !keepTemp) { - addTearDown(() => tempDir.delete(recursive: true)); - } - return tempUri; -} diff --git a/pkgs/native_assets_cli/pubspec.yaml b/pkgs/native_assets_cli/pubspec.yaml index 193e6783ed..d72d7b0954 100644 --- a/pkgs/native_assets_cli/pubspec.yaml +++ b/pkgs/native_assets_cli/pubspec.yaml @@ -23,10 +23,10 @@ dependencies: logging: ^1.2.0 meta: ^1.15.0 pub_semver: ^2.1.3 - test: ^1.25.7 yaml: ^3.1.2 # Used for reading pubspec.yaml to obtain the package name dev_dependencies: dart_flutter_team_lints: ^2.1.1 file_testing: ^3.0.0 glob: any + test: ^1.25.7