| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // This code was auto-generated, is not intended to be edited, and is subject to | |
| 6 // significant change. Please see the README file for more information. | |
| 7 | |
| 8 library engine.scanner_test; | 5 library engine.scanner_test; |
| 9 | 6 |
| 10 import 'package:analyzer/src/generated/error.dart'; | 7 import 'package:analyzer/src/generated/error.dart'; |
| 11 import 'package:analyzer/src/generated/scanner.dart'; | 8 import 'package:analyzer/src/generated/scanner.dart'; |
| 12 import 'package:analyzer/src/generated/source.dart'; | 9 import 'package:analyzer/src/generated/source.dart'; |
| 13 import 'package:analyzer/src/generated/utilities_collection.dart' show TokenMap; | |
| 14 import 'package:unittest/unittest.dart'; | 10 import 'package:unittest/unittest.dart'; |
| 15 | 11 |
| 16 import '../reflective_tests.dart'; | 12 import '../reflective_tests.dart'; |
| 17 import 'test_support.dart'; | 13 import 'test_support.dart'; |
| 18 | 14 |
| 19 | |
| 20 main() { | 15 main() { |
| 21 groupSep = ' | '; | 16 groupSep = ' | '; |
| 22 runReflectiveTests(CharSequenceReaderTest); | 17 runReflectiveTests(CharSequenceReaderTest); |
| 23 runReflectiveTests(IncrementalScannerTest); | |
| 24 runReflectiveTests(KeywordStateTest); | 18 runReflectiveTests(KeywordStateTest); |
| 25 runReflectiveTests(ScannerTest); | 19 runReflectiveTests(ScannerTest); |
| 26 runReflectiveTests(TokenTypeTest); | 20 runReflectiveTests(TokenTypeTest); |
| 27 } | 21 } |
| 28 | 22 |
| 29 class CharSequenceReaderTest { | 23 class CharSequenceReaderTest { |
| 30 void test_advance() { | 24 void test_advance() { |
| 31 CharSequenceReader reader = new CharSequenceReader("x"); | 25 CharSequenceReader reader = new CharSequenceReader("x"); |
| 32 expect(reader.advance(), 0x78); | 26 expect(reader.advance(), 0x78); |
| 33 expect(reader.advance(), -1); | 27 expect(reader.advance(), -1); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 } | 116 } |
| 123 | 117 |
| 124 void test_setOffset() { | 118 void test_setOffset() { |
| 125 CharSequenceReader baseReader = new CharSequenceReader("xyzzy"); | 119 CharSequenceReader baseReader = new CharSequenceReader("xyzzy"); |
| 126 CharacterRangeReader reader = new CharacterRangeReader(baseReader, 1, 4); | 120 CharacterRangeReader reader = new CharacterRangeReader(baseReader, 1, 4); |
| 127 reader.offset = 2; | 121 reader.offset = 2; |
| 128 expect(reader.offset, 2); | 122 expect(reader.offset, 2); |
| 129 } | 123 } |
| 130 } | 124 } |
| 131 | 125 |
| 132 class IncrementalScannerTest extends EngineTestCase { | |
| 133 /** | |
| 134 * The first token from the token stream resulting from parsing the original | |
| 135 * source, or `null` if [scan] has not been invoked. | |
| 136 */ | |
| 137 Token _originalTokens; | |
| 138 | |
| 139 /** | |
| 140 * The scanner used to perform incremental scanning, or `null` if [scan] has | |
| 141 * not been invoked. | |
| 142 */ | |
| 143 IncrementalScanner _incrementalScanner; | |
| 144 | |
| 145 /** | |
| 146 * The first token from the token stream resulting from performing an | |
| 147 * incremental scan, or `null` if [scan] has not been invoked. | |
| 148 */ | |
| 149 Token _incrementalTokens; | |
| 150 | |
| 151 void fail_insert_beginning() { | |
| 152 // This is currently reporting the changed range as being from 0 to 5, but | |
| 153 // that would force us to re-parse both classes, which is clearly | |
| 154 // sub-optimal. | |
| 155 // | |
| 156 // "class B {}" | |
| 157 // "class A {} class B {}" | |
| 158 _scan("", "", "class A {} ", "class B {}"); | |
| 159 _assertTokens(-1, 4, ["class", "A", "{", "}", "class", "B", "{", "}"]); | |
| 160 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 161 } | |
| 162 | |
| 163 void fail_insert_comment_afterIdentifier() { | |
| 164 // "a + b" | |
| 165 // "a /* TODO */ + b" | |
| 166 _scan("a", "", " /* TODO */", " + b"); | |
| 167 _assertTokens(0, 1, ["a", "+", "b"]); | |
| 168 _assertComments(1, ["/* TODO */"]); | |
| 169 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse); | |
| 170 } | |
| 171 | |
| 172 void fail_insert_comment_beforeIdentifier() { | |
| 173 // "a + b" | |
| 174 // "a + /* TODO */ b" | |
| 175 _scan("a + ", "", "/* TODO */ ", "b"); | |
| 176 _assertTokens(1, 2, ["a", "+", "b"]); | |
| 177 _assertComments(2, ["/* TODO */"]); | |
| 178 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse); | |
| 179 } | |
| 180 | |
| 181 void fail_insert_inComment() { | |
| 182 // "a /* TO */ b" | |
| 183 // "a /* TODO */ b" | |
| 184 _scan("a /* TO", "", "DO", " */ b"); | |
| 185 _assertTokens(0, 1, ["a", "b"]); | |
| 186 _assertComments(1, ["/* TODO */"]); | |
| 187 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse); | |
| 188 } | |
| 189 | |
| 190 void test_delete_identifier_beginning() { | |
| 191 // "abs + b;" | |
| 192 // "s + b;" | |
| 193 _scan("", "ab", "", "s + b;"); | |
| 194 _assertTokens(-1, 1, ["s", "+", "b", ";"]); | |
| 195 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 196 } | |
| 197 | |
| 198 void test_delete_identifier_end() { | |
| 199 // "abs + b;" | |
| 200 // "a + b;" | |
| 201 _scan("a", "bs", "", " + b;"); | |
| 202 _assertTokens(-1, 1, ["a", "+", "b", ";"]); | |
| 203 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 204 } | |
| 205 | |
| 206 void test_delete_identifier_middle() { | |
| 207 // "abs + b;" | |
| 208 // "as + b;" | |
| 209 _scan("a", "b", "", "s + b;"); | |
| 210 _assertTokens(-1, 1, ["as", "+", "b", ";"]); | |
| 211 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 212 } | |
| 213 | |
| 214 void test_delete_mergeTokens() { | |
| 215 // "a + b + c;" | |
| 216 // "ac;" | |
| 217 _scan("a", " + b + ", "", "c;"); | |
| 218 _assertTokens(-1, 1, ["ac", ";"]); | |
| 219 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 220 } | |
| 221 | |
| 222 void test_delete_whitespace() { | |
| 223 // "a + b + c;" | |
| 224 // "a+ b + c;" | |
| 225 _scan("a", " ", "", "+ b + c;"); | |
| 226 _assertTokens(1, 2, ["a", "+", "b", "+", "c", ";"]); | |
| 227 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse); | |
| 228 } | |
| 229 | |
| 230 void test_insert_convertOneFunctionToTwo_noOverlap() { | |
| 231 // "f() {}" | |
| 232 // "f() => 0; g() {}" | |
| 233 _scan("f()", "", " => 0; g()", " {}"); | |
| 234 _assertTokens( | |
| 235 2, | |
| 236 9, | |
| 237 ["f", "(", ")", "=>", "0", ";", "g", "(", ")", "{", "}"]); | |
| 238 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 239 } | |
| 240 | |
| 241 void test_insert_convertOneFunctionToTwo_overlap() { | |
| 242 // "f() {}" | |
| 243 // "f() {} g() {}" | |
| 244 _scan("f() {", "", "} g() {", "}"); | |
| 245 _assertTokens(4, 10, ["f", "(", ")", "{", "}", "g", "(", ")", "{", "}"]); | |
| 246 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 247 } | |
| 248 | |
| 249 void test_insert_end() { | |
| 250 // "class A {}" | |
| 251 // "class A {} class B {}" | |
| 252 _scan("class A {}", "", " class B {}", ""); | |
| 253 _assertTokens(3, 8, ["class", "A", "{", "}", "class", "B", "{", "}"]); | |
| 254 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 255 } | |
| 256 | |
| 257 void test_insert_identifierAndPeriod() { | |
| 258 // "a + b;" | |
| 259 // "a + x.b;" | |
| 260 _scan("a + ", "", "x.", "b;"); | |
| 261 _assertTokens(1, 4, ["a", "+", "x", ".", "b", ";"]); | |
| 262 } | |
| 263 | |
| 264 void test_insert_inIdentifier_left_firstToken() { | |
| 265 // "a + b;" | |
| 266 // "xa + b;" | |
| 267 _scan("", "", "x", "a + b;"); | |
| 268 _assertTokens(-1, 1, ["xa", "+", "b", ";"]); | |
| 269 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 270 } | |
| 271 | |
| 272 void test_insert_inIdentifier_left_lastToken() { | |
| 273 // "a + b" | |
| 274 // "a + xb" | |
| 275 _scan("a + ", "", "x", "b"); | |
| 276 _assertTokens(1, 3, ["a", "+", "xb"]); | |
| 277 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 278 } | |
| 279 | |
| 280 void test_insert_inIdentifier_left_middleToken() { | |
| 281 // "a + b;" | |
| 282 // "a + xb;" | |
| 283 _scan("a + ", "", "x", "b;"); | |
| 284 _assertTokens(1, 3, ["a", "+", "xb", ";"]); | |
| 285 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 286 } | |
| 287 | |
| 288 void test_insert_inIdentifier_middle() { | |
| 289 // "cat;" | |
| 290 // "cart;" | |
| 291 _scan("ca", "", "r", "t;"); | |
| 292 _assertTokens(-1, 1, ["cart", ";"]); | |
| 293 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 294 } | |
| 295 | |
| 296 void test_insert_inIdentifier_right_firstToken() { | |
| 297 // "a + b;" | |
| 298 // "abs + b;" | |
| 299 _scan("a", "", "bs", " + b;"); | |
| 300 _assertTokens(-1, 1, ["abs", "+", "b", ";"]); | |
| 301 _assertReplaced(1, "+"); | |
| 302 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 303 } | |
| 304 | |
| 305 void test_insert_inIdentifier_right_lastToken() { | |
| 306 // "a + b" | |
| 307 // "a + bc" | |
| 308 _scan("a + b", "", "c", ""); | |
| 309 _assertTokens(1, 3, ["a", "+", "bc"]); | |
| 310 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 311 } | |
| 312 | |
| 313 void test_insert_inIdentifier_right_middleToken() { | |
| 314 // "a + b;" | |
| 315 // "a + by;" | |
| 316 _scan("a + b", "", "y", ";"); | |
| 317 _assertTokens(1, 3, ["a", "+", "by", ";"]); | |
| 318 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 319 } | |
| 320 | |
| 321 void test_insert_newIdentifier_noSpaceBefore() { | |
| 322 // "a; c;" | |
| 323 // "a;b c;" | |
| 324 _scan("a;", "", "b", " c;"); | |
| 325 _assertTokens(1, 3, ["a", ";", "b", "c", ";"]); | |
| 326 _assertReplaced(1, ";"); | |
| 327 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 328 } | |
| 329 | |
| 330 void test_insert_newIdentifier_spaceBefore() { | |
| 331 // "a; c;" | |
| 332 // "a; b c;" | |
| 333 _scan("a; ", "", "b ", "c;"); | |
| 334 _assertTokens(1, 3, ["a", ";", "b", "c", ";"]); | |
| 335 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 336 } | |
| 337 | |
| 338 void test_insert_periodAndIdentifier() { | |
| 339 // "a + b;" | |
| 340 // "a + b.x;" | |
| 341 _scan("a + b", "", ".x", ";"); | |
| 342 _assertTokens(2, 5, ["a", "+", "b", ".", "x", ";"]); | |
| 343 } | |
| 344 | |
| 345 void test_insert_period_afterIdentifier() { | |
| 346 // "a + b;" | |
| 347 // "a + b.;" | |
| 348 _scan("a + b", "", ".", ";"); | |
| 349 _assertTokens(2, 4, ["a", "+", "b", ".", ";"]); | |
| 350 } | |
| 351 | |
| 352 void test_insert_period_betweenIdentifiers_left() { | |
| 353 // "a b;" | |
| 354 // "a. b;" | |
| 355 _scan("a", "", ".", " b;"); | |
| 356 _assertTokens(0, 2, ["a", ".", "b", ";"]); | |
| 357 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 358 } | |
| 359 | |
| 360 void test_insert_period_betweenIdentifiers_middle() { | |
| 361 // "a b;" | |
| 362 // "a . b;" | |
| 363 _scan("a ", "", ".", " b;"); | |
| 364 _assertTokens(0, 2, ["a", ".", "b", ";"]); | |
| 365 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 366 } | |
| 367 | |
| 368 void test_insert_period_betweenIdentifiers_right() { | |
| 369 // "a b;" | |
| 370 // "a .b;" | |
| 371 _scan("a ", "", ".", "b;"); | |
| 372 _assertTokens(0, 2, ["a", ".", "b", ";"]); | |
| 373 } | |
| 374 | |
| 375 void test_insert_period_insideExistingIdentifier() { | |
| 376 // "ab;" | |
| 377 // "a.b;" | |
| 378 _scan("a", "", ".", "b;"); | |
| 379 _assertTokens(-1, 3, ["a", ".", "b", ";"]); | |
| 380 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 381 } | |
| 382 | |
| 383 void test_insert_splitIdentifier() { | |
| 384 // "cob;" | |
| 385 // "cow.b;" | |
| 386 _scan("co", "", "w.", "b;"); | |
| 387 _assertTokens(-1, 3, ["cow", ".", "b", ";"]); | |
| 388 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 389 } | |
| 390 | |
| 391 void test_insert_whitespace_beginning_beforeToken() { | |
| 392 // "a + b;" | |
| 393 // " a + b;" | |
| 394 _scan("", "", " ", "a + b;"); | |
| 395 _assertTokens(0, 1, ["a", "+", "b", ";"]); | |
| 396 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse); | |
| 397 } | |
| 398 | |
| 399 void test_insert_whitespace_betweenTokens() { | |
| 400 // "a + b;" | |
| 401 // "a + b;" | |
| 402 _scan("a ", "", " ", "+ b;"); | |
| 403 _assertTokens(1, 2, ["a", "+", "b", ";"]); | |
| 404 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse); | |
| 405 } | |
| 406 | |
| 407 void test_insert_whitespace_end_afterToken() { | |
| 408 // "a + b;" | |
| 409 // "a + b; " | |
| 410 _scan("a + b;", "", " ", ""); | |
| 411 _assertTokens(3, 4, ["a", "+", "b", ";"]); | |
| 412 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse); | |
| 413 } | |
| 414 | |
| 415 void test_insert_whitespace_end_afterWhitespace() { | |
| 416 // "a + b; " | |
| 417 // "a + b; " | |
| 418 _scan("a + b; ", "", " ", ""); | |
| 419 _assertTokens(3, 4, ["a", "+", "b", ";"]); | |
| 420 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse); | |
| 421 } | |
| 422 | |
| 423 void test_insert_whitespace_withMultipleComments() { | |
| 424 // "//comment", "//comment2", "a + b;" | |
| 425 // "//comment", "//comment2", "a + b;" | |
| 426 _scan(r''' | |
| 427 //comment | |
| 428 //comment2 | |
| 429 a''', "", " ", " + b;"); | |
| 430 _assertTokens(1, 2, ["a", "+", "b", ";"]); | |
| 431 expect(_incrementalScanner.hasNonWhitespaceChange, isFalse); | |
| 432 } | |
| 433 | |
| 434 void test_replace_identifier_beginning() { | |
| 435 // "bell + b;" | |
| 436 // "fell + b;" | |
| 437 _scan("", "b", "f", "ell + b;"); | |
| 438 _assertTokens(-1, 1, ["fell", "+", "b", ";"]); | |
| 439 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 440 } | |
| 441 | |
| 442 void test_replace_identifier_end() { | |
| 443 // "bell + b;" | |
| 444 // "belt + b;" | |
| 445 _scan("bel", "l", "t", " + b;"); | |
| 446 _assertTokens(-1, 1, ["belt", "+", "b", ";"]); | |
| 447 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 448 } | |
| 449 | |
| 450 void test_replace_identifier_middle() { | |
| 451 // "first + b;" | |
| 452 // "frost + b;" | |
| 453 _scan("f", "ir", "ro", "st + b;"); | |
| 454 _assertTokens(-1, 1, ["frost", "+", "b", ";"]); | |
| 455 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 456 } | |
| 457 | |
| 458 void test_replace_multiple_partialFirstAndLast() { | |
| 459 // "aa + bb;" | |
| 460 // "ab * ab;" | |
| 461 _scan("a", "a + b", "b * a", "b;"); | |
| 462 _assertTokens(-1, 3, ["ab", "*", "ab", ";"]); | |
| 463 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 464 } | |
| 465 | |
| 466 void test_replace_operator_oneForMany() { | |
| 467 // "a + b;" | |
| 468 // "a * c - b;" | |
| 469 _scan("a ", "+", "* c -", " b;"); | |
| 470 _assertTokens(0, 4, ["a", "*", "c", "-", "b", ";"]); | |
| 471 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 472 } | |
| 473 | |
| 474 void test_replace_operator_oneForOne() { | |
| 475 // "a + b;" | |
| 476 // "a * b;" | |
| 477 _scan("a ", "+", "*", " b;"); | |
| 478 _assertTokens(0, 2, ["a", "*", "b", ";"]); | |
| 479 expect(_incrementalScanner.hasNonWhitespaceChange, isTrue); | |
| 480 } | |
| 481 | |
| 482 /** | |
| 483 * Assert that the comments associated with the token at the given [index] | |
| 484 * have lexemes that match the given list of lexemes, both in number and in | |
| 485 * content. | |
| 486 */ | |
| 487 void _assertComments(int index, List<String> lexemes) { | |
| 488 Token token = _incrementalTokens; | |
| 489 for (int i = 0; i < index; i++) { | |
| 490 token = token.next; | |
| 491 } | |
| 492 Token comment = token.precedingComments; | |
| 493 if (lexemes.isEmpty) { | |
| 494 expect( | |
| 495 comment, | |
| 496 isNull, | |
| 497 reason: "No comments expected but comments found"); | |
| 498 } | |
| 499 int count = 0; | |
| 500 for (String lexeme in lexemes) { | |
| 501 if (comment == null) { | |
| 502 fail("Expected ${lexemes.length} comments but found $count"); | |
| 503 } | |
| 504 expect(comment.lexeme, lexeme); | |
| 505 count++; | |
| 506 comment = comment.next; | |
| 507 } | |
| 508 if (comment != null) { | |
| 509 while (comment != null) { | |
| 510 count++; | |
| 511 comment = comment.next; | |
| 512 } | |
| 513 fail("Expected ${lexemes.length} comments but found $count"); | |
| 514 } | |
| 515 } | |
| 516 | |
| 517 /** | |
| 518 * Assert that the token at the given [offset] was replaced with a new token | |
| 519 * having the given [lexeme]. | |
| 520 */ | |
| 521 void _assertReplaced(int offset, String lexeme) { | |
| 522 Token oldToken = _originalTokens; | |
| 523 for (int i = 0; i < offset; i++) { | |
| 524 oldToken = oldToken.next; | |
| 525 } | |
| 526 expect(oldToken.lexeme, lexeme); | |
| 527 Token newToken = _incrementalScanner.tokenMap.get(oldToken); | |
| 528 expect(newToken, isNotNull); | |
| 529 expect(newToken.lexeme, lexeme); | |
| 530 expect(newToken, isNot(same(oldToken))); | |
| 531 } | |
| 532 | |
| 533 /** | |
| 534 * Assert that the result of the incremental scan matches the given list of | |
| 535 * [lexemes] and that the left and right tokens correspond to the tokens at | |
| 536 * the [leftIndex] and [rightIndex]. | |
| 537 */ | |
| 538 void _assertTokens(int leftIndex, int rightIndex, List<String> lexemes) { | |
| 539 int count = lexemes.length; | |
| 540 expect( | |
| 541 leftIndex >= -1 && leftIndex < count, | |
| 542 isTrue, | |
| 543 reason: "Invalid left index"); | |
| 544 expect( | |
| 545 rightIndex >= 0 && rightIndex <= count, | |
| 546 isTrue, | |
| 547 reason: "Invalid right index"); | |
| 548 Token leftToken = null; | |
| 549 Token rightToken = null; | |
| 550 Token token = _incrementalTokens; | |
| 551 if (leftIndex < 0) { | |
| 552 leftToken = token.previous; | |
| 553 } | |
| 554 for (int i = 0; i < count; i++) { | |
| 555 expect(token.lexeme, lexemes[i]); | |
| 556 if (i == leftIndex) { | |
| 557 leftToken = token; | |
| 558 } | |
| 559 if (i == rightIndex) { | |
| 560 rightToken = token; | |
| 561 } | |
| 562 token = token.next; | |
| 563 } | |
| 564 if (rightIndex >= count) { | |
| 565 rightToken = token; | |
| 566 } | |
| 567 expect(token.type, same(TokenType.EOF), reason: "Too many tokens"); | |
| 568 if (leftIndex >= 0) { | |
| 569 expect(leftToken, isNotNull); | |
| 570 } | |
| 571 expect( | |
| 572 _incrementalScanner.leftToken, | |
| 573 same(leftToken), | |
| 574 reason: "Invalid left token"); | |
| 575 if (rightIndex >= 0) { | |
| 576 expect(rightToken, isNotNull); | |
| 577 } | |
| 578 expect( | |
| 579 _incrementalScanner.rightToken, | |
| 580 same(rightToken), | |
| 581 reason: "Invalid right token"); | |
| 582 } | |
| 583 | |
| 584 /** | |
| 585 * Given a description of the original and modified contents, perform an | |
| 586 * incremental scan of the two pieces of text. Verify that the incremental | |
| 587 * scan produced the same tokens as those that would be produced by a full | |
| 588 * scan of the new contents. | |
| 589 * | |
| 590 * The original content is the concatenation of the [prefix], [removed] and | |
| 591 * [suffix] fragments. The modeified content is the concatenation of the | |
| 592 * [prefix], [added] and [suffix] fragments. | |
| 593 */ | |
| 594 void _scan(String prefix, String removed, String added, String suffix) { | |
| 595 // | |
| 596 // Compute the information needed to perform the test. | |
| 597 // | |
| 598 String originalContents = "$prefix$removed$suffix"; | |
| 599 String modifiedContents = "$prefix$added$suffix"; | |
| 600 int replaceStart = prefix.length; | |
| 601 Source source = new TestSource(); | |
| 602 // | |
| 603 // Scan the original contents. | |
| 604 // | |
| 605 GatheringErrorListener originalListener = new GatheringErrorListener(); | |
| 606 Scanner originalScanner = new Scanner( | |
| 607 source, | |
| 608 new CharSequenceReader(originalContents), | |
| 609 originalListener); | |
| 610 _originalTokens = originalScanner.tokenize(); | |
| 611 expect(_originalTokens, isNotNull); | |
| 612 // | |
| 613 // Scan the modified contents. | |
| 614 // | |
| 615 GatheringErrorListener modifiedListener = new GatheringErrorListener(); | |
| 616 Scanner modifiedScanner = new Scanner( | |
| 617 source, | |
| 618 new CharSequenceReader(modifiedContents), | |
| 619 modifiedListener); | |
| 620 Token modifiedTokens = modifiedScanner.tokenize(); | |
| 621 expect(modifiedTokens, isNotNull); | |
| 622 // | |
| 623 // Incrementally scan the modified contents. | |
| 624 // | |
| 625 GatheringErrorListener incrementalListener = new GatheringErrorListener(); | |
| 626 _incrementalScanner = new IncrementalScanner( | |
| 627 source, | |
| 628 new CharSequenceReader(modifiedContents), | |
| 629 incrementalListener); | |
| 630 _incrementalTokens = _incrementalScanner.rescan( | |
| 631 _originalTokens, | |
| 632 replaceStart, | |
| 633 removed.length, | |
| 634 added.length); | |
| 635 // | |
| 636 // Validate that the results of the incremental scan are the same as the | |
| 637 // full scan of the modified source. | |
| 638 // | |
| 639 Token incrementalToken = _incrementalTokens; | |
| 640 expect(incrementalToken, isNotNull); | |
| 641 while (incrementalToken.type != TokenType.EOF && | |
| 642 modifiedTokens.type != TokenType.EOF) { | |
| 643 expect( | |
| 644 incrementalToken.type, | |
| 645 same(modifiedTokens.type), | |
| 646 reason: "Wrong type for token"); | |
| 647 expect( | |
| 648 incrementalToken.offset, | |
| 649 modifiedTokens.offset, | |
| 650 reason: | |
| 651 "Wrong offset for token (${incrementalToken.lexeme} != ${modifiedT
okens.lexeme})"); | |
| 652 expect( | |
| 653 incrementalToken.length, | |
| 654 modifiedTokens.length, | |
| 655 reason: | |
| 656 "Wrong length for token (${incrementalToken.lexeme} != ${modifiedT
okens.lexeme})"); | |
| 657 expect( | |
| 658 incrementalToken.lexeme, | |
| 659 modifiedTokens.lexeme, | |
| 660 reason: "Wrong lexeme for token"); | |
| 661 incrementalToken = incrementalToken.next; | |
| 662 modifiedTokens = modifiedTokens.next; | |
| 663 } | |
| 664 expect( | |
| 665 incrementalToken.type, | |
| 666 same(TokenType.EOF), | |
| 667 reason: "Too many tokens"); | |
| 668 expect( | |
| 669 modifiedTokens.type, | |
| 670 same(TokenType.EOF), | |
| 671 reason: "Not enough tokens"); | |
| 672 // TODO(brianwilkerson) Verify that the errors are correct? | |
| 673 } | |
| 674 } | |
| 675 | |
| 676 class KeywordStateTest { | 126 class KeywordStateTest { |
| 677 void test_KeywordState() { | 127 void test_KeywordState() { |
| 678 // | 128 // |
| 679 // Generate the test data to be scanned. | 129 // Generate the test data to be scanned. |
| 680 // | 130 // |
| 681 List<Keyword> keywords = Keyword.values; | 131 List<Keyword> keywords = Keyword.values; |
| 682 int keywordCount = keywords.length; | 132 int keywordCount = keywords.length; |
| 683 List<String> textToTest = new List<String>(keywordCount * 3); | 133 List<String> textToTest = new List<String>(keywordCount * 3); |
| 684 for (int i = 0; i < keywordCount; i++) { | 134 for (int i = 0; i < keywordCount; i++) { |
| 685 String syntax = keywords[i].syntax; | 135 String syntax = keywords[i].syntax; |
| (...skipping 931 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1617 expect(token.type, TokenType.EOF); | 1067 expect(token.type, TokenType.EOF); |
| 1618 comment = token.precedingComments; | 1068 comment = token.precedingComments; |
| 1619 expect(comment, isNotNull); | 1069 expect(comment, isNotNull); |
| 1620 expect(comment.type, commentType); | 1070 expect(comment.type, commentType); |
| 1621 expect(comment.offset, 0); | 1071 expect(comment.offset, 0); |
| 1622 expect(comment.length, source.length); | 1072 expect(comment.length, source.length); |
| 1623 expect(comment.lexeme, source); | 1073 expect(comment.lexeme, source); |
| 1624 } | 1074 } |
| 1625 | 1075 |
| 1626 /** | 1076 /** |
| 1627 * Assert that scanning the given source produces an error with the given code
. | 1077 * Assert that scanning the given [source] produces an error with the given |
| 1078 * code. |
| 1628 * | 1079 * |
| 1629 * @param expectedError the error that should be produced | 1080 * [expectedError] the error that should be produced |
| 1630 * @param expectedOffset the string offset that should be associated with the
error | 1081 * [expectedOffset] the string offset that should be associated with the error |
| 1631 * @param source the source to be scanned to produce the error | 1082 * [source] the source to be scanned to produce the error |
| 1632 */ | 1083 */ |
| 1633 void _assertError(ScannerErrorCode expectedError, int expectedOffset, | 1084 void _assertError(ScannerErrorCode expectedError, int expectedOffset, |
| 1634 String source) { | 1085 String source) { |
| 1635 GatheringErrorListener listener = new GatheringErrorListener(); | 1086 GatheringErrorListener listener = new GatheringErrorListener(); |
| 1636 _scanWithListener(source, listener); | 1087 _scanWithListener(source, listener); |
| 1637 listener.assertErrors( | 1088 listener.assertErrors( |
| 1638 [ | 1089 [ |
| 1639 new AnalysisError.con2( | 1090 new AnalysisError.con2( |
| 1640 null, | 1091 null, |
| 1641 expectedOffset, | 1092 expectedOffset, |
| 1642 1, | 1093 1, |
| 1643 expectedError, | 1094 expectedError, |
| 1644 [source.codeUnitAt(expectedOffset)])]); | 1095 [source.codeUnitAt(expectedOffset)])]); |
| 1645 } | 1096 } |
| 1646 | 1097 |
| 1647 /** | 1098 /** |
| 1648 * Assert that scanning the given source produces an error with the given code
, and also produces | 1099 * Assert that scanning the given [source] produces an error with the given |
| 1649 * the given tokens. | 1100 * code, and also produces the given tokens. |
| 1650 * | 1101 * |
| 1651 * @param expectedError the error that should be produced | 1102 * [expectedError] the error that should be produced |
| 1652 * @param expectedOffset the string offset that should be associated with the
error | 1103 * [expectedOffset] the string offset that should be associated with the error |
| 1653 * @param source the source to be scanned to produce the error | 1104 * [source] the source to be scanned to produce the error |
| 1654 * @param expectedTokens the tokens that are expected to be in the source | 1105 * [expectedTokens] the tokens that are expected to be in the source |
| 1655 */ | 1106 */ |
| 1656 void _assertErrorAndTokens(ScannerErrorCode expectedError, int expectedOffset, | 1107 void _assertErrorAndTokens(ScannerErrorCode expectedError, int expectedOffset, |
| 1657 String source, List<Token> expectedTokens) { | 1108 String source, List<Token> expectedTokens) { |
| 1658 GatheringErrorListener listener = new GatheringErrorListener(); | 1109 GatheringErrorListener listener = new GatheringErrorListener(); |
| 1659 Token token = _scanWithListener(source, listener); | 1110 Token token = _scanWithListener(source, listener); |
| 1660 listener.assertErrors( | 1111 listener.assertErrors( |
| 1661 [ | 1112 [ |
| 1662 new AnalysisError.con2( | 1113 new AnalysisError.con2( |
| 1663 null, | 1114 null, |
| 1664 expectedOffset, | 1115 expectedOffset, |
| 1665 1, | 1116 1, |
| 1666 expectedError, | 1117 expectedError, |
| 1667 [source.codeUnitAt(expectedOffset)])]); | 1118 [source.codeUnitAt(expectedOffset)])]); |
| 1668 _checkTokens(token, expectedTokens); | 1119 _checkTokens(token, expectedTokens); |
| 1669 } | 1120 } |
| 1670 | 1121 |
| 1671 /** | 1122 /** |
| 1672 * Assert that when scanned the given source contains a single keyword token w
ith the same lexeme | 1123 * Assert that when scanned the given [source] contains a single keyword token |
| 1673 * as the original source. | 1124 * with the same lexeme as the original source. |
| 1674 * | |
| 1675 * @param source the source to be scanned | |
| 1676 */ | 1125 */ |
| 1677 void _assertKeywordToken(String source) { | 1126 void _assertKeywordToken(String source) { |
| 1678 Token token = _scan(source); | 1127 Token token = _scan(source); |
| 1679 expect(token, isNotNull); | 1128 expect(token, isNotNull); |
| 1680 expect(token.type, TokenType.KEYWORD); | 1129 expect(token.type, TokenType.KEYWORD); |
| 1681 expect(token.offset, 0); | 1130 expect(token.offset, 0); |
| 1682 expect(token.length, source.length); | 1131 expect(token.length, source.length); |
| 1683 expect(token.lexeme, source); | 1132 expect(token.lexeme, source); |
| 1684 Object value = token.value(); | 1133 Object value = token.value(); |
| 1685 expect(value is Keyword, isTrue); | 1134 expect(value is Keyword, isTrue); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1704 LineInfo info = listener.getLineInfo(new TestSource()); | 1153 LineInfo info = listener.getLineInfo(new TestSource()); |
| 1705 expect(info, isNotNull); | 1154 expect(info, isNotNull); |
| 1706 for (ScannerTest_ExpectedLocation expectedLocation in expectedLocations) { | 1155 for (ScannerTest_ExpectedLocation expectedLocation in expectedLocations) { |
| 1707 LineInfo_Location location = info.getLocation(expectedLocation._offset); | 1156 LineInfo_Location location = info.getLocation(expectedLocation._offset); |
| 1708 expect(location.lineNumber, expectedLocation._lineNumber); | 1157 expect(location.lineNumber, expectedLocation._lineNumber); |
| 1709 expect(location.columnNumber, expectedLocation._columnNumber); | 1158 expect(location.columnNumber, expectedLocation._columnNumber); |
| 1710 } | 1159 } |
| 1711 } | 1160 } |
| 1712 | 1161 |
| 1713 /** | 1162 /** |
| 1714 * Assert that the token scanned from the given source has the expected type. | 1163 * Assert that the token scanned from the given [source] has the |
| 1715 * | 1164 * [expectedType]. |
| 1716 * @param expectedType the expected type of the token | |
| 1717 * @param source the source to be scanned to produce the actual token | |
| 1718 */ | 1165 */ |
| 1719 Token _assertToken(TokenType expectedType, String source) { | 1166 Token _assertToken(TokenType expectedType, String source) { |
| 1720 Token originalToken = _scan(source); | 1167 Token originalToken = _scan(source); |
| 1721 expect(originalToken, isNotNull); | 1168 expect(originalToken, isNotNull); |
| 1722 expect(originalToken.type, expectedType); | 1169 expect(originalToken.type, expectedType); |
| 1723 expect(originalToken.offset, 0); | 1170 expect(originalToken.offset, 0); |
| 1724 expect(originalToken.length, source.length); | 1171 expect(originalToken.length, source.length); |
| 1725 expect(originalToken.lexeme, source); | 1172 expect(originalToken.lexeme, source); |
| 1726 if (expectedType == TokenType.SCRIPT_TAG) { | 1173 if (expectedType == TokenType.SCRIPT_TAG) { |
| 1727 // Adding space before the script tag is not allowed, and adding text at | 1174 // Adding space before the script tag is not allowed, and adding text at |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1755 expect(tokenWithSpaces, isNotNull); | 1202 expect(tokenWithSpaces, isNotNull); |
| 1756 expect(tokenWithSpaces.type, expectedType); | 1203 expect(tokenWithSpaces.type, expectedType); |
| 1757 expect(tokenWithSpaces.offset, 1); | 1204 expect(tokenWithSpaces.offset, 1); |
| 1758 expect(tokenWithSpaces.length, source.length); | 1205 expect(tokenWithSpaces.length, source.length); |
| 1759 expect(tokenWithSpaces.lexeme, source); | 1206 expect(tokenWithSpaces.lexeme, source); |
| 1760 expect(originalToken.next.type, TokenType.EOF); | 1207 expect(originalToken.next.type, TokenType.EOF); |
| 1761 return originalToken; | 1208 return originalToken; |
| 1762 } | 1209 } |
| 1763 | 1210 |
| 1764 /** | 1211 /** |
| 1765 * Assert that when scanned the given source contains a sequence of tokens ide
ntical to the given | 1212 * Assert that when scanned the given [source] contains a sequence of tokens |
| 1766 * tokens. | 1213 * identical to the given list of [expectedTokens]. |
| 1767 * | |
| 1768 * @param source the source to be scanned | |
| 1769 * @param expectedTokens the tokens that are expected to be in the source | |
| 1770 */ | 1214 */ |
| 1771 void _assertTokens(String source, List<Token> expectedTokens) { | 1215 void _assertTokens(String source, List<Token> expectedTokens) { |
| 1772 Token token = _scan(source); | 1216 Token token = _scan(source); |
| 1773 _checkTokens(token, expectedTokens); | 1217 _checkTokens(token, expectedTokens); |
| 1774 } | 1218 } |
| 1775 | 1219 |
| 1776 void _checkTokens(Token firstToken, List<Token> expectedTokens) { | 1220 void _checkTokens(Token firstToken, List<Token> expectedTokens) { |
| 1777 expect(firstToken, isNotNull); | 1221 expect(firstToken, isNotNull); |
| 1778 Token token = firstToken; | 1222 Token token = firstToken; |
| 1779 for (int i = 0; i < expectedTokens.length; i++) { | 1223 for (int i = 0; i < expectedTokens.length; i++) { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1807 Token _scanWithListener(String source, GatheringErrorListener listener) { | 1251 Token _scanWithListener(String source, GatheringErrorListener listener) { |
| 1808 Scanner scanner = | 1252 Scanner scanner = |
| 1809 new Scanner(null, new CharSequenceReader(source), listener); | 1253 new Scanner(null, new CharSequenceReader(source), listener); |
| 1810 Token result = scanner.tokenize(); | 1254 Token result = scanner.tokenize(); |
| 1811 listener.setLineInfo(new TestSource(), scanner.lineStarts); | 1255 listener.setLineInfo(new TestSource(), scanner.lineStarts); |
| 1812 return result; | 1256 return result; |
| 1813 } | 1257 } |
| 1814 } | 1258 } |
| 1815 | 1259 |
| 1816 /** | 1260 /** |
| 1817 * Instances of the class `ExpectedLocation` encode information about the expect
ed location | 1261 * An `ExpectedLocation` encodes information about the expected location of a |
| 1818 * of a given offset in source code. | 1262 * given offset in source code. |
| 1819 */ | 1263 */ |
| 1820 class ScannerTest_ExpectedLocation { | 1264 class ScannerTest_ExpectedLocation { |
| 1821 final int _offset; | 1265 final int _offset; |
| 1822 | 1266 |
| 1823 final int _lineNumber; | 1267 final int _lineNumber; |
| 1824 | 1268 |
| 1825 final int _columnNumber; | 1269 final int _columnNumber; |
| 1826 | 1270 |
| 1827 ScannerTest_ExpectedLocation(this._offset, this._lineNumber, | 1271 ScannerTest_ExpectedLocation(this._offset, this._lineNumber, |
| 1828 this._columnNumber); | 1272 this._columnNumber); |
| 1829 } | 1273 } |
| 1830 | 1274 |
| 1831 /** | 1275 /** |
| 1832 * Instances of the class `TokenStreamValidator` are used to validate the correc
t construction | 1276 * A `TokenStreamValidator` is used to validate the correct construction of a |
| 1833 * of a stream of tokens. | 1277 * stream of tokens. |
| 1834 */ | 1278 */ |
| 1835 class TokenStreamValidator { | 1279 class TokenStreamValidator { |
| 1836 /** | 1280 /** |
| 1837 * Validate that the stream of tokens that starts with the given token is corr
ect. | 1281 * Validate that the stream of tokens that starts with the given [token] is |
| 1838 * | 1282 * correct. |
| 1839 * @param token the first token in the stream of tokens to be validated | |
| 1840 */ | 1283 */ |
| 1841 void validate(Token token) { | 1284 void validate(Token token) { |
| 1842 StringBuffer buffer = new StringBuffer(); | 1285 StringBuffer buffer = new StringBuffer(); |
| 1843 _validateStream(buffer, token); | 1286 _validateStream(buffer, token); |
| 1844 if (buffer.length > 0) { | 1287 if (buffer.length > 0) { |
| 1845 fail(buffer.toString()); | 1288 fail(buffer.toString()); |
| 1846 } | 1289 } |
| 1847 } | 1290 } |
| 1848 | 1291 |
| 1849 void _validateStream(StringBuffer buffer, Token token) { | 1292 void _validateStream(StringBuffer buffer, Token token) { |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1954 expect(TokenType.LT_LT.isUserDefinableOperator, isTrue); | 1397 expect(TokenType.LT_LT.isUserDefinableOperator, isTrue); |
| 1955 expect(TokenType.MINUS.isUserDefinableOperator, isTrue); | 1398 expect(TokenType.MINUS.isUserDefinableOperator, isTrue); |
| 1956 expect(TokenType.PERCENT.isUserDefinableOperator, isTrue); | 1399 expect(TokenType.PERCENT.isUserDefinableOperator, isTrue); |
| 1957 expect(TokenType.PLUS.isUserDefinableOperator, isTrue); | 1400 expect(TokenType.PLUS.isUserDefinableOperator, isTrue); |
| 1958 expect(TokenType.SLASH.isUserDefinableOperator, isTrue); | 1401 expect(TokenType.SLASH.isUserDefinableOperator, isTrue); |
| 1959 expect(TokenType.STAR.isUserDefinableOperator, isTrue); | 1402 expect(TokenType.STAR.isUserDefinableOperator, isTrue); |
| 1960 expect(TokenType.TILDE.isUserDefinableOperator, isTrue); | 1403 expect(TokenType.TILDE.isUserDefinableOperator, isTrue); |
| 1961 expect(TokenType.TILDE_SLASH.isUserDefinableOperator, isTrue); | 1404 expect(TokenType.TILDE_SLASH.isUserDefinableOperator, isTrue); |
| 1962 } | 1405 } |
| 1963 } | 1406 } |
| OLD | NEW |