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

Unified Diff: pkg/front_end/test/scanner_fasta_test.dart

Issue 2915093002: improve fasta unterminated string recovery (Closed)
Patch Set: fix dartdoc Created 3 years, 7 months 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 side-by-side diff with in-line comments
Download patch
Index: pkg/front_end/test/scanner_fasta_test.dart
diff --git a/pkg/front_end/test/scanner_fasta_test.dart b/pkg/front_end/test/scanner_fasta_test.dart
index 852c5151185aab03672c7cdb8108899d2dc14715..60ae3c3847d1a0bf0580bcc1fff5fe00dd84fbf3 100644
--- a/pkg/front_end/test/scanner_fasta_test.dart
+++ b/pkg/front_end/test/scanner_fasta_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2017, 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.
+import 'dart:convert';
import 'package:analyzer/src/fasta/token_utils.dart';
import 'package:front_end/src/fasta/fasta_codes.dart';
@@ -8,6 +9,7 @@ import 'package:front_end/src/fasta/scanner/error_token.dart' as fasta;
import 'package:front_end/src/fasta/scanner/string_scanner.dart' as fasta;
import 'package:front_end/src/fasta/scanner/token.dart' as fasta;
import 'package:front_end/src/fasta/scanner/token_constants.dart' as fasta;
+import 'package:front_end/src/fasta/scanner/utf8_bytes_scanner.dart' as fasta;
import 'package:front_end/src/scanner/errors.dart';
import 'package:front_end/src/scanner/token.dart';
import 'package:test/test.dart';
@@ -18,23 +20,41 @@ import 'scanner_test.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(ScannerTest_Fasta);
+ defineReflectiveTests(ScannerTest_Fasta_UTF8);
defineReflectiveTests(ScannerTest_Fasta_Direct);
+ defineReflectiveTests(ScannerTest_Fasta_Direct_UTF8);
});
}
@reflectiveTest
+class ScannerTest_Fasta_UTF8 extends ScannerTest_Fasta {
+ @override
+ createScanner(String source, {bool genericMethodComments: false}) {
+ List<int> encoded = UTF8.encode(source).toList(growable: true);
+ encoded.add(0); // Ensure 0 terminted bytes for UTF8 scanner
+ return new fasta.Utf8BytesScanner(encoded,
+ includeComments: true,
+ scanGenericMethodComments: genericMethodComments);
+ }
+}
+
+@reflectiveTest
class ScannerTest_Fasta extends ScannerTestBase {
ScannerTest_Fasta() {
usingFasta = true;
}
+ createScanner(String source, {bool genericMethodComments: false}) =>
+ new fasta.StringScanner(source,
+ includeComments: true,
+ scanGenericMethodComments: genericMethodComments);
+
@override
Token scanWithListener(String source, ErrorListener listener,
{bool genericMethodComments: false,
bool lazyAssignmentOperators: false}) {
- var scanner = new fasta.StringScanner(source,
- includeComments: true,
- scanGenericMethodComments: genericMethodComments);
+ var scanner =
+ createScanner(source, genericMethodComments: genericMethodComments);
var token = scanner.tokenize();
return new ToAnalyzerTokenStreamConverter_WithListener(listener)
.convertTokens(token);
@@ -240,76 +260,6 @@ main() {}
}
@override
- @failingTest
- void test_string_multi_unterminated() {
- // TODO(paulberry,ahe): bad error recovery.
- super.test_string_multi_unterminated();
- }
-
- @override
- @failingTest
- void test_string_multi_unterminated_interpolation_block() {
- // TODO(paulberry,ahe): bad error recovery.
- super.test_string_multi_unterminated_interpolation_block();
- }
-
- @override
- @failingTest
- void test_string_multi_unterminated_interpolation_identifier() {
- // TODO(paulberry,ahe): bad error recovery.
- super.test_string_multi_unterminated_interpolation_identifier();
- }
-
- @override
- @failingTest
- void test_string_raw_multi_unterminated() {
- // TODO(paulberry,ahe): bad error recovery.
- super.test_string_raw_multi_unterminated();
- }
-
- @override
- @failingTest
- void test_string_raw_simple_unterminated_eof() {
- // TODO(paulberry,ahe): bad error recovery.
- super.test_string_raw_simple_unterminated_eof();
- }
-
- @override
- @failingTest
- void test_string_raw_simple_unterminated_eol() {
- // TODO(paulberry,ahe): bad error recovery.
- super.test_string_raw_simple_unterminated_eol();
- }
-
- @override
- @failingTest
- void test_string_simple_unterminated_eof() {
- // TODO(paulberry,ahe): bad error recovery.
- super.test_string_simple_unterminated_eof();
- }
-
- @override
- @failingTest
- void test_string_simple_unterminated_eol() {
- // TODO(paulberry,ahe): bad error recovery.
- super.test_string_simple_unterminated_eol();
- }
-
- @override
- @failingTest
- void test_string_simple_unterminated_interpolation_block() {
- // TODO(paulberry,ahe): bad error recovery.
- super.test_string_simple_unterminated_interpolation_block();
- }
-
- @override
- @failingTest
- void test_string_simple_unterminated_interpolation_identifier() {
- // TODO(paulberry,ahe): bad error recovery.
- super.test_string_simple_unterminated_interpolation_identifier();
- }
-
- @override
void test_unmatched_openers() {
var openBrace = _scan('{[(') as BeginToken;
var openBracket = openBrace.next as BeginToken;
@@ -339,6 +289,125 @@ main() {}
abstract class ScannerTest_Fasta_Base {
Token scan(String source);
+ expectToken(Token token, TokenType type, int offset, int length,
+ {bool isSynthetic: false, String lexeme}) {
+ String description = '${token.type} $token';
+ expect(token.type, type, reason: description);
+ expect(token.offset, offset, reason: description);
+ expect(token.length, length, reason: description);
+ expect(token.isSynthetic, isSynthetic, reason: description);
+ if (lexeme != null) {
+ expect(token.lexeme, lexeme, reason: description);
+ }
+ }
+
+ void test_string_simple_unterminated_interpolation_block() {
+ Token token = scan(r'"foo ${bar');
+ expectToken(token, TokenType.STRING, 0, 5, lexeme: '"foo ');
+
+ token = token.next;
+ expectToken(token, TokenType.STRING_INTERPOLATION_EXPRESSION, 5, 2);
+ BeginToken interpolationStart = token;
+
+ token = token.next;
+ expectToken(token, TokenType.IDENTIFIER, 7, 3, lexeme: 'bar');
+
+ // Expect interpolation to be terminated before string is closed
+ token = token.next;
+ expectToken(token, TokenType.CLOSE_CURLY_BRACKET, 10, 0,
+ isSynthetic: true, lexeme: '}');
+ expect(interpolationStart.endToken, same(token));
+
+ token = token.next;
+ expect((token as fasta.ErrorToken).errorCode, same(codeUnmatchedToken));
+ expect((token as fasta.UnmatchedToken).begin, same(interpolationStart));
+
+ token = token.next;
+ expectToken(token, TokenType.STRING, 10, 0, isSynthetic: true, lexeme: '"');
+
+ token = token.next;
+ expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
+ }
+
+ void test_string_simple_missing_interpolation_identifier() {
+ Token token = scan(r'"foo $');
+ expectToken(token, TokenType.STRING, 0, 5, lexeme: '"foo ');
+
+ token = token.next;
+ expectToken(token, TokenType.STRING_INTERPOLATION_IDENTIFIER, 5, 1);
+
+ token = token.next;
+ expect((token as fasta.ErrorToken).errorCode,
+ same(codeUnexpectedDollarInString));
+ expect((token as fasta.UnterminatedToken).start, r'$');
+
+ token = token.next;
+ expectToken(token, TokenType.STRING, 6, 0, isSynthetic: true, lexeme: '"');
+
+ token = token.next;
+ expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
+ }
+
+ void test_string_multi_unterminated() {
+ Token token = scan("'''string");
+ expectToken(token, TokenType.STRING, 0, 9,
+ lexeme: "'''string'''", isSynthetic: true);
+
+ token = token.next;
+ expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
+ expect((token as fasta.ErrorToken).start, "'''");
+ }
+
+ void test_string_raw_multi_unterminated() {
+ Token token = scan("r'''string");
+ expectToken(token, TokenType.STRING, 0, 10,
+ lexeme: "r'''string'''", isSynthetic: true);
+
+ token = token.next;
+ expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
+ expect((token as fasta.ErrorToken).start, "r'''");
+ }
+
+ void test_string_raw_simple_unterminated_eof() {
+ Token token = scan("r'string");
+ expectToken(token, TokenType.STRING, 0, 8,
+ lexeme: "r'string'", isSynthetic: true);
+
+ token = token.next;
+ expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
+ expect((token as fasta.ErrorToken).start, "r'");
+ }
+
+ void test_string_raw_simple_unterminated_eol() {
+ Token token = scan("r'string\n");
+ expectToken(token, TokenType.STRING, 0, 8,
+ lexeme: "r'string'", isSynthetic: true);
+
+ token = token.next;
+ expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
+ expect((token as fasta.ErrorToken).start, "r'");
+ }
+
+ void test_string_simple_unterminated_eof() {
+ Token token = scan("'string");
+ expectToken(token, TokenType.STRING, 0, 7,
+ lexeme: "'string'", isSynthetic: true);
+
+ token = token.next;
+ expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
+ expect((token as fasta.ErrorToken).start, "'");
+ }
+
+ void test_string_simple_unterminated_eol() {
+ Token token = scan("'string\n");
+ expectToken(token, TokenType.STRING, 0, 7,
+ lexeme: "'string'", isSynthetic: true);
+
+ token = token.next;
+ expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
+ expect((token as fasta.ErrorToken).start, "'");
+ }
+
void test_match_angle_brackets() {
var x = scan('x<y>');
var lessThan = x.next as BeginToken;
@@ -494,46 +563,33 @@ abstract class ScannerTest_Fasta_Base {
/// Scanner tests that exercise the Fasta scanner directly.
@reflectiveTest
+class ScannerTest_Fasta_Direct_UTF8 extends ScannerTest_Fasta_Direct {
+ createScanner(String source, {bool includeComments}) {
+ List<int> encoded = UTF8.encode(source).toList(growable: true);
+ encoded.add(0); // Ensure 0 terminted bytes for UTF8 scanner
+ return new fasta.Utf8BytesScanner(encoded,
+ includeComments: includeComments);
+ }
+}
+
+/// Scanner tests that exercise the Fasta scanner directly.
+@reflectiveTest
class ScannerTest_Fasta_Direct extends ScannerTest_Fasta_Base {
+ createScanner(String source, {bool includeComments}) =>
+ new fasta.StringScanner(source, includeComments: includeComments);
+
@override
Token scan(String source) {
- var scanner = new fasta.StringScanner(source, includeComments: true);
- return scanner.tokenize();
+ return createScanner(source, includeComments: true).tokenize();
}
void test_linestarts() {
- var scanner = new fasta.StringScanner("var\r\ni\n=\n1;\n");
+ var scanner = createScanner("var\r\ni\n=\n1;\n");
var token = scanner.tokenize();
expect(token.lexeme, 'var');
var lineStarts = scanner.lineStarts;
expect(lineStarts, orderedEquals([0, 5, 7, 9, 12, 13]));
}
-
- test_unterminated_string_with_unterminated_interpolation() {
- Token token = scan(r'"foo ${bar');
- BeginToken interpolationStart = token.next;
-
- Token previous;
- while (token.kind != fasta.BAD_INPUT_TOKEN) {
- expect(token.isEof, isFalse);
- previous = token;
- token = token.next;
- }
-
- // Expect interpolation to be terminated before string is closed
-
- token = previous;
- expect(token.isSynthetic, isTrue);
- expect(token.length, 0);
- expect(token.stringValue, '}');
-
- token = token.next;
- expect((token as fasta.ErrorToken).errorCode, same(codeUnmatchedToken));
- expect((token as fasta.UnmatchedToken).begin, same(interpolationStart));
-
- token = token.next;
- expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
- }
}
/// Override of [ToAnalyzerTokenStreamConverter] that verifies that there are no

Powered by Google App Engine
This is Rietveld 408576698