Chromium Code Reviews| Index: test/backend/platform_selector/parser_test.dart |
| diff --git a/test/backend/platform_selector/parser_test.dart b/test/backend/platform_selector/parser_test.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0b8f38a85a1f6f4e5a778be36631695eee4714bd |
| --- /dev/null |
| +++ b/test/backend/platform_selector/parser_test.dart |
| @@ -0,0 +1,274 @@ |
| +// 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/ast.dart'; |
| +import 'package:unittest/src/backend/platform_selector/parser.dart'; |
| + |
| +/// A matcher that asserts that a value is a [ConditionalNode]. |
| +Matcher _isConditionalNode = |
| + new isInstanceOf<ConditionalNode>("ConditionalNode"); |
| + |
| +/// A matcher that asserts that a value is an [OrNode]. |
| +Matcher _isOrNode = new isInstanceOf<OrNode>("OrNode"); |
| + |
| +/// A matcher that asserts that a value is an [AndNode]. |
| +Matcher _isAndNode = new isInstanceOf<AndNode>("AndNode"); |
| + |
| +/// A matcher that asserts that a value is a [NotNode]. |
| +Matcher _isNotNode = new isInstanceOf<NotNode>("NotNode"); |
| + |
| +void main() { |
| + group("parses a conditional expression", () { |
| + test("with identifiers", () { |
| + var node = _parse(" a ? b : c "); |
| + expect(node, _isConditionalNode); |
|
Bob Nystrom
2015/03/11 20:05:53
It's probably simpler just to test node.toString()
nweiz
2015/03/12 19:48:58
But the AST tests also rely on the parser to do th
|
| + expect(node.condition, _isVar("a")); |
| + expect(node.branch1, _isVar("b")); |
| + expect(node.branch2, _isVar("c")); |
| + |
| + expect(node.span.text, equals("a ? b : c")); |
| + expect(node.span.start.offset, equals(2)); |
| + expect(node.span.end.offset, equals(11)); |
| + }); |
| + |
| + test("with nested ors", () { |
| + // Should parse as "(a || b) ? (c || d) : (e || f)". |
| + // Should not parse as "a || (b ? (c || d) : (e || f))". |
| + // Should not parse as "((a || b) ? (c || d) : e) || f". |
| + // Should not parse as "a || (b ? (c || d) : e) || f". |
| + var node = _parse("a || b ? c || d : e || f"); |
| + expect(node, _isConditionalNode); |
| + |
| + expect(node.condition, _isOrNode); |
| + expect(node.condition.branch1, _isVar("a")); |
| + expect(node.condition.branch2, _isVar("b")); |
| + |
| + expect(node.branch1, _isOrNode); |
| + expect(node.branch1.branch1, _isVar("c")); |
| + expect(node.branch1.branch2, _isVar("d")); |
| + |
| + expect(node.branch2, _isOrNode); |
| + expect(node.branch2.branch1, _isVar("e")); |
| + expect(node.branch2.branch2, _isVar("f")); |
| + }); |
| + |
| + test("with a conditional expression as branch 1", () { |
| + // Should parse as "a ? (b ? c : d) : e". |
| + var node = _parse("a ? b ? c : d : e"); |
| + expect(node, _isConditionalNode); |
| + expect(node.condition, _isVar("a")); |
| + expect(node.branch2, _isVar("e")); |
| + |
| + expect(node.branch1, _isConditionalNode); |
| + expect(node.branch1.condition, _isVar("b")); |
| + expect(node.branch1.branch1, _isVar("c")); |
| + expect(node.branch1.branch2, _isVar("d")); |
| + }); |
| + |
| + test("with a conditional expression as branch 2", () { |
| + // Should parse as "a ? b : (c ? d : e)". |
| + // Should not parse as "(a ? b : c) ? d : e". |
| + var node = _parse("a ? b : c ? d : e"); |
| + expect(node, _isConditionalNode); |
| + expect(node.condition, _isVar("a")); |
| + expect(node.branch1, _isVar("b")); |
| + |
| + expect(node.branch2, _isConditionalNode); |
| + expect(node.branch2.condition, _isVar("c")); |
| + expect(node.branch2.branch1, _isVar("d")); |
| + expect(node.branch2.branch2, _isVar("e")); |
| + }); |
| + |
| + group("which must have", () { |
| + test("an expression after the ?", () { |
| + expect(() => _parse("a ?"), throwsFormatException); |
| + expect(() => _parse("a ? && b"), throwsFormatException); |
| + }); |
| + |
| + test("a :", () { |
| + expect(() => _parse("a ? b"), throwsFormatException); |
| + expect(() => _parse("a ? b && c"), throwsFormatException); |
| + }); |
| + |
| + test("an expression after the :", () { |
| + expect(() => _parse("a ? b :"), throwsFormatException); |
| + expect(() => _parse("a ? b : && c"), throwsFormatException); |
| + }); |
| + }); |
| + }); |
| + |
| + group("parses an or expression", () { |
| + test("with identifiers", () { |
| + var node = _parse(" a || b "); |
| + expect(node, _isOrNode); |
| + expect(node.branch1, _isVar("a")); |
| + expect(node.branch2, _isVar("b")); |
| + |
| + expect(node.span.text, equals("a || b")); |
| + expect(node.span.start.offset, equals(2)); |
| + expect(node.span.end.offset, equals(8)); |
| + }); |
| + |
| + test("with nested ands", () { |
| + // Should parse as "(a && b) || (c && d)". |
| + // Should not parse as "a && (b || c) && d". |
| + var node = _parse("a && b || c && d"); |
| + expect(node, _isOrNode); |
| + |
| + expect(node.branch1, _isAndNode); |
| + expect(node.branch1.branch1, _isVar("a")); |
| + expect(node.branch1.branch2, _isVar("b")); |
| + |
| + expect(node.branch2, _isAndNode); |
| + expect(node.branch2.branch1, _isVar("c")); |
| + expect(node.branch2.branch2, _isVar("d")); |
| + }); |
| + |
| + test("with trailing ors", () { |
| + // Should parse as "a || (b || (c || d))", although it doesn't affect the |
| + // semantics. |
| + var node = _parse("a || b || c || d"); |
| + |
| + for (var variable in ["a", "b", "c"]) { |
| + expect(node, _isOrNode); |
| + expect(node.branch1, _isVar(variable)); |
| + node = node.branch2; |
| + } |
| + expect(node, _isVar("d")); |
| + }); |
| + |
| + test("which must have an expression after the ||", () { |
| + expect(() => _parse("a ||"), throwsFormatException); |
| + expect(() => _parse("a || && b"), throwsFormatException); |
| + }); |
| + }); |
| + |
| + group("parses an and expression", () { |
| + test("with identifiers", () { |
| + var node = _parse(" a && b "); |
| + expect(node, _isAndNode); |
| + expect(node.branch1, _isVar("a")); |
| + expect(node.branch2, _isVar("b")); |
| + |
| + expect(node.span.text, equals("a && b")); |
| + expect(node.span.start.offset, equals(2)); |
| + expect(node.span.end.offset, equals(8)); |
| + }); |
| + |
| + test("with nested nots", () { |
| + // Should parse as "(!a) && (!b)", obviously. |
| + // Should not parse as "!(a && (!b))". |
| + var node = _parse("!a && !b"); |
| + expect(node, _isAndNode); |
| + |
| + expect(node.branch1, _isNotNode); |
| + expect(node.branch1.child, _isVar("a")); |
| + |
| + expect(node.branch2, _isNotNode); |
| + expect(node.branch2.child, _isVar("b")); |
| + }); |
| + |
| + test("with trailing ands", () { |
| + // Should parse as "a && (b && (c && d))", although it doesn't affect the |
| + // semantics since . |
| + var node = _parse("a && b && c && d"); |
| + |
| + for (var variable in ["a", "b", "c"]) { |
| + expect(node, _isAndNode); |
| + expect(node.branch1, _isVar(variable)); |
| + node = node.branch2; |
| + } |
| + expect(node, _isVar("d")); |
| + }); |
| + |
| + test("which must have an expression after the &&", () { |
| + expect(() => _parse("a &&"), throwsFormatException); |
| + expect(() => _parse("a && && b"), throwsFormatException); |
| + }); |
| + }); |
| + |
| + group("parses a not expression", () { |
| + test("with an identifier", () { |
| + var node = _parse(" ! a "); |
| + expect(node, _isNotNode); |
| + expect(node.child, _isVar("a")); |
| + |
| + expect(node.span.text, equals("! a")); |
| + expect(node.span.start.offset, equals(2)); |
| + expect(node.span.end.offset, equals(5)); |
| + }); |
| + |
| + test("with a parenthesized expression", () { |
| + var node = _parse("!(a || b)"); |
| + expect(node, _isNotNode); |
| + |
| + expect(node.child, _isOrNode); |
| + expect(node.child.branch1, _isVar("a")); |
| + expect(node.child.branch2, _isVar("b")); |
| + }); |
| + |
| + test("with a nested not", () { |
| + var node = _parse("!!a"); |
| + expect(node, _isNotNode); |
| + expect(node.child, _isNotNode); |
| + expect(node.child.child, _isVar("a")); |
| + }); |
| + |
| + test("which must have an expression after the !", () { |
| + expect(() => _parse("!"), throwsFormatException); |
| + expect(() => _parse("! && a"), throwsFormatException); |
| + }); |
| + }); |
| + |
| + group("parses a parenthesized expression", () { |
| + test("with an identifier", () { |
| + var node = _parse("(a)"); |
| + expect(node, _isVar("a")); |
| + }); |
| + |
| + test("controls precedence", () { |
| + // Without parentheses, this would parse as "(a || b) ? c : d". |
| + var node = _parse("a || (b ? c : d)"); |
| + |
| + expect(node, _isOrNode); |
| + expect(node.branch1, _isVar("a")); |
| + |
| + expect(node.branch2, _isConditionalNode); |
| + expect(node.branch2.condition, _isVar("b")); |
| + expect(node.branch2.branch1, _isVar("c")); |
| + expect(node.branch2.branch2, _isVar("d")); |
| + }); |
| + |
| + group("which must have", () { |
| + test("an expression within the ()", () { |
| + expect(() => _parse("()"), throwsFormatException); |
| + expect(() => _parse("( && a )"), throwsFormatException); |
| + }); |
| + |
| + test("a matching )", () { |
| + expect(() => _parse("( a"), throwsFormatException); |
| + }); |
| + }); |
| + }); |
| + |
| + group("disallows", () { |
| + test("an empty selector", () { |
| + expect(() => _parse(""), throwsFormatException); |
| + }); |
| + |
| + test("too many expressions", () { |
| + expect(() => _parse("a b"), throwsFormatException); |
| + }); |
| + }); |
| +} |
| + |
| +/// Parses [selector] and returns its root node. |
| +Node _parse(String selector) => new Parser(selector).parse(); |
| + |
| +/// A matcher that asserts that a value is a [VariableNode] with the given |
| +/// [name]. |
| +Matcher _isVar(String name) => predicate( |
| + (value) => value is VariableNode && value.name == name, |
| + 'is a variable named "$name"'); |