| // Copyright (c) 2023, 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. | |
| @TestOn('vm') | |
| library; | |
| import 'dart:io'; | |
| import 'package:checks/checks.dart'; | |
| import 'package:pub/src/dart.dart'; | |
| import 'package:pub/src/exceptions.dart'; | |
| import 'package:pub/src/log.dart'; | |
| import 'package:test/test.dart'; | |
| import 'descriptor.dart'; | |
| String outputPath() => '$sandbox/output/snapshot'; | |
| String incrementalDillPath() => '${outputPath()}.incremental'; | |
| // A quite big program is needed for the caching to be an actual advantage. | |
| FileDescriptor foo = file('foo.dart', ''' | |
| foo() { | |
| ${List.generate(500000, (index) => 'print("$index");').join('\n')} | |
| } | |
| '''); | |
| FileDescriptor workingMain = file('main.dart', ''' | |
| import 'foo.dart'; | |
| main() async { | |
| foo(); | |
| } | |
| '''); | |
| FileDescriptor brokenMain = file('main.dart', ''' | |
| import 'foo.dart'; | |
| yadda yadda | |
| main() asyncc { | |
| foo(); | |
| } | |
| '''); | |
| Future<Duration> timeCompilation( | |
| String executable, { | |
| bool fails = false, | |
| }) async { | |
| final s = Stopwatch()..start(); | |
| verbosity = Verbosity.none; | |
| Future<void> compile() async { | |
| await precompile( | |
| executablePath: executable, | |
| name: 'abc', | |
| outputPath: outputPath(), | |
| packageConfigPath: path('app/.dart_tool/package_config.json'), | |
| ); | |
| } | |
| if (fails) { | |
| await check(compile()).throws<ApplicationException>(); | |
| } else { | |
| await compile(); | |
| } | |
| verbosity = Verbosity.normal; | |
| return s.elapsed; | |
| } | |
| void main() { | |
| test( | |
| 'Precompilation is much faster second time and removes old artifacts', | |
| () async { | |
| await dir('app', [workingMain, foo, packageConfigFile([])]).create(); | |
| final first = await timeCompilation(path('app/main.dart')); | |
| check( | |
| because: 'Should not leave a stray directory.', | |
| File(incrementalDillPath()).existsSync(), | |
| ).isFalse(); | |
| check(File(outputPath()).existsSync()).isTrue(); | |
| // Do a second compilation to compare the compile times, it should be much | |
| // faster because it can reuse the compiled data in the dill file. | |
| final second = await timeCompilation(path('app/main.dart')); | |
| check(first).isGreaterThan(second * 2); | |
| // Now create an error to test that the output is placed at a different | |
| // location. | |
| await dir('app', [brokenMain, foo, packageConfigFile([])]).create(); | |
| final afterErrors = await timeCompilation( | |
| path('app/main.dart'), | |
| fails: true, | |
| ); | |
| check(File(incrementalDillPath()).existsSync()).isTrue(); | |
| check(File(outputPath()).existsSync()).isFalse(); | |
| check(first).isGreaterThan(afterErrors * 2); | |
| // Fix the error, and check that we still use the cached output to improve | |
| // compile times. | |
| await dir('app', [workingMain]).create(); | |
| final afterFix = await timeCompilation(path('app/main.dart')); | |
| // The output from the failed compilation should now be gone. | |
| check(File('${outputPath()}.incremental').existsSync()).isFalse(); | |
| check(File(outputPath()).existsSync()).isTrue(); | |
| check(first).isGreaterThan(afterFix * 2); | |
| }, | |
| ); | |
| } |