Bug 1352355 - Allow lists as default values in wpt expectation metadata files, r=ato
authorJames Graham <james@hoppipolla.co.uk>
Fri, 30 Nov 2018 23:17:32 +0000
changeset 508568 80a92104544fbab8e6506c86e6b1230a1da01dd4
parent 508567 5441e0814fb901fa2ebb2d694eacf3b98b7bd30f
child 508569 02e4dbfecbc426e118199e4ce140db13814aaf7a
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersato
bugs1352355
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1352355 - Allow lists as default values in wpt expectation metadata files, r=ato A bug in the wptmanifest parser meant that we were erroneously parsing lists in the default-value position for conditionals as strings i.e. key: if cond: [a, b] [c] with cond false was evaluating as the string "[c]" rather than a one-item list containing "c". To fix this we need to ensure that when the indent level doesn't decrease we parse the line after a conditional expression as an expr_or_value rather than as a normal line (this is because the list syntax is ambiguous with headings, and we put too much logic into the tokeniser rather than the parser). Depends on D12409 Differential Revision: https://phabricator.services.mozilla.com/D12410
testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/parser.py
testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_parser.py
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/parser.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/parser.py
@@ -130,19 +130,20 @@ class Tokenizer(object):
         self.skip_whitespace()
         if self.char() == eol:
             self.state = self.eol_state
             return
         if self.index > self.indent_levels[-1]:
             self.indent_levels.append(self.index)
             yield (token_types.group_start, None)
         else:
-            while self.index < self.indent_levels[-1]:
-                self.indent_levels.pop()
-                yield (token_types.group_end, None)
+            if self.index < self.indent_levels[-1]:
+                while self.index < self.indent_levels[-1]:
+                    self.indent_levels.pop()
+                    yield (token_types.group_end, None)
                 # This is terrible; if we were parsing an expression
                 # then the next_state will be expr_or_value but when we deindent
                 # it must always be a heading or key next so we go back to data_line_state
                 self.next_state = self.data_line_state
             if self.index != self.indent_levels[-1]:
                 raise ParseError(self.filename, self.line_number, "Unexpected indent")
 
         self.state = self.next_state
@@ -297,28 +298,31 @@ class Tokenizer(object):
 
     def list_end_state(self):
         self.consume()
         yield (token_types.list_end, "]")
         self.state = self.line_end_state
 
     def value_state(self):
         self.skip_whitespace()
-        if self.char() in ("'", '"'):
+        c = self.char()
+        if c in ("'", '"'):
             quote_char = self.char()
             self.consume()
             yield (token_types.string, self.consume_string(quote_char))
             if self.char() == "#":
                 self.state = self.comment_state
             else:
                 self.state = self.line_end_state
-        elif self.char() == "@":
+        elif c == "@":
             self.consume()
             for _, value in self.value_inner_state():
                 yield token_types.atom, value
+        elif c == "[":
+            self.state = self.list_start_state
         else:
             self.state = self.value_inner_state
 
     def value_inner_state(self):
         rv = ""
         spaces = 0
         while True:
             c = self.char()
@@ -576,16 +580,19 @@ class Parser(object):
             self.list_value()
         elif self.token[0] == token_types.string:
             self.value()
         elif self.token[0] == token_types.group_start:
             self.consume()
             self.expression_values()
             if self.token[0] == token_types.string:
                 self.value()
+            elif self.token[0] == token_types.list_start:
+                self.consume()
+                self.list_value()
             self.eof_or_end_group()
         elif self.token[0] == token_types.atom:
             self.atom()
         else:
             raise ParseError(self.tokenizer.filename, self.tokenizer.line_number,
                              "Token '{}' is not a known type".format(self.token[0]))
 
     def list_value(self):
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_parser.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/tests/test_parser.py
@@ -102,11 +102,50 @@ key:
     def test_atom_0(self):
         with self.assertRaises(parser.ParseError):
             self.parse("key: @Unknown")
 
     def test_atom_1(self):
         with self.assertRaises(parser.ParseError):
             self.parse("key: @true")
 
+    def test_list_expr(self):
+        self.compare(
+            """
+key:
+  if x == 1: [a]
+  [b]""",
+            ["DataNode", None,
+             [["KeyValueNode", "key",
+               [["ConditionalNode", None,
+                 [["BinaryExpressionNode", None,
+                   [["BinaryOperatorNode", "==", []],
+                    ["VariableNode", "x", []],
+                       ["NumberNode", "1", []]
+                    ]],
+                     ["ListNode", None,
+                      [["ValueNode", "a", []]]],
+                  ]],
+                ["ListNode", None,
+                 [["ValueNode", "b", []]]]]]]])
+
+    def test_list_heading(self):
+        self.compare(
+            """
+key:
+  if x == 1: [a]
+[b]""",
+            ["DataNode", None,
+             [["KeyValueNode", "key",
+               [["ConditionalNode", None,
+                 [["BinaryExpressionNode", None,
+                   [["BinaryOperatorNode", "==", []],
+                    ["VariableNode", "x", []],
+                       ["NumberNode", "1", []]
+                    ]],
+                     ["ListNode", None,
+                      [["ValueNode", "a", []]]],
+                  ]]]],
+              ["DataNode", "b", []]]])
+
 
 if __name__ == "__main__":
     unittest.main()