| // Copyright (c) 2013, 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. |
| |
| // Test the exit code of dart2js in case of exceptions, errors, warnings, etc. |
| |
| |
| import 'dart:async'; |
| import 'dart:io' show Platform; |
| |
| import 'package:async_helper/async_helper.dart'; |
| import 'package:expect/expect.dart'; |
| |
| import 'package:compiler/compiler.dart' as api; |
| import 'package:compiler/src/dart2js.dart' as entry; |
| import 'package:compiler/src/dart2jslib.dart'; |
| import 'package:compiler/src/apiimpl.dart' as apiimpl; |
| import 'package:compiler/src/elements/elements.dart'; |
| import 'package:compiler/src/library_loader.dart'; |
| import 'package:compiler/src/resolution/resolution.dart'; |
| import 'package:compiler/src/scanner/scannerlib.dart'; |
| import 'package:compiler/src/util/util.dart'; |
| |
| class TestCompiler extends apiimpl.Compiler { |
| final String testMarker; |
| final String testType; |
| final Function onTest; |
| |
| TestCompiler(api.CompilerInputProvider inputProvider, |
| api.CompilerOutputProvider outputProvider, |
| api.DiagnosticHandler handler, |
| Uri libraryRoot, |
| Uri packageRoot, |
| List<String> options, |
| Map<String, dynamic> environment, |
| String this.testMarker, |
| String this.testType, |
| Function this.onTest) |
| : super(inputProvider, outputProvider, handler, libraryRoot, |
| packageRoot, options, environment) { |
| scanner = new TestScanner(this); |
| resolver = new TestResolver(this, backend.constantCompilerTask); |
| test('Compiler'); |
| } |
| |
| Future<bool> run(Uri uri) { |
| test('Compiler.run'); |
| return super.run(uri); |
| } |
| |
| Future onLibraryScanned(LibraryElement element, LibraryLoader loader) { |
| test('Compiler.onLibraryScanned'); |
| return super.onLibraryScanned(element, loader); |
| } |
| |
| Future onLibrariesLoaded(LoadedLibraries loadedLibraries) { |
| test('Compiler.onLibrariesLoaded'); |
| return super.onLibrariesLoaded(loadedLibraries); |
| } |
| |
| void analyzeElement(Element element) { |
| test('Compiler.analyzeElement'); |
| super.analyzeElement(element); |
| } |
| |
| void codegen(CodegenWorkItem work, CodegenEnqueuer world) { |
| test('Compiler.codegen'); |
| super.codegen(work, world); |
| } |
| |
| withCurrentElement(Element element, f()) { |
| return super.withCurrentElement(element, () { |
| test('Compiler.withCurrentElement'); |
| return f(); |
| }); |
| } |
| |
| test(String marker) { |
| if (marker == testMarker) { |
| switch (testType) { |
| case 'assert': |
| onTest(testMarker, testType); |
| assert(false); |
| break; |
| case 'invariant': |
| onTest(testMarker, testType); |
| invariant(NO_LOCATION_SPANNABLE, false, message: marker); |
| break; |
| case 'warning': |
| onTest(testMarker, testType); |
| reportWarning(NO_LOCATION_SPANNABLE, |
| MessageKind.GENERIC, {'text': marker}); |
| break; |
| case 'error': |
| onTest(testMarker, testType); |
| reportError(NO_LOCATION_SPANNABLE, |
| MessageKind.GENERIC, {'text': marker}); |
| break; |
| case 'internalError': |
| onTest(testMarker, testType); |
| internalError(NO_LOCATION_SPANNABLE, marker); |
| break; |
| case 'NoSuchMethodError': |
| onTest(testMarker, testType); |
| null.foo; |
| break; |
| case '': |
| onTest(testMarker, testType); |
| break; |
| } |
| } |
| } |
| } |
| |
| class TestScanner extends ScannerTask { |
| TestScanner(TestCompiler compiler) : super(compiler); |
| |
| TestCompiler get compiler => super.compiler; |
| |
| void scanElements(CompilationUnitElement compilationUnit) { |
| compiler.test('ScannerTask.scanElements'); |
| super.scanElements(compilationUnit); |
| } |
| } |
| |
| class TestResolver extends ResolverTask { |
| TestResolver(TestCompiler compiler, ConstantCompiler constantCompiler) |
| : super(compiler, constantCompiler); |
| |
| TestCompiler get compiler => super.compiler; |
| |
| void computeClassMembers(ClassElement element) { |
| compiler.test('ResolverTask.computeClassMembers'); |
| super.computeClassMembers(element); |
| } |
| } |
| |
| int checkedResults = 0; |
| |
| Future testExitCode(String marker, String type, int expectedExitCode) { |
| bool testOccurred = false; |
| |
| void onTest(String testMarker, String testType) { |
| if (testMarker == marker && testType == type) { |
| testOccurred = true; |
| } |
| } |
| return new Future(() { |
| Future<api.CompilationResult> compile( |
| Uri script, |
| Uri libraryRoot, |
| Uri packageRoot, |
| api.CompilerInputProvider inputProvider, |
| api.DiagnosticHandler handler, |
| [List<String> options = const [], |
| api.CompilerOutputProvider outputProvider, |
| Map<String, dynamic> environment = const {}]) { |
| libraryRoot = Platform.script.resolve('../../../sdk/'); |
| outputProvider = NullSink.outputProvider; |
| // Use this to silence the test when debugging: |
| // handler = (uri, begin, end, message, kind) {}; |
| Compiler compiler = new TestCompiler(inputProvider, |
| outputProvider, |
| handler, |
| libraryRoot, |
| packageRoot, |
| options, |
| environment, |
| marker, |
| type, |
| onTest); |
| return compiler.run(script).then((bool success) { |
| return new api.CompilationResult(compiler, isSuccess: success); |
| }); |
| } |
| |
| int foundExitCode; |
| |
| checkResult() { |
| Expect.isTrue(testOccurred, 'testExitCode($marker, $type) did not occur'); |
| if (foundExitCode == null) foundExitCode = 0; |
| print('testExitCode($marker, $type) ' |
| 'exitCode=$foundExitCode expected=$expectedExitCode'); |
| Expect.equals(expectedExitCode, foundExitCode, |
| 'testExitCode($marker, $type) ' |
| 'exitCode=$foundExitCode expected=${expectedExitCode}'); |
| checkedResults++; |
| } |
| |
| void exit(exitCode) { |
| if (foundExitCode == null) { |
| foundExitCode = exitCode; |
| } |
| }; |
| |
| entry.exitFunc = exit; |
| entry.compileFunc = compile; |
| |
| Future result = entry.internalMain( |
| ["tests/compiler/dart2js/exit_code_helper.dart"]); |
| return result.catchError((e, s) { |
| // Capture crashes. |
| }).whenComplete(checkResult); |
| }); |
| } |
| |
| Future testExitCodes(String marker, Map<String,int> expectedExitCodes) { |
| return Future.forEach(expectedExitCodes.keys, (String type) { |
| return testExitCode(marker, type, expectedExitCodes[type]); |
| }); |
| } |
| |
| void main() { |
| bool isCheckedMode = false; |
| assert((isCheckedMode = true)); |
| |
| final beforeRun = { |
| '': 0, |
| 'NoSuchMethodError': 253, |
| 'assert': isCheckedMode ? 253 : 0, |
| 'invariant': 253 |
| }; |
| |
| final duringRun = { |
| '': 0, |
| 'NoSuchMethodError': 253, |
| 'assert': isCheckedMode ? 253 : 0, |
| 'invariant': 253, |
| 'warning': 0, |
| 'error': 1, |
| 'internalError': 253, |
| }; |
| |
| final tests = { |
| 'Compiler': beforeRun, |
| 'Compiler.run': beforeRun, |
| 'Compiler.onLibraryScanned': beforeRun, |
| 'Compiler.onLibrariesLoaded': beforeRun, |
| 'ScannerTask.scanElements': duringRun, |
| 'Compiler.withCurrentElement': duringRun, |
| 'Compiler.analyzeElement': duringRun, |
| 'Compiler.codegen': duringRun, |
| 'ResolverTask.computeClassMembers': duringRun, |
| }; |
| |
| asyncStart(); |
| Future.forEach(tests.keys, (marker) { |
| return testExitCodes(marker, tests[marker]); |
| }).then((_) { |
| int countResults(Map runType) { |
| return runType.length * |
| tests.values.where((r) => r == runType).length; |
| } |
| |
| Expect.equals(countResults(beforeRun) + countResults(duringRun), |
| checkedResults); |
| asyncEnd(); |
| }); |
| } |