| OLD | NEW | 
| (Empty) |  | 
 |    1 // Copyright (c) 2012, 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 // TODO(jmesserly): this was factored out of | 
 |    6 // dart-lang/sdk/tools/testing/dart/multitest.dart | 
 |    7 library dev_compiler.test.tools.multitest; | 
 |    8  | 
 |    9 final validMultitestOutcomes = new Set<String>.from([ | 
 |   10   'ok', | 
 |   11   'compile-time error', | 
 |   12   'runtime error', | 
 |   13   'static type warning', | 
 |   14   'dynamic type error', | 
 |   15   'checked mode compile-time error' | 
 |   16 ]); | 
 |   17  | 
 |   18 // Require at least one non-space character before '///' | 
 |   19 final _multiTestRegExp = new RegExp(r"\S */// \w+:(.*)"); | 
 |   20  | 
 |   21 bool isMultiTest(String contents) => _multiTestRegExp.hasMatch(contents); | 
 |   22  | 
 |   23 // Multitests are Dart test scripts containing lines of the form | 
 |   24 // " [some dart code] /// [key]: [error type]" | 
 |   25 // | 
 |   26 // For each key in the file, a new test file is made containing all | 
 |   27 // the normal lines of the file, and all of the multitest lines containing | 
 |   28 // that key, in the same order as in the source file.  The new test is expected | 
 |   29 // to pass if the error type listed is 'ok', or to fail if there is an error | 
 |   30 // type of type 'compile-time error', 'runtime error', 'static type warning', or | 
 |   31 // 'dynamic type error'.  The type error tests fail only in checked mode. | 
 |   32 // There is also a test created from only the untagged lines of the file, | 
 |   33 // with key "none", which is expected to pass.  This library extracts these | 
 |   34 // tests, writes them into a temporary directory, and passes them to the test | 
 |   35 // runner.  These tests may be referred to in the status files with the | 
 |   36 // pattern [test name]/[key]. | 
 |   37 // | 
 |   38 // For example: file I_am_a_multitest.dart | 
 |   39 //   aaa | 
 |   40 //   bbb /// 02: runtime error | 
 |   41 //   ccc /// 02: continued | 
 |   42 //   ddd /// 07: static type warning | 
 |   43 //   eee /// 10: ok | 
 |   44 //   fff | 
 |   45 // | 
 |   46 // should create four tests: | 
 |   47 // I_am_a_multitest_none.dart | 
 |   48 //   aaa | 
 |   49 //   fff | 
 |   50 // | 
 |   51 // I_am_a_multitest_02.dart | 
 |   52 //   aaa | 
 |   53 //   bbb /// 02: runtime error | 
 |   54 //   ccc /// 02: continued | 
 |   55 //   fff | 
 |   56 // | 
 |   57 // I_am_a_multitest_07.dart | 
 |   58 //   aaa | 
 |   59 //   ddd /// 07: static type warning | 
 |   60 //   fff | 
 |   61 // | 
 |   62 // and I_am_a_multitest_10.dart | 
 |   63 //   aaa | 
 |   64 //   eee /// 10: ok | 
 |   65 //   fff | 
 |   66 // | 
 |   67 // Note that it is possible to indicate more than one acceptable outcome | 
 |   68 // in the case of dynamic and static type warnings | 
 |   69 //   aaa | 
 |   70 //   ddd /// 07: static type warning, dynamic type error | 
 |   71 //   fff | 
 |   72  | 
 |   73 void extractTestsFromMultitest(String filePath, String contents, | 
 |   74     Map<String, String> tests, Map<String, Set<String>> outcomes) { | 
 |   75   int first_newline = contents.indexOf('\n'); | 
 |   76   final String line_separator = (first_newline == 0 || | 
 |   77       contents[first_newline - 1] != '\r') ? '\n' : '\r\n'; | 
 |   78   List<String> lines = contents.split(line_separator); | 
 |   79   if (lines.last == '') lines.removeLast(); | 
 |   80   contents = null; | 
 |   81  | 
 |   82   // Create the set of multitests, which will have a new test added each | 
 |   83   // time we see a multitest line with a new key. | 
 |   84   Map<String, List<String>> testsAsLines = new Map<String, List<String>>(); | 
 |   85  | 
 |   86   // Add the default case with key "none". | 
 |   87   testsAsLines['none'] = new List<String>(); | 
 |   88   outcomes['none'] = new Set<String>(); | 
 |   89  | 
 |   90   int lineCount = 0; | 
 |   91   for (String line in lines) { | 
 |   92     lineCount++; | 
 |   93     var annotation = new _Annotation.from(line); | 
 |   94     if (annotation != null) { | 
 |   95       testsAsLines.putIfAbsent( | 
 |   96           annotation.key, () => new List<String>.from(testsAsLines["none"])); | 
 |   97       // Add line to test with annotation.key as key, empty line to the rest. | 
 |   98       for (var key in testsAsLines.keys) { | 
 |   99         testsAsLines[key].add(annotation.key == key ? line : ""); | 
 |  100       } | 
 |  101       outcomes.putIfAbsent(annotation.key, () => new Set<String>()); | 
 |  102       if (annotation.rest != 'continued') { | 
 |  103         for (String nextOutcome in annotation.outcomesList) { | 
 |  104           if (validMultitestOutcomes.contains(nextOutcome)) { | 
 |  105             outcomes[annotation.key].add(nextOutcome); | 
 |  106           } else { | 
 |  107             print("Warning: Invalid test directive '$nextOutcome' on line " | 
 |  108                 "${lineCount}:\n${annotation.rest} "); | 
 |  109           } | 
 |  110         } | 
 |  111       } | 
 |  112     } else { | 
 |  113       for (var test in testsAsLines.values) test.add(line); | 
 |  114     } | 
 |  115   } | 
 |  116   // End marker, has a final line separator so we don't need to add it after | 
 |  117   // joining the lines. | 
 |  118   var marker = '// Test created from multitest named $filePath.' | 
 |  119       '$line_separator'; | 
 |  120   for (var test in testsAsLines.values) test.add(marker); | 
 |  121  | 
 |  122   var keysToDelete = []; | 
 |  123   // Check that every key (other than the none case) has at least one outcome | 
 |  124   for (var outcomeKey in outcomes.keys) { | 
 |  125     if (outcomeKey != 'none' && outcomes[outcomeKey].isEmpty) { | 
 |  126       print("Warning: Test ${outcomeKey} has no valid annotated outcomes.\n" | 
 |  127           "Expected one of: ${validMultitestOutcomes.toString()}"); | 
 |  128       // If this multitest doesn't have an outcome, mark the multitest for | 
 |  129       // deletion. | 
 |  130       keysToDelete.add(outcomeKey); | 
 |  131     } | 
 |  132   } | 
 |  133   // If a key/multitest was marked for deletion, do the necessary cleanup. | 
 |  134   keysToDelete.forEach(outcomes.remove); | 
 |  135   keysToDelete.forEach(testsAsLines.remove); | 
 |  136  | 
 |  137   // Copy all the tests into the output map tests, as multiline strings. | 
 |  138   for (String key in testsAsLines.keys) { | 
 |  139     tests[key] = testsAsLines[key].join(line_separator); | 
 |  140   } | 
 |  141 } | 
 |  142  | 
 |  143 // Represents a mutlitest annotation in the special /// comment. | 
 |  144 class _Annotation { | 
 |  145   String key; | 
 |  146   String rest; | 
 |  147   List<String> outcomesList; | 
 |  148   _Annotation() {} | 
 |  149   factory _Annotation.from(String line) { | 
 |  150     // Do an early return with "null" if this is not a valid multitest | 
 |  151     // annotation. | 
 |  152     if (!line.contains('///')) { | 
 |  153       return null; | 
 |  154     } | 
 |  155     var parts = line.split('///')[1] | 
 |  156         .split(':') | 
 |  157         .map((s) => s.trim()) | 
 |  158         .where((s) => s.length > 0) | 
 |  159         .toList(); | 
 |  160     if (parts.length <= 1) { | 
 |  161       return null; | 
 |  162     } | 
 |  163  | 
 |  164     var annotation = new _Annotation(); | 
 |  165     annotation.key = parts[0]; | 
 |  166     annotation.rest = parts[1]; | 
 |  167     annotation.outcomesList = | 
 |  168         annotation.rest.split(',').map((s) => s.trim()).toList(); | 
 |  169     return annotation; | 
 |  170   } | 
 |  171 } | 
| OLD | NEW |