| Index: tests/compiler/dart2js/cps_ir/runner.dart | 
| diff --git a/tests/compiler/dart2js/cps_ir/runner.dart b/tests/compiler/dart2js/cps_ir/runner.dart | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..b4ecb6fb01d330f8772282120069eb43b46823e1 | 
| --- /dev/null | 
| +++ b/tests/compiler/dart2js/cps_ir/runner.dart | 
| @@ -0,0 +1,130 @@ | 
| +// Copyright (c) 2016, 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 that the CPS IR code generator compiles programs and produces the | 
| +// the expected output. | 
| + | 
| +import 'dart:io'; | 
| + | 
| +import 'package:async_helper/async_helper.dart'; | 
| +import 'package:expect/expect.dart'; | 
| +import 'package:compiler/src/apiimpl.dart' show | 
| +    CompilerImpl; | 
| +import '../memory_compiler.dart'; | 
| +import 'package:compiler/src/js/js.dart' as js; | 
| +import 'package:compiler/src/elements/elements.dart' show | 
| +    ClassElement, | 
| +    Element; | 
| + | 
| +// Regular experession used to extract the method name that is used to match the | 
| +// test output. By default we match the output of main. | 
| +final RegExp elementNameRegExp = new RegExp(r'^// Method to test: (.*)$', | 
| +    multiLine: true); | 
| + | 
| +runTest(String filename, {bool update: false}) { | 
| +  var outputname = filename.replaceFirst('.dart', '.js'); | 
| +  String source = new File.fromUri(Platform.script.resolve('input/$filename')) | 
| +      .readAsStringSync(); | 
| +  var expectedFile = | 
| +      new File.fromUri(Platform.script.resolve('expected/$outputname')); | 
| +  String expected = expectedFile.existsSync() | 
| +    ? expectedFile.readAsStringSync() : ''; | 
| +  var match = elementNameRegExp.firstMatch(source); | 
| +  var elementName = match?.group(1); | 
| + | 
| +  Map files = {TEST_MAIN_FILE: source}; | 
| +  asyncTest(() async { | 
| +    Uri uri = Uri.parse('memory:$TEST_MAIN_FILE'); | 
| +    String found = null; | 
| +    try { | 
| +      CompilationResult result = await runCompiler( | 
| +          entryPoint: uri, | 
| +          memorySourceFiles: files, | 
| +          options: <String>['--use-cps-ir']); | 
| +      Expect.isTrue(result.isSuccess); | 
| +      CompilerImpl compiler = result.compiler; | 
| +      if (expected != null) { | 
| +        String output = elementName == null | 
| +            ? _getCodeForMain(compiler) | 
| +            : _getCodeForMethod(compiler, elementName); | 
| +        // Include the input in a comment of the expected file to make it easier | 
| +        // to see the relation between input and output in code reviews. | 
| +        found = '// Expectation for test: \n' | 
| +            '// ${source.trim().replaceAll('\n', '\n// ')}\n\n' | 
| +            '$output\n'; | 
| +      } | 
| +    } catch (e, st) { | 
| +      print(e); | 
| +      print(st); | 
| +      var message = 'The following test failed to compile:\n' | 
| +                    '${_formatTest(files)}'; | 
| +      if (update) { | 
| +        print('\n\n$message\n'); | 
| +        return; | 
| +      } else { | 
| +        Expect.fail(message); | 
| +      } | 
| +    } | 
| +    if (expected != found) { | 
| +      if (update) { | 
| +        expectedFile.writeAsStringSync(found); | 
| +        print('INFO: $expectedFile was updated'); | 
| +      } else { | 
| +        Expect.fail('Unexpected output for test:\n  ' | 
| +            '${_formatTest(files).replaceAll('\n', '\n  ')}\n' | 
| +            'Expected:\n  ${expected.replaceAll('\n', '\n  ')}\n' | 
| +            'but found:\n  ${found?.replaceAll('\n', '\n  ')}\n' | 
| +            '$regenerateCommand'); | 
| +      } | 
| +    } | 
| +  }); | 
| +} | 
| + | 
| +String get regenerateCommand { | 
| +  var flags = Platform.packageRoot == null | 
| +    ? '' : '--package-root=${Platform.packageRoot} '; | 
| +  return ''' | 
| +${const bool.fromEnvironment('woohoo')} | 
| +To update the test expectations, rerun this test passing "update" as an | 
| +argument, as follows: | 
| + | 
| +  dart $flags${Platform.script} update | 
| + | 
| +To update more than one test at once, run: | 
| +  dart $flags${Platform.script.resolve('update_all.dart')} | 
| + | 
| +'''; | 
| +} | 
| + | 
| +const String TEST_MAIN_FILE = 'test.dart'; | 
| + | 
| +String _formatTest(Map test) { | 
| +  return test[TEST_MAIN_FILE]; | 
| +} | 
| + | 
| +String _getCodeForMain(CompilerImpl compiler) { | 
| +  Element mainFunction = compiler.mainFunction; | 
| +  js.Node ast = compiler.enqueuer.codegen.generatedCode[mainFunction]; | 
| +  return js.prettyPrint(ast, compiler).getText(); | 
| +} | 
| + | 
| +String _getCodeForMethod(CompilerImpl compiler, | 
| +                        String name) { | 
| +  Element foundElement; | 
| +  for (Element element in compiler.enqueuer.codegen.generatedCode.keys) { | 
| +    if (element.toString() == name) { | 
| +      if (foundElement != null) { | 
| +        Expect.fail('Multiple compiled elements are called $name'); | 
| +      } | 
| +      foundElement = element; | 
| +    } | 
| +  } | 
| + | 
| +  if (foundElement == null) { | 
| +    Expect.fail('There is no compiled element called $name'); | 
| +  } | 
| + | 
| +  js.Node ast = compiler.enqueuer.codegen.generatedCode[foundElement]; | 
| +  return js.prettyPrint(ast, compiler).getText(); | 
| +} | 
|  |