| // Copyright (c) 2026, 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. | |
| import 'dart:io'; | |
| import 'package:dartdev/src/native_assets.dart'; | |
| import 'package:dartdev/src/resident_frontend_utils.dart'; | |
| import 'package:test/test.dart'; | |
| import 'helpers.dart'; | |
| void main() { | |
| group('compileNativeAssetsToDill', () { | |
| test('compiles native_assets.yaml to dill', () async { | |
| await inTempDir((tempUri) async { | |
| final nativeAssetsYaml = File.fromUri( | |
| tempUri.resolve('native_assets.yaml'), | |
| ); | |
| await nativeAssetsYaml.writeAsString(''' | |
| format-version: | |
| - 1 | |
| - 0 | |
| - 0 | |
| native-assets: {} | |
| '''); | |
| final outputDill = tempUri.resolve('output.dill'); | |
| final success = await compileNativeAssetsToDill( | |
| nativeAssetsYamlUri: nativeAssetsYaml.uri, | |
| outputDillUri: outputDill, | |
| ); | |
| expect(success, isTrue); | |
| final outputFile = File.fromUri(outputDill); | |
| expect(await outputFile.exists(), isTrue); | |
| expect(await isFileKernelFile(outputFile), isTrue); | |
| }); | |
| }); | |
| test('returns false when native assets compilation fails', () async { | |
| await inTempDir((tempUri) async { | |
| final nonExistentYaml = tempUri.resolve('does_not_exist.yaml'); | |
| final outputDill = tempUri.resolve('output.dill'); | |
| final success = await compileNativeAssetsToDill( | |
| nativeAssetsYamlUri: nonExistentYaml, | |
| outputDillUri: outputDill, | |
| ); | |
| expect(success, isFalse); | |
| }); | |
| }); | |
| }); | |
| group('concatenateNativeAssetsKernel', () { | |
| test('concatenates kernel file with native assets dill', () async { | |
| await inTempDir((tempUri) async { | |
| final dummyKernelFile = File.fromUri(tempUri.resolve('original.dill')); | |
| // Kernel magic number: 0x90, 0xab, 0xcd, 0xef | |
| final dummyKernelBytes = [0x90, 0xab, 0xcd, 0xef, 1, 2, 3, 4, 5]; | |
| await dummyKernelFile.writeAsBytes(dummyKernelBytes); | |
| final nativeAssetsYaml = File.fromUri( | |
| tempUri.resolve('native_assets.yaml'), | |
| ); | |
| await nativeAssetsYaml.writeAsString(''' | |
| format-version: | |
| - 1 | |
| - 0 | |
| - 0 | |
| native-assets: {} | |
| '''); | |
| final concatenatedPath = await concatenateNativeAssetsKernel( | |
| kernelFilePath: dummyKernelFile.path, | |
| nativeAssetsYamlUri: nativeAssetsYaml.uri, | |
| tempDirUri: tempUri, | |
| ); | |
| expect(concatenatedPath, isNotNull); | |
| final concatenatedFile = File(concatenatedPath!); | |
| expect(await concatenatedFile.exists(), isTrue); | |
| final concatenatedBytes = await concatenatedFile.readAsBytes(); | |
| final nativeAssetsDill = File.fromUri( | |
| tempUri.resolve('native_assets.dill'), | |
| ); | |
| expect(await nativeAssetsDill.exists(), isTrue); | |
| final nativeAssetsBytes = await nativeAssetsDill.readAsBytes(); | |
| expect( | |
| concatenatedBytes.length, | |
| equals(dummyKernelBytes.length + nativeAssetsBytes.length), | |
| ); | |
| expect( | |
| concatenatedBytes.sublist(0, dummyKernelBytes.length), | |
| equals(dummyKernelBytes), | |
| ); | |
| expect( | |
| concatenatedBytes.sublist(dummyKernelBytes.length), | |
| equals(nativeAssetsBytes), | |
| ); | |
| }); | |
| }); | |
| test( | |
| 'updating native assets between concatenations updates output while preserving base kernel', | |
| () async { | |
| await inTempDir((tempUri) async { | |
| final baseKernelFile = File.fromUri(tempUri.resolve('base.dill')); | |
| final baseKernelBytes = [0x90, 0xab, 0xcd, 0xef, 10, 20, 30, 40]; | |
| await baseKernelFile.writeAsBytes(baseKernelBytes); | |
| final run1TempDir = Directory.fromUri(tempUri.resolve('run1/')); | |
| await run1TempDir.create(); | |
| final nativeAssetsYaml1 = File.fromUri( | |
| run1TempDir.uri.resolve('native_assets.yaml'), | |
| ); | |
| await nativeAssetsYaml1.writeAsString(''' | |
| format-version: | |
| - 1 | |
| - 0 | |
| - 0 | |
| native-assets: | |
| linux_x64: | |
| foo: | |
| - system | |
| - libfoo.so | |
| '''); | |
| final concatenatedPath1 = await concatenateNativeAssetsKernel( | |
| kernelFilePath: baseKernelFile.path, | |
| nativeAssetsYamlUri: nativeAssetsYaml1.uri, | |
| tempDirUri: run1TempDir.uri, | |
| ); | |
| expect(concatenatedPath1, isNotNull); | |
| final bytes1 = await File(concatenatedPath1!).readAsBytes(); | |
| final run2TempDir = Directory.fromUri(tempUri.resolve('run2/')); | |
| await run2TempDir.create(); | |
| final nativeAssetsYaml2 = File.fromUri( | |
| run2TempDir.uri.resolve('native_assets.yaml'), | |
| ); | |
| await nativeAssetsYaml2.writeAsString(''' | |
| format-version: | |
| - 1 | |
| - 0 | |
| - 0 | |
| native-assets: | |
| linux_x64: | |
| bar: | |
| - system | |
| - libbar.so | |
| '''); | |
| final concatenatedPath2 = await concatenateNativeAssetsKernel( | |
| kernelFilePath: baseKernelFile.path, | |
| nativeAssetsYamlUri: nativeAssetsYaml2.uri, | |
| tempDirUri: run2TempDir.uri, | |
| ); | |
| expect(concatenatedPath2, isNotNull); | |
| final bytes2 = await File(concatenatedPath2!).readAsBytes(); | |
| // Both start with the same base kernel bytes. | |
| expect( | |
| bytes1.sublist(0, baseKernelBytes.length), | |
| equals(baseKernelBytes), | |
| ); | |
| expect( | |
| bytes2.sublist(0, baseKernelBytes.length), | |
| equals(baseKernelBytes), | |
| ); | |
| // But the native assets portions differ, reflecting the update. | |
| expect( | |
| bytes1.sublist(baseKernelBytes.length), | |
| isNot(equals(bytes2.sublist(baseKernelBytes.length))), | |
| ); | |
| }); | |
| }, | |
| ); | |
| test('returns null when native assets compilation fails', () async { | |
| await inTempDir((tempUri) async { | |
| final dummyKernelFile = File.fromUri(tempUri.resolve('original.dill')); | |
| await dummyKernelFile.writeAsBytes([0x90, 0xab, 0xcd, 0xef, 1, 2, 3]); | |
| final nonExistentYaml = tempUri.resolve('does_not_exist.yaml'); | |
| final result = await concatenateNativeAssetsKernel( | |
| kernelFilePath: dummyKernelFile.path, | |
| nativeAssetsYamlUri: nonExistentYaml, | |
| tempDirUri: tempUri, | |
| ); | |
| expect(result, isNull); | |
| }); | |
| }); | |
| }); | |
| } |