| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 // Test that the CPS IR code generator compiles programs and produces the | |
| 6 // the expected output. | |
| 7 | |
| 8 import 'dart:io'; | |
| 9 | |
| 10 import 'package:async_helper/async_helper.dart'; | |
| 11 import 'package:expect/expect.dart'; | |
| 12 import 'package:compiler/src/apiimpl.dart' show | |
| 13 CompilerImpl; | |
| 14 import '../memory_compiler.dart'; | |
| 15 import 'package:compiler/src/js/js.dart' as js; | |
| 16 import 'package:compiler/src/elements/elements.dart' show | |
| 17 ClassElement, | |
| 18 Element; | |
| 19 | |
| 20 // Regular experession used to extract the method name that is used to match the | |
| 21 // test output. By default we match the output of main. | |
| 22 final RegExp elementNameRegExp = new RegExp(r'^// Method to test: (.*)$', | |
| 23 multiLine: true); | |
| 24 | |
| 25 runTest(String filename, {bool update: false}) { | |
| 26 var outputname = filename.replaceFirst('.dart', '.js'); | |
| 27 String source = new File.fromUri(Platform.script.resolve('input/$filename')) | |
| 28 .readAsStringSync(); | |
| 29 var expectedFile = | |
| 30 new File.fromUri(Platform.script.resolve('expected/$outputname')); | |
| 31 String expected = ''; | |
| 32 if (expectedFile.existsSync()) { | |
| 33 expected = expectedFile.readAsStringSync() | |
| 34 .replaceAll(new RegExp('^//.*\n', multiLine: true), '') | |
| 35 .trim(); | |
| 36 } | |
| 37 | |
| 38 var match = elementNameRegExp.firstMatch(source); | |
| 39 var elementName = match?.group(1); | |
| 40 | |
| 41 Map files = { | |
| 42 TEST_MAIN_FILE: source, | |
| 43 'package:expect/expect.dart': ''' | |
| 44 class NoInline { | |
| 45 const NoInline(); | |
| 46 } | |
| 47 class TrustTypeAnnotations { | |
| 48 const TrustTypeAnnotations(); | |
| 49 } | |
| 50 class AssumeDynamic { | |
| 51 const AssumeDynamic(); | |
| 52 } | |
| 53 ''', | |
| 54 }; | |
| 55 asyncTest(() async { | |
| 56 Uri uri = Uri.parse('memory:$TEST_MAIN_FILE'); | |
| 57 String found = null; | |
| 58 try { | |
| 59 CompilationResult result = await runCompiler( | |
| 60 entryPoint: uri, | |
| 61 memorySourceFiles: files, | |
| 62 options: <String>['--use-cps-ir']); | |
| 63 Expect.isTrue(result.isSuccess); | |
| 64 CompilerImpl compiler = result.compiler; | |
| 65 if (expected != null) { | |
| 66 found = elementName == null | |
| 67 ? _getCodeForMain(compiler) | |
| 68 : _getCodeForMethod(compiler, elementName); | |
| 69 } | |
| 70 } catch (e, st) { | |
| 71 print(e); | |
| 72 print(st); | |
| 73 var message = 'The following test failed to compile:\n' | |
| 74 '${_formatTest(files)}'; | |
| 75 if (update) { | |
| 76 print('\n\n$message\n'); | |
| 77 return; | |
| 78 } else { | |
| 79 Expect.fail(message); | |
| 80 } | |
| 81 } | |
| 82 if (expected != found) { | |
| 83 if (update) { | |
| 84 // Include the input in a comment of the expected file to make it easier | |
| 85 // to see the relation between input and output in code reviews. | |
| 86 String comment = source.trim().replaceAll('\n', '\n// '); | |
| 87 expectedFile.writeAsStringSync('// Expectation for test: \n' | |
| 88 '// ${comment}\n\n${found}\n'); | |
| 89 print('INFO: $expectedFile was updated'); | |
| 90 } else { | |
| 91 Expect.fail('Unexpected output for test:\n ' | |
| 92 '${_formatTest(files).replaceAll('\n', '\n ')}\n' | |
| 93 'Expected:\n ${expected.replaceAll('\n', '\n ')}\n\n' | |
| 94 'but found:\n ${found?.replaceAll('\n', '\n ')}\n' | |
| 95 '$regenerateCommand'); | |
| 96 } | |
| 97 } | |
| 98 }); | |
| 99 } | |
| 100 | |
| 101 String get regenerateCommand { | |
| 102 var flags = Platform.packageRoot == null | |
| 103 ? '' : '--package-root=${Platform.packageRoot} '; | |
| 104 return ''' | |
| 105 If you wish to update the test expectations, rerun this test passing "update" as | |
| 106 an argument, as follows: | |
| 107 | |
| 108 dart $flags${Platform.script} update | |
| 109 | |
| 110 If you want to update more than one test at once, run: | |
| 111 dart $flags${Platform.script.resolve('update_all.dart')} | |
| 112 | |
| 113 '''; | |
| 114 } | |
| 115 | |
| 116 const String TEST_MAIN_FILE = 'test.dart'; | |
| 117 | |
| 118 String _formatTest(Map test) { | |
| 119 return test[TEST_MAIN_FILE]; | |
| 120 } | |
| 121 | |
| 122 String _getCodeForMain(CompilerImpl compiler) { | |
| 123 Element mainFunction = compiler.mainFunction; | |
| 124 js.Node ast = compiler.enqueuer.codegen.generatedCode[mainFunction]; | |
| 125 return js.prettyPrint(ast, compiler); | |
| 126 } | |
| 127 | |
| 128 String _getCodeForMethod(CompilerImpl compiler, | |
| 129 String name) { | |
| 130 Element foundElement; | |
| 131 for (Element element in compiler.enqueuer.codegen.generatedCode.keys) { | |
| 132 if (element.toString() == name) { | |
| 133 if (foundElement != null) { | |
| 134 Expect.fail('Multiple compiled elements are called $name'); | |
| 135 } | |
| 136 foundElement = element; | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 if (foundElement == null) { | |
| 141 Expect.fail('There is no compiled element called $name'); | |
| 142 } | |
| 143 | |
| 144 js.Node ast = compiler.enqueuer.codegen.generatedCode[foundElement]; | |
| 145 return js.prettyPrint(ast, compiler); | |
| 146 } | |
| OLD | NEW |