// Copyright (c) 2020, 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:convert'; import 'dart:io'; import 'package:path/path.dart' as path; import 'package:test/test.dart'; final dart2native = () { final sdkBin = path.dirname(Platform.executable); final dart2native = path.join(sdkBin, Platform.isWindows ? 'dart2native.bat' : 'dart2native'); if (!File(dart2native).existsSync()) { throw 'Failed to locate dart2native in the SDK'; } return path.canonicalize(dart2native); }(); class AotSnapshot { final String outputBinary; final String sizesJson; AotSnapshot({required this.outputBinary, required this.sizesJson}); } Future withFlag( Map source, String flag, Future Function(String) f) { return withFlagImpl(source, flag, (info) => f(info.sizesJson)); } Future withFlagImpl( Map source, String? flag, Future Function(AotSnapshot) f) { return withTempDir((dir) async { final snapshot = AotSnapshot( outputBinary: path.join(dir, 'output.exe'), sizesJson: path.join(dir, 'sizes.json'), ); final packages = path.join(dir, '.packages'); final mainDart = path.join(dir, 'main.dart'); // Create test input. for (var file in source.entries) { await File(path.join(dir, file.key)).writeAsString(file.value); } await File(packages).writeAsString(''' input:./ '''); await File(mainDart).writeAsString(''' import 'package:input/input.dart' as input; void main(List args) => input.main(args); '''); final extraGenSnapshotOptions = [ '--dwarf-stack-traces', if (flag != null) '$flag=${snapshot.sizesJson}', ]; final args = [ '-o', snapshot.outputBinary, '--packages=$packages', '--extra-gen-snapshot-options=${extraGenSnapshotOptions.join(',')}', mainDart, ]; // Compile input.dart to native and output instruction sizes. final result = await Process.run(dart2native, args); expect(result.exitCode, equals(0), reason: ''' Compilation completed with exit code ${result.exitCode}. Command line: $dart2native ${args.join(' ')} stdout: ${result.stdout} stderr: ${result.stderr} '''); expect(File(snapshot.outputBinary).existsSync(), isTrue, reason: 'Output binary exists'); if (flag != null) { expect(File(snapshot.sizesJson).existsSync(), isTrue, reason: 'Instruction sizes output exists'); } await f(snapshot); }); } late final shouldKeepTemporaryDirectories = Platform.environment['KEEP_TEMPORARY_DIRECTORIES']?.isNotEmpty == true; Future withTempDir(Future Function(String dir) f) async { final tempDir = Directory.systemTemp.createTempSync('instruction-sizes-test-'); try { await f(tempDir.path); } finally { if (shouldKeepTemporaryDirectories) { tempDir.deleteSync(recursive: true); } } } Future loadJson(File input) async { return (await input .openRead() .transform(utf8.decoder) .transform(json.decoder) .first)!; }