| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013, 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 library test_utils; | |
| 6 | |
| 7 import 'package:unittest/unittest.dart'; | |
| 8 | |
| 9 import 'package:analyzer_experimental/src/generated/java_core.dart' show CharSeq
uence; | |
| 10 import 'package:analyzer_experimental/src/generated/engine.dart' show AnalysisCo
ntext, AnalysisContextImpl; | |
| 11 import 'package:analyzer_experimental/src/generated/source.dart'; | |
| 12 import 'package:analyzer_experimental/src/generated/error.dart'; | |
| 13 import 'package:analyzer_experimental/src/generated/scanner.dart'; | |
| 14 import 'package:analyzer_experimental/src/generated/ast.dart'; | |
| 15 import 'package:analyzer_experimental/src/generated/parser.dart'; | |
| 16 | |
| 17 | |
| 18 /// Instances of the class [_GatheringErrorListener] implement an error listener | |
| 19 /// that collects all of the errors passed to it for later examination. | |
| 20 class _GatheringErrorListener implements AnalysisErrorListener { | |
| 21 | |
| 22 /// The source being parsed. | |
| 23 String _rawSource; | |
| 24 | |
| 25 /// The source being parsed after inserting a marker at the beginning and end | |
| 26 /// of the range of the most recent error. | |
| 27 String _markedSource; | |
| 28 | |
| 29 /// A list containing the errors that were collected. | |
| 30 final List<AnalysisError> _errors = new List<AnalysisError>(); | |
| 31 | |
| 32 /// A table mapping sources to the line information for the source. | |
| 33 final Map<Source, LineInfo> _lineInfoMap = new Map<Source, LineInfo>(); | |
| 34 | |
| 35 void onError(AnalysisError error) { | |
| 36 if (_rawSource != null) { | |
| 37 var left = error.offset; | |
| 38 var right = left + error.length - 1; | |
| 39 _markedSource = '${_rawSource.substring(0, left)}^${_rawSource.substring(l
eft, right)}^${_rawSource.substring(right)}'; | |
| 40 } | |
| 41 _errors.add(error); | |
| 42 } | |
| 43 | |
| 44 | |
| 45 /// Sets the line information associated with the given source to the given | |
| 46 /// information. | |
| 47 void setLineInfo(Source source, List<int> lineStarts) { | |
| 48 _lineInfoMap[source] = new LineInfo(lineStarts); | |
| 49 } | |
| 50 | |
| 51 | |
| 52 /// Asserts that the number of errors that have been gathered matches the | |
| 53 /// number of errors that are given and that they have the expected error | |
| 54 /// codes. The order in which the errors were gathered is ignored. | |
| 55 void expectErrors(List<ErrorCode> expectedErrorCodes) { | |
| 56 var builder = new StringBuffer(); | |
| 57 var expectedCounts = new Map<ErrorCode, int>(); | |
| 58 | |
| 59 for (var code in expectedErrorCodes) { | |
| 60 var count = expectedCounts[code]; | |
| 61 if (count == null) { | |
| 62 count = 1; | |
| 63 } else { | |
| 64 count = count + 1; | |
| 65 } | |
| 66 expectedCounts[code] = count; | |
| 67 } | |
| 68 | |
| 69 var errorsByCode = new Map<ErrorCode, List<AnalysisError>>(); | |
| 70 for (var error in _errors) { | |
| 71 var code = error.errorCode; | |
| 72 var list = errorsByCode[code]; | |
| 73 if (list == null) { | |
| 74 list = new List<AnalysisError>(); | |
| 75 errorsByCode[code] = list; | |
| 76 } | |
| 77 list.add(error); | |
| 78 } | |
| 79 | |
| 80 for (var entry in _getMapEntrySet(expectedCounts)) { | |
| 81 var code = entry.getKey(); | |
| 82 var expectedCount = entry.getValue(); | |
| 83 var actualCount; | |
| 84 | |
| 85 var list = errorsByCode.remove(code); | |
| 86 if (list == null) { | |
| 87 actualCount = 0; | |
| 88 } else { | |
| 89 actualCount = list.length; | |
| 90 } | |
| 91 | |
| 92 if (actualCount != expectedCount) { | |
| 93 if (builder.length == 0) { | |
| 94 builder.write('Expected '); | |
| 95 } else { | |
| 96 builder.write('; '); | |
| 97 } | |
| 98 builder.write(expectedCount); | |
| 99 builder.write(' errors of type '); | |
| 100 builder.write(code); | |
| 101 builder.write(', found '); | |
| 102 builder.write(actualCount); | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 for (var entry in _getMapEntrySet(errorsByCode)) { | |
| 107 var code = entry.getKey(); | |
| 108 var actualErrors = entry.getValue(); | |
| 109 var actualCount = actualErrors.length; | |
| 110 | |
| 111 if (builder.length == 0) { | |
| 112 builder.write('Expected '); | |
| 113 } else { | |
| 114 builder.write('; '); | |
| 115 } | |
| 116 | |
| 117 builder.write('0 errors of type '); | |
| 118 builder.write(code); | |
| 119 builder.write(', found '); | |
| 120 builder.write(actualCount); | |
| 121 builder.write(' ('); | |
| 122 | |
| 123 for (int i = 0; i < actualErrors.length; i++) { | |
| 124 var error = actualErrors[i]; | |
| 125 if (i > 0) { | |
| 126 builder.write(', '); | |
| 127 } | |
| 128 builder.write(error.offset); | |
| 129 } | |
| 130 | |
| 131 builder.write(')'); | |
| 132 } | |
| 133 | |
| 134 if (builder.length > 0) { | |
| 135 fail(builder.toString()); | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 } | |
| 140 | |
| 141 | |
| 142 Set<_MapEntry> _getMapEntrySet(Map m) { | |
| 143 var result = new Set(); | |
| 144 m.forEach((k, v) { | |
| 145 result.add(new _MapEntry(k, v)); | |
| 146 }); | |
| 147 return result; | |
| 148 } | |
| 149 | |
| 150 | |
| 151 class _MapEntry<K, V> { | |
| 152 K _key; | |
| 153 V _value; | |
| 154 _MapEntry(this._key, this._value); | |
| 155 K getKey() => _key; | |
| 156 V getValue() => _value; | |
| 157 } | |
| 158 | |
| 159 | |
| 160 class _TestSource implements Source { | |
| 161 | |
| 162 bool operator == (Object object) => object is _TestSource; | |
| 163 | |
| 164 AnalysisContext get context => _unsupported(); | |
| 165 | |
| 166 void getContents(Source_ContentReceiver receiver) => _unsupported(); | |
| 167 | |
| 168 String get fullName => _unsupported(); | |
| 169 | |
| 170 String get shortName => _unsupported(); | |
| 171 | |
| 172 String get encoding => _unsupported(); | |
| 173 | |
| 174 int get modificationStamp =>_unsupported(); | |
| 175 | |
| 176 UriKind get uriKind => _unsupported(); | |
| 177 | |
| 178 bool exists() => true; | |
| 179 | |
| 180 bool get isInSystemLibrary => _unsupported(); | |
| 181 | |
| 182 Source resolve(String uri) => _unsupported(); | |
| 183 | |
| 184 Source resolveRelative(Uri uri) => _unsupported(); | |
| 185 | |
| 186 } | |
| 187 | |
| 188 | |
| 189 _unsupported() => throw new _UnsupportedOperationException(); | |
| 190 | |
| 191 class _UnsupportedOperationException implements Exception { | |
| 192 String toString() => 'UnsupportedOperationException'; | |
| 193 } | |
| 194 | |
| 195 | |
| 196 /// Parse the given [source] as a statement and assert, if provided, that | |
| 197 /// exactly a given set of [expectedErrorCodes] are encountered. | |
| 198 Statement parseStatement(String source, [List<ErrorCode> expectedErrorCodes]) { | |
| 199 | |
| 200 var listener = new _GatheringErrorListener(); | |
| 201 var reader = new CharSequenceReader(new CharSequence(source)); | |
| 202 var scanner = new Scanner(null, reader, listener); | |
| 203 listener.setLineInfo(new _TestSource(), scanner.lineStarts); | |
| 204 | |
| 205 var token = scanner.tokenize(); | |
| 206 var parser = new Parser(null, listener); | |
| 207 var statement = parser.parseStatement(token); | |
| 208 expect(statement, isNotNull); | |
| 209 | |
| 210 if (expectedErrorCodes != null) { | |
| 211 listener.expectErrors(expectedErrorCodes); | |
| 212 } | |
| 213 | |
| 214 return statement; | |
| 215 } | |
| OLD | NEW |