| Index: test/backend/platform_selector/scanner_test.dart
|
| diff --git a/test/backend/platform_selector/scanner_test.dart b/test/backend/platform_selector/scanner_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e2ecdda6d67b1b452768444d8f1eac54bb6e39cb
|
| --- /dev/null
|
| +++ b/test/backend/platform_selector/scanner_test.dart
|
| @@ -0,0 +1,266 @@
|
| +// Copyright (c) 2015, 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 'package:unittest/unittest.dart';
|
| +import 'package:unittest/src/backend/platform_selector/scanner.dart';
|
| +import 'package:unittest/src/backend/platform_selector/token.dart';
|
| +
|
| +void main() {
|
| + group("peek()", () {
|
| + test("returns the next token without consuming it", () {
|
| + var scanner = new Scanner("( )");
|
| + expect(scanner.peek().type, equals(TokenType.leftParen));
|
| + expect(scanner.peek().type, equals(TokenType.leftParen));
|
| + expect(scanner.peek().type, equals(TokenType.leftParen));
|
| + });
|
| +
|
| + test("returns an end-of-file token at the end of a file", () {
|
| + var scanner = new Scanner("( )");
|
| + scanner.next();
|
| + scanner.next();
|
| +
|
| + var token = scanner.peek();
|
| + expect(token.type, equals(TokenType.endOfFile));
|
| + expect(token.span.start.offset, equals(3));
|
| + expect(token.span.end.offset, equals(3));
|
| + });
|
| +
|
| + test("throws a StateError if called after end-of-file was consumed", () {
|
| + var scanner = new Scanner("( )");
|
| + scanner.next();
|
| + scanner.next();
|
| + scanner.next();
|
| + expect(() => scanner.peek(), throwsStateError);
|
| + });
|
| + });
|
| +
|
| + group("next()", () {
|
| + test("consumes and returns the next token", () {
|
| + var scanner = new Scanner("( )");
|
| + expect(scanner.next().type, equals(TokenType.leftParen));
|
| + expect(scanner.peek().type, equals(TokenType.rightParen));
|
| + expect(scanner.next().type, equals(TokenType.rightParen));
|
| + });
|
| +
|
| + test("returns an end-of-file token at the end of a file", () {
|
| + var scanner = new Scanner("( )");
|
| + scanner.next();
|
| + scanner.next();
|
| +
|
| + var token = scanner.next();
|
| + expect(token.type, equals(TokenType.endOfFile));
|
| + expect(token.span.start.offset, equals(3));
|
| + expect(token.span.end.offset, equals(3));
|
| + });
|
| +
|
| + test("throws a StateError if called after end-of-file was consumed", () {
|
| + var scanner = new Scanner("( )");
|
| + scanner.next();
|
| + scanner.next();
|
| + scanner.next();
|
| + expect(() => scanner.next(), throwsStateError);
|
| + });
|
| + });
|
| +
|
| + group("scan()", () {
|
| + test("consumes a matching token and returns true", () {
|
| + var scanner = new Scanner("( )");
|
| + expect(scanner.scan(TokenType.leftParen), isTrue);
|
| + expect(scanner.peek().type, equals(TokenType.rightParen));
|
| + });
|
| +
|
| + test("doesn't consume a matching token and returns false", () {
|
| + var scanner = new Scanner("( )");
|
| + expect(scanner.scan(TokenType.questionMark), isFalse);
|
| + expect(scanner.peek().type, equals(TokenType.leftParen));
|
| + });
|
| +
|
| + test("throws a StateError called after end-of-file was consumed", () {
|
| + var scanner = new Scanner("( )");
|
| + scanner.next();
|
| + scanner.next();
|
| + scanner.next();
|
| + expect(() => scanner.scan(TokenType.endOfFile), throwsStateError);
|
| + });
|
| + });
|
| +
|
| + group("scans a simple token:", () {
|
| + test("left paren", () => _expectSimpleScan("(", TokenType.leftParen));
|
| + test("right paren", () => _expectSimpleScan(")", TokenType.rightParen));
|
| + test("or", () => _expectSimpleScan("||", TokenType.or));
|
| + test("and", () => _expectSimpleScan("&&", TokenType.and));
|
| + test("not", () => _expectSimpleScan("!", TokenType.not));
|
| + test("question mark", () => _expectSimpleScan("?", TokenType.questionMark));
|
| + test("colon", () => _expectSimpleScan(":", TokenType.colon));
|
| + });
|
| +
|
| + group("scans an identifier that", () {
|
| + test("is simple", () {
|
| + var token = _scan(" foo ");
|
| + expect(token.name, equals("foo"));
|
| + expect(token.span.text, equals("foo"));
|
| + expect(token.span.start.offset, equals(3));
|
| + expect(token.span.end.offset, equals(6));
|
| + });
|
| +
|
| + test("is a single character", () {
|
| + var token = _scan("f");
|
| + expect(token.name, equals("f"));
|
| + });
|
| +
|
| + test("has a leading underscore", () {
|
| + var token = _scan("_foo");
|
| + expect(token.name, equals("_foo"));
|
| + });
|
| +
|
| + test("has a leading dash", () {
|
| + var token = _scan("-foo");
|
| + expect(token.name, equals("-foo"));
|
| + });
|
| +
|
| + test("contains an underscore", () {
|
| + var token = _scan("foo_bar");
|
| + expect(token.name, equals("foo_bar"));
|
| + });
|
| +
|
| + test("contains a dash", () {
|
| + var token = _scan("foo-bar");
|
| + expect(token.name, equals("foo-bar"));
|
| + });
|
| +
|
| + test("is capitalized", () {
|
| + var token = _scan("FOO");
|
| + expect(token.name, equals("FOO"));
|
| + });
|
| +
|
| + test("contains numbers", () {
|
| + var token = _scan("foo123");
|
| + expect(token.name, equals("foo123"));
|
| + });
|
| + });
|
| +
|
| + test("scans an empty selector", () {
|
| + expect(_scan("").type, equals(TokenType.endOfFile));
|
| + });
|
| +
|
| + test("scans multiple tokens", () {
|
| + var scanner = new Scanner("(foo && bar)");
|
| +
|
| + var token = scanner.next();
|
| + expect(token.type, equals(TokenType.leftParen));
|
| + expect(token.span.start.offset, equals(0));
|
| + expect(token.span.end.offset, equals(1));
|
| +
|
| + token = scanner.next();
|
| + expect(token.type, equals(TokenType.identifier));
|
| + expect(token.name, equals("foo"));
|
| + expect(token.span.start.offset, equals(1));
|
| + expect(token.span.end.offset, equals(4));
|
| +
|
| + token = scanner.next();
|
| + expect(token.type, equals(TokenType.and));
|
| + expect(token.span.start.offset, equals(5));
|
| + expect(token.span.end.offset, equals(7));
|
| +
|
| + token = scanner.next();
|
| + expect(token.type, equals(TokenType.identifier));
|
| + expect(token.name, equals("bar"));
|
| + expect(token.span.start.offset, equals(8));
|
| + expect(token.span.end.offset, equals(11));
|
| +
|
| + token = scanner.next();
|
| + expect(token.type, equals(TokenType.rightParen));
|
| + expect(token.span.start.offset, equals(11));
|
| + expect(token.span.end.offset, equals(12));
|
| +
|
| + token = scanner.next();
|
| + expect(token.type, equals(TokenType.endOfFile));
|
| + expect(token.span.start.offset, equals(12));
|
| + expect(token.span.end.offset, equals(12));
|
| + });
|
| +
|
| + group("ignores", () {
|
| + test("a single-line comment", () {
|
| + var scanner = new Scanner("( // &&\n// ||\n)");
|
| + expect(scanner.next().type, equals(TokenType.leftParen));
|
| + expect(scanner.next().type, equals(TokenType.rightParen));
|
| + expect(scanner.next().type, equals(TokenType.endOfFile));
|
| + });
|
| +
|
| + test("a single-line comment without a trailing newline", () {
|
| + var scanner = new Scanner("( // &&");
|
| + expect(scanner.next().type, equals(TokenType.leftParen));
|
| + expect(scanner.next().type, equals(TokenType.endOfFile));
|
| + });
|
| +
|
| + test("a multi-line comment", () {
|
| + var scanner = new Scanner("( /* && * /\n|| */\n)");
|
| + expect(scanner.next().type, equals(TokenType.leftParen));
|
| + expect(scanner.next().type, equals(TokenType.rightParen));
|
| + expect(scanner.next().type, equals(TokenType.endOfFile));
|
| + });
|
| +
|
| + test("a multi-line nested comment", () {
|
| + var scanner = new Scanner("(/* && /* ? /* || */ : */ ! */)");
|
| + expect(scanner.next().type, equals(TokenType.leftParen));
|
| + expect(scanner.next().type, equals(TokenType.rightParen));
|
| + expect(scanner.next().type, equals(TokenType.endOfFile));
|
| + });
|
| +
|
| + test("Dart's notion of whitespace", () {
|
| + var scanner = new Scanner("( \t \n)");
|
| + expect(scanner.next().type, equals(TokenType.leftParen));
|
| + expect(scanner.next().type, equals(TokenType.rightParen));
|
| + expect(scanner.next().type, equals(TokenType.endOfFile));
|
| + });
|
| + });
|
| +
|
| + group("disallows", () {
|
| + test("a single |", () {
|
| + expect(() => _scan("|"), throwsFormatException);
|
| + });
|
| +
|
| + test('"| |"', () {
|
| + expect(() => _scan("| |"), throwsFormatException);
|
| + });
|
| +
|
| + test("a single &", () {
|
| + expect(() => _scan("&"), throwsFormatException);
|
| + });
|
| +
|
| + test('"& &"', () {
|
| + expect(() => _scan("& &"), throwsFormatException);
|
| + });
|
| +
|
| + test("an unknown operator", () {
|
| + expect(() => _scan("=="), throwsFormatException);
|
| + });
|
| +
|
| + test("unicode", () {
|
| + expect(() => _scan("öh"), throwsFormatException);
|
| + });
|
| +
|
| + test("an unclosed multi-line comment", () {
|
| + expect(() => _scan("/*"), throwsFormatException);
|
| + });
|
| +
|
| + test("an unopened multi-line comment", () {
|
| + expect(() => _scan("*/"), throwsFormatException);
|
| + });
|
| + });
|
| +}
|
| +
|
| +/// Asserts that the first token scanned from [selector] has type [type],
|
| +/// and that that token's span is exactly [selector].
|
| +void _expectSimpleScan(String selector, TokenType type) {
|
| + // Complicate the selector to test that the span covers it correctly.
|
| + var token = _scan(" $selector ");
|
| + expect(token.type, equals(type));
|
| + expect(token.span.text, equals(selector));
|
| + expect(token.span.start.offset, equals(3));
|
| + expect(token.span.end.offset, equals(3 + selector.length));
|
| +}
|
| +
|
| +/// Scans a single token from [selector].
|
| +Token _scan(String selector) => new Scanner(selector).next();
|
|
|