Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3008)

Side by Side Diff: pkg/analyzer/test/generated/incremental_scanner_test.dart

Issue 746503002: Move incremental scanner to separate file (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add new files Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2014, 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 engine.incremental_scanner_test;
6
7 import 'package:analyzer/src/generated/incremental_scanner.dart';
8 import 'package:analyzer/src/generated/scanner.dart';
9 import 'package:analyzer/src/generated/source.dart';
10 import 'package:unittest/unittest.dart';
11
12 import '../reflective_tests.dart';
13 import 'test_support.dart';
14
15
16 main() {
17 groupSep = ' | ';
18 runReflectiveTests(IncrementalScannerTest);
19 }
20
21 class IncrementalScannerTest extends EngineTestCase {
22 /**
23 * The first token from the token stream resulting from parsing the original
24 * source, or `null` if [scan] has not been invoked.
25 */
26 Token _originalTokens;
27
28 /**
29 * The scanner used to perform incremental scanning, or `null` if [scan] has
30 * not been invoked.
31 */
32 IncrementalScanner _incrementalScanner;
33
34 /**
35 * The first token from the token stream resulting from performing an
36 * incremental scan, or `null` if [scan] has not been invoked.
37 */
38 Token _incrementalTokens;
39
40 void fail_insert_beginning() {
41 // This is currently reporting the changed range as being from 0 to 5, but
42 // that would force us to re-parse both classes, which is clearly
43 // sub-optimal.
44 //
45 // "class B {}"
46 // "class A {} class B {}"
47 _scan("", "", "class A {} ", "class B {}");
48 _assertTokens(-1, 4, ["class", "A", "{", "}", "class", "B", "{", "}"]);
49 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
50 }
51
52 void fail_insert_comment_afterIdentifier() {
53 // "a + b"
54 // "a /* TODO */ + b"
55 _scan("a", "", " /* TODO */", " + b");
56 _assertTokens(0, 1, ["a", "+", "b"]);
57 _assertComments(1, ["/* TODO */"]);
58 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse);
59 }
60
61 void fail_insert_comment_beforeIdentifier() {
62 // "a + b"
63 // "a + /* TODO */ b"
64 _scan("a + ", "", "/* TODO */ ", "b");
65 _assertTokens(1, 2, ["a", "+", "b"]);
66 _assertComments(2, ["/* TODO */"]);
67 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse);
68 }
69
70 void fail_insert_inComment() {
71 // "a /* TO */ b"
72 // "a /* TODO */ b"
73 _scan("a /* TO", "", "DO", " */ b");
74 _assertTokens(0, 1, ["a", "b"]);
75 _assertComments(1, ["/* TODO */"]);
76 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse);
77 }
78
79 void test_delete_identifier_beginning() {
80 // "abs + b;"
81 // "s + b;"
82 _scan("", "ab", "", "s + b;");
83 _assertTokens(-1, 1, ["s", "+", "b", ";"]);
84 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
85 }
86
87 void test_delete_identifier_end() {
88 // "abs + b;"
89 // "a + b;"
90 _scan("a", "bs", "", " + b;");
91 _assertTokens(-1, 1, ["a", "+", "b", ";"]);
92 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
93 }
94
95 void test_delete_identifier_middle() {
96 // "abs + b;"
97 // "as + b;"
98 _scan("a", "b", "", "s + b;");
99 _assertTokens(-1, 1, ["as", "+", "b", ";"]);
100 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
101 }
102
103 void test_delete_mergeTokens() {
104 // "a + b + c;"
105 // "ac;"
106 _scan("a", " + b + ", "", "c;");
107 _assertTokens(-1, 1, ["ac", ";"]);
108 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
109 }
110
111 void test_delete_whitespace() {
112 // "a + b + c;"
113 // "a+ b + c;"
114 _scan("a", " ", "", "+ b + c;");
115 _assertTokens(1, 2, ["a", "+", "b", "+", "c", ";"]);
116 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse);
117 }
118
119 void test_insert_convertOneFunctionToTwo_noOverlap() {
120 // "f() {}"
121 // "f() => 0; g() {}"
122 _scan("f()", "", " => 0; g()", " {}");
123 _assertTokens(
124 2,
125 9,
126 ["f", "(", ")", "=>", "0", ";", "g", "(", ")", "{", "}"]);
127 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
128 }
129
130 void test_insert_convertOneFunctionToTwo_overlap() {
131 // "f() {}"
132 // "f() {} g() {}"
133 _scan("f() {", "", "} g() {", "}");
134 _assertTokens(4, 10, ["f", "(", ")", "{", "}", "g", "(", ")", "{", "}"]);
135 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
136 }
137
138 void test_insert_end() {
139 // "class A {}"
140 // "class A {} class B {}"
141 _scan("class A {}", "", " class B {}", "");
142 _assertTokens(3, 8, ["class", "A", "{", "}", "class", "B", "{", "}"]);
143 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
144 }
145
146 void test_insert_identifierAndPeriod() {
147 // "a + b;"
148 // "a + x.b;"
149 _scan("a + ", "", "x.", "b;");
150 _assertTokens(1, 4, ["a", "+", "x", ".", "b", ";"]);
151 }
152
153 void test_insert_inIdentifier_left_firstToken() {
154 // "a + b;"
155 // "xa + b;"
156 _scan("", "", "x", "a + b;");
157 _assertTokens(-1, 1, ["xa", "+", "b", ";"]);
158 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
159 }
160
161 void test_insert_inIdentifier_left_lastToken() {
162 // "a + b"
163 // "a + xb"
164 _scan("a + ", "", "x", "b");
165 _assertTokens(1, 3, ["a", "+", "xb"]);
166 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
167 }
168
169 void test_insert_inIdentifier_left_middleToken() {
170 // "a + b;"
171 // "a + xb;"
172 _scan("a + ", "", "x", "b;");
173 _assertTokens(1, 3, ["a", "+", "xb", ";"]);
174 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
175 }
176
177 void test_insert_inIdentifier_middle() {
178 // "cat;"
179 // "cart;"
180 _scan("ca", "", "r", "t;");
181 _assertTokens(-1, 1, ["cart", ";"]);
182 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
183 }
184
185 void test_insert_inIdentifier_right_firstToken() {
186 // "a + b;"
187 // "abs + b;"
188 _scan("a", "", "bs", " + b;");
189 _assertTokens(-1, 1, ["abs", "+", "b", ";"]);
190 _assertReplaced(1, "+");
191 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
192 }
193
194 void test_insert_inIdentifier_right_lastToken() {
195 // "a + b"
196 // "a + bc"
197 _scan("a + b", "", "c", "");
198 _assertTokens(1, 3, ["a", "+", "bc"]);
199 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
200 }
201
202 void test_insert_inIdentifier_right_middleToken() {
203 // "a + b;"
204 // "a + by;"
205 _scan("a + b", "", "y", ";");
206 _assertTokens(1, 3, ["a", "+", "by", ";"]);
207 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
208 }
209
210 void test_insert_newIdentifier_noSpaceBefore() {
211 // "a; c;"
212 // "a;b c;"
213 _scan("a;", "", "b", " c;");
214 _assertTokens(1, 3, ["a", ";", "b", "c", ";"]);
215 _assertReplaced(1, ";");
216 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
217 }
218
219 void test_insert_newIdentifier_spaceBefore() {
220 // "a; c;"
221 // "a; b c;"
222 _scan("a; ", "", "b ", "c;");
223 _assertTokens(1, 3, ["a", ";", "b", "c", ";"]);
224 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
225 }
226
227 void test_insert_periodAndIdentifier() {
228 // "a + b;"
229 // "a + b.x;"
230 _scan("a + b", "", ".x", ";");
231 _assertTokens(2, 5, ["a", "+", "b", ".", "x", ";"]);
232 }
233
234 void test_insert_period_afterIdentifier() {
235 // "a + b;"
236 // "a + b.;"
237 _scan("a + b", "", ".", ";");
238 _assertTokens(2, 4, ["a", "+", "b", ".", ";"]);
239 }
240
241 void test_insert_period_betweenIdentifiers_left() {
242 // "a b;"
243 // "a. b;"
244 _scan("a", "", ".", " b;");
245 _assertTokens(0, 2, ["a", ".", "b", ";"]);
246 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
247 }
248
249 void test_insert_period_betweenIdentifiers_middle() {
250 // "a b;"
251 // "a . b;"
252 _scan("a ", "", ".", " b;");
253 _assertTokens(0, 2, ["a", ".", "b", ";"]);
254 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
255 }
256
257 void test_insert_period_betweenIdentifiers_right() {
258 // "a b;"
259 // "a .b;"
260 _scan("a ", "", ".", "b;");
261 _assertTokens(0, 2, ["a", ".", "b", ";"]);
262 }
263
264 void test_insert_period_insideExistingIdentifier() {
265 // "ab;"
266 // "a.b;"
267 _scan("a", "", ".", "b;");
268 _assertTokens(-1, 3, ["a", ".", "b", ";"]);
269 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
270 }
271
272 void test_insert_splitIdentifier() {
273 // "cob;"
274 // "cow.b;"
275 _scan("co", "", "w.", "b;");
276 _assertTokens(-1, 3, ["cow", ".", "b", ";"]);
277 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
278 }
279
280 void test_insert_whitespace_beginning_beforeToken() {
281 // "a + b;"
282 // " a + b;"
283 _scan("", "", " ", "a + b;");
284 _assertTokens(0, 1, ["a", "+", "b", ";"]);
285 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse);
286 }
287
288 void test_insert_whitespace_betweenTokens() {
289 // "a + b;"
290 // "a + b;"
291 _scan("a ", "", " ", "+ b;");
292 _assertTokens(1, 2, ["a", "+", "b", ";"]);
293 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse);
294 }
295
296 void test_insert_whitespace_end_afterToken() {
297 // "a + b;"
298 // "a + b; "
299 _scan("a + b;", "", " ", "");
300 _assertTokens(3, 4, ["a", "+", "b", ";"]);
301 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse);
302 }
303
304 void test_insert_whitespace_end_afterWhitespace() {
305 // "a + b; "
306 // "a + b; "
307 _scan("a + b; ", "", " ", "");
308 _assertTokens(3, 4, ["a", "+", "b", ";"]);
309 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse);
310 }
311
312 void test_insert_whitespace_withMultipleComments() {
313 // "//comment", "//comment2", "a + b;"
314 // "//comment", "//comment2", "a + b;"
315 _scan(r'''
316 //comment
317 //comment2
318 a''', "", " ", " + b;");
319 _assertTokens(1, 2, ["a", "+", "b", ";"]);
320 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse);
321 }
322
323 void test_replace_identifier_beginning() {
324 // "bell + b;"
325 // "fell + b;"
326 _scan("", "b", "f", "ell + b;");
327 _assertTokens(-1, 1, ["fell", "+", "b", ";"]);
328 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
329 }
330
331 void test_replace_identifier_end() {
332 // "bell + b;"
333 // "belt + b;"
334 _scan("bel", "l", "t", " + b;");
335 _assertTokens(-1, 1, ["belt", "+", "b", ";"]);
336 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
337 }
338
339 void test_replace_identifier_middle() {
340 // "first + b;"
341 // "frost + b;"
342 _scan("f", "ir", "ro", "st + b;");
343 _assertTokens(-1, 1, ["frost", "+", "b", ";"]);
344 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
345 }
346
347 void test_replace_multiple_partialFirstAndLast() {
348 // "aa + bb;"
349 // "ab * ab;"
350 _scan("a", "a + b", "b * a", "b;");
351 _assertTokens(-1, 3, ["ab", "*", "ab", ";"]);
352 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
353 }
354
355 void test_replace_operator_oneForMany() {
356 // "a + b;"
357 // "a * c - b;"
358 _scan("a ", "+", "* c -", " b;");
359 _assertTokens(0, 4, ["a", "*", "c", "-", "b", ";"]);
360 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
361 }
362
363 void test_replace_operator_oneForOne() {
364 // "a + b;"
365 // "a * b;"
366 _scan("a ", "+", "*", " b;");
367 _assertTokens(0, 2, ["a", "*", "b", ";"]);
368 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
369 }
370
371 /**
372 * Assert that the comments associated with the token at the given [index]
373 * have lexemes that match the given list of lexemes, both in number and in
374 * content.
375 */
376 void _assertComments(int index, List<String> lexemes) {
377 Token token = _incrementalTokens;
378 for (int i = 0; i < index; i++) {
379 token = token.next;
380 }
381 Token comment = token.precedingComments;
382 if (lexemes.isEmpty) {
383 expect(
384 comment,
385 isNull,
386 reason: "No comments expected but comments found");
387 }
388 int count = 0;
389 for (String lexeme in lexemes) {
390 if (comment == null) {
391 fail("Expected ${lexemes.length} comments but found $count");
392 }
393 expect(comment.lexeme, lexeme);
394 count++;
395 comment = comment.next;
396 }
397 if (comment != null) {
398 while (comment != null) {
399 count++;
400 comment = comment.next;
401 }
402 fail("Expected ${lexemes.length} comments but found $count");
403 }
404 }
405
406 /**
407 * Assert that the token at the given [offset] was replaced with a new token
408 * having the given [lexeme].
409 */
410 void _assertReplaced(int offset, String lexeme) {
411 Token oldToken = _originalTokens;
412 for (int i = 0; i < offset; i++) {
413 oldToken = oldToken.next;
414 }
415 expect(oldToken.lexeme, lexeme);
416 Token newToken = _incrementalScanner.tokenMap.get(oldToken);
417 expect(newToken, isNotNull);
418 expect(newToken.lexeme, lexeme);
419 expect(newToken, isNot(same(oldToken)));
420 }
421
422 /**
423 * Assert that the result of the incremental scan matches the given list of
424 * [lexemes] and that the left and right tokens correspond to the tokens at
425 * the [leftIndex] and [rightIndex].
426 */
427 void _assertTokens(int leftIndex, int rightIndex, List<String> lexemes) {
428 int count = lexemes.length;
429 expect(
430 leftIndex >= -1 && leftIndex < count,
431 isTrue,
432 reason: "Invalid left index");
433 expect(
434 rightIndex >= 0 && rightIndex <= count,
435 isTrue,
436 reason: "Invalid right index");
437 Token leftToken = null;
438 Token rightToken = null;
439 Token token = _incrementalTokens;
440 if (leftIndex < 0) {
441 leftToken = token.previous;
442 }
443 for (int i = 0; i < count; i++) {
444 expect(token.lexeme, lexemes[i]);
445 if (i == leftIndex) {
446 leftToken = token;
447 }
448 if (i == rightIndex) {
449 rightToken = token;
450 }
451 token = token.next;
452 }
453 if (rightIndex >= count) {
454 rightToken = token;
455 }
456 expect(token.type, same(TokenType.EOF), reason: "Too many tokens");
457 if (leftIndex >= 0) {
458 expect(leftToken, isNotNull);
459 }
460 expect(
461 _incrementalScanner.leftToken,
462 same(leftToken),
463 reason: "Invalid left token");
464 if (rightIndex >= 0) {
465 expect(rightToken, isNotNull);
466 }
467 expect(
468 _incrementalScanner.rightToken,
469 same(rightToken),
470 reason: "Invalid right token");
471 }
472
473 /**
474 * Given a description of the original and modified contents, perform an
475 * incremental scan of the two pieces of text. Verify that the incremental
476 * scan produced the same tokens as those that would be produced by a full
477 * scan of the new contents.
478 *
479 * The original content is the concatenation of the [prefix], [removed] and
480 * [suffix] fragments. The modeified content is the concatenation of the
481 * [prefix], [added] and [suffix] fragments.
482 */
483 void _scan(String prefix, String removed, String added, String suffix) {
484 //
485 // Compute the information needed to perform the test.
486 //
487 String originalContents = "$prefix$removed$suffix";
488 String modifiedContents = "$prefix$added$suffix";
489 int replaceStart = prefix.length;
490 Source source = new TestSource();
491 //
492 // Scan the original contents.
493 //
494 GatheringErrorListener originalListener = new GatheringErrorListener();
495 Scanner originalScanner = new Scanner(
496 source,
497 new CharSequenceReader(originalContents),
498 originalListener);
499 _originalTokens = originalScanner.tokenize();
500 expect(_originalTokens, isNotNull);
501 //
502 // Scan the modified contents.
503 //
504 GatheringErrorListener modifiedListener = new GatheringErrorListener();
505 Scanner modifiedScanner = new Scanner(
506 source,
507 new CharSequenceReader(modifiedContents),
508 modifiedListener);
509 Token modifiedTokens = modifiedScanner.tokenize();
510 expect(modifiedTokens, isNotNull);
511 //
512 // Incrementally scan the modified contents.
513 //
514 GatheringErrorListener incrementalListener = new GatheringErrorListener();
515 _incrementalScanner = new IncrementalScanner(
516 source,
517 new CharSequenceReader(modifiedContents),
518 incrementalListener);
519 _incrementalTokens = _incrementalScanner.rescan(
520 _originalTokens,
521 replaceStart,
522 removed.length,
523 added.length);
524 //
525 // Validate that the results of the incremental scan are the same as the
526 // full scan of the modified source.
527 //
528 Token incrementalToken = _incrementalTokens;
529 expect(incrementalToken, isNotNull);
530 while (incrementalToken.type != TokenType.EOF &&
531 modifiedTokens.type != TokenType.EOF) {
532 expect(
533 incrementalToken.type,
534 same(modifiedTokens.type),
535 reason: "Wrong type for token");
536 expect(
537 incrementalToken.offset,
538 modifiedTokens.offset,
539 reason:
540 "Wrong offset for token (${incrementalToken.lexeme} != ${modifiedT okens.lexeme})");
541 expect(
542 incrementalToken.length,
543 modifiedTokens.length,
544 reason:
545 "Wrong length for token (${incrementalToken.lexeme} != ${modifiedT okens.lexeme})");
546 expect(
547 incrementalToken.lexeme,
548 modifiedTokens.lexeme,
549 reason: "Wrong lexeme for token");
550 incrementalToken = incrementalToken.next;
551 modifiedTokens = modifiedTokens.next;
552 }
553 expect(
554 incrementalToken.type,
555 same(TokenType.EOF),
556 reason: "Too many tokens");
557 expect(
558 modifiedTokens.type,
559 same(TokenType.EOF),
560 reason: "Not enough tokens");
561 // TODO(brianwilkerson) Verify that the errors are correct?
562 }
563 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/generated/scanner.dart ('k') | pkg/analyzer/test/generated/parser_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698