diff options
Diffstat (limited to 'testing/web-platform/harness/wptrunner/wptmanifest/tests')
6 files changed, 925 insertions, 0 deletions
diff --git a/testing/web-platform/harness/wptrunner/wptmanifest/tests/__init__.py b/testing/web-platform/harness/wptrunner/wptmanifest/tests/__init__.py new file mode 100644 index 000000000..c580d191c --- /dev/null +++ b/testing/web-platform/harness/wptrunner/wptmanifest/tests/__init__.py @@ -0,0 +1,3 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_conditional.py b/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_conditional.py new file mode 100644 index 000000000..af18f4acc --- /dev/null +++ b/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_conditional.py @@ -0,0 +1,150 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +import unittest + +from cStringIO import StringIO + +from ..backends import conditional +from ..node import BinaryExpressionNode, BinaryOperatorNode, VariableNode, NumberNode + + +class TestConditional(unittest.TestCase): + def parse(self, input_str): + return self.parser.parse(StringIO(input_str)) + + def compile(self, input_text): + return conditional.compile(input_text) + + def test_get_0(self): + data = """ +key: value + +[Heading 1] + other_key: + if a == 1: value_1 + if a == 2: value_2 + value_3 +""" + + manifest = self.compile(data) + + self.assertEquals(manifest.get("key"), "value") + children = list(item for item in manifest.iterchildren()) + self.assertEquals(len(children), 1) + section = children[0] + self.assertEquals(section.name, "Heading 1") + + self.assertEquals(section.get("other_key", {"a": 1}), "value_1") + self.assertEquals(section.get("other_key", {"a": 2}), "value_2") + self.assertEquals(section.get("other_key", {"a": 7}), "value_3") + self.assertEquals(section.get("key"), "value") + + def test_get_1(self): + data = """ +key: value + +[Heading 1] + other_key: + if a == "1": value_1 + if a == 2: value_2 + value_3 +""" + + manifest = self.compile(data) + + children = list(item for item in manifest.iterchildren()) + section = children[0] + + self.assertEquals(section.get("other_key", {"a": "1"}), "value_1") + self.assertEquals(section.get("other_key", {"a": 1}), "value_3") + + def test_get_2(self): + data = """ +key: + if a[1] == "b": value_1 + if a[1] == 2: value_2 + value_3 +""" + + manifest = self.compile(data) + + self.assertEquals(manifest.get("key", {"a": "ab"}), "value_1") + self.assertEquals(manifest.get("key", {"a": [1, 2]}), "value_2") + + def test_get_3(self): + data = """ +key: + if a[1] == "ab"[1]: value_1 + if a[1] == 2: value_2 + value_3 +""" + + manifest = self.compile(data) + + self.assertEquals(manifest.get("key", {"a": "ab"}), "value_1") + self.assertEquals(manifest.get("key", {"a": [1, 2]}), "value_2") + + def test_set_0(self): + data = """ +key: + if a == "a": value_1 + if a == "b": value_2 + value_3 +""" + manifest = self.compile(data) + + manifest.set("new_key", "value_new") + + self.assertEquals(manifest.get("new_key"), "value_new") + + def test_set_1(self): + data = """ +key: + if a == "a": value_1 + if a == "b": value_2 + value_3 +""" + + manifest = self.compile(data) + + manifest.set("key", "value_new") + + self.assertEquals(manifest.get("key"), "value_new") + self.assertEquals(manifest.get("key", {"a": "a"}), "value_1") + + def test_set_2(self): + data = """ +key: + if a == "a": value_1 + if a == "b": value_2 + value_3 +""" + + manifest = self.compile(data) + + expr = BinaryExpressionNode(BinaryOperatorNode("=="), + VariableNode("a"), + NumberNode("1")) + + manifest.set("key", "value_new", expr) + + self.assertEquals(manifest.get("key", {"a": 1}), "value_new") + self.assertEquals(manifest.get("key", {"a": "a"}), "value_1") + + def test_api_0(self): + data = """ +key: + if a == 1.5: value_1 + value_2 +key_1: other_value +""" + manifest = self.compile(data) + + self.assertFalse(manifest.is_empty) + self.assertEquals(manifest.root, manifest) + self.assertTrue(manifest.has_key("key_1")) + self.assertFalse(manifest.has_key("key_2")) + + self.assertEquals(set(manifest.iterkeys()), set(["key", "key_1"])) diff --git a/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_parser.py b/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_parser.py new file mode 100644 index 000000000..6e8e6e6be --- /dev/null +++ b/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_parser.py @@ -0,0 +1,79 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +import unittest + +from cStringIO import StringIO + +from .. import parser + +# There aren't many tests here because it turns out to be way more convenient to +# use test_serializer for the majority of cases + + +class TestExpression(unittest.TestCase): + def setUp(self): + self.parser = parser.Parser() + + def parse(self, input_str): + return self.parser.parse(StringIO(input_str)) + + def compare(self, input_text, expected): + actual = self.parse(input_text) + self.match(expected, actual) + + def match(self, expected_node, actual_node): + self.assertEquals(expected_node[0], actual_node.__class__.__name__) + self.assertEquals(expected_node[1], actual_node.data) + self.assertEquals(len(expected_node[2]), len(actual_node.children)) + for expected_child, actual_child in zip(expected_node[2], actual_node.children): + self.match(expected_child, actual_child) + + def test_expr_0(self): + self.compare( + """ +key: + if x == 1 : value""", + ["DataNode", None, + [["KeyValueNode", "key", + [["ConditionalNode", None, + [["BinaryExpressionNode", None, + [["BinaryOperatorNode", "==", []], + ["VariableNode", "x", []], + ["NumberNode", "1", []] + ]], + ["ValueNode", "value", []], + ]]]]]] + ) + + def test_expr_1(self): + self.compare( + """ +key: + if not x and y : value""", + ["DataNode", None, + [["KeyValueNode", "key", + [["ConditionalNode", None, + [["BinaryExpressionNode", None, + [["BinaryOperatorNode", "and", []], + ["UnaryExpressionNode", None, + [["UnaryOperatorNode", "not", []], + ["VariableNode", "x", []] + ]], + ["VariableNode", "y", []] + ]], + ["ValueNode", "value", []], + ]]]]]] + ) + + 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") + +if __name__ == "__main__": + unittest.main() diff --git a/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_serializer.py b/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_serializer.py new file mode 100644 index 000000000..ec4d6e2d7 --- /dev/null +++ b/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_serializer.py @@ -0,0 +1,227 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +import unittest + +from cStringIO import StringIO + +from .. import parser, serializer + + +class TokenizerTest(unittest.TestCase): + def setUp(self): + self.serializer = serializer.ManifestSerializer() + self.parser = parser.Parser() + + def serialize(self, input_str): + return self.serializer.serialize(self.parser.parse(input_str)) + + def compare(self, input_str, expected=None): + if expected is None: + expected = input_str + expected = expected.encode("utf8") + actual = self.serialize(input_str) + self.assertEquals(actual, expected) + + def test_0(self): + self.compare("""key: value +[Heading 1] + other_key: other_value +""") + + def test_1(self): + self.compare("""key: value +[Heading 1] + other_key: + if a or b: other_value +""") + + def test_2(self): + self.compare("""key: value +[Heading 1] + other_key: + if a or b: other_value + fallback_value +""") + + def test_3(self): + self.compare("""key: value +[Heading 1] + other_key: + if a == 1: other_value + fallback_value +""") + + def test_4(self): + self.compare("""key: value +[Heading 1] + other_key: + if a == "1": other_value + fallback_value +""") + + def test_5(self): + self.compare("""key: value +[Heading 1] + other_key: + if a == "abc"[1]: other_value + fallback_value +""") + + def test_6(self): + self.compare("""key: value +[Heading 1] + other_key: + if a == "abc"[c]: other_value + fallback_value +""") + + def test_7(self): + self.compare("""key: value +[Heading 1] + other_key: + if (a or b) and c: other_value + fallback_value +""", +"""key: value +[Heading 1] + other_key: + if a or b and c: other_value + fallback_value +""") + + def test_8(self): + self.compare("""key: value +[Heading 1] + other_key: + if a or (b and c): other_value + fallback_value +""") + + def test_9(self): + self.compare("""key: value +[Heading 1] + other_key: + if not (a and b): other_value + fallback_value +""") + + def test_10(self): + self.compare("""key: value +[Heading 1] + some_key: some_value + +[Heading 2] + other_key: other_value +""") + + def test_11(self): + self.compare("""key: + if not a and b and c and d: true +""") + + def test_12(self): + self.compare("""[Heading 1] + key: [a:1, b:2] +""") + + def test_13(self): + self.compare("""key: [a:1, "b:#"] +""") + + def test_14(self): + self.compare("""key: [","] +""") + + def test_15(self): + self.compare("""key: , +""") + + def test_16(self): + self.compare("""key: ["]", b] +""") + + def test_17(self): + self.compare("""key: ] +""") + + def test_18(self): + self.compare("""key: \] + """, """key: ] +""") + + def test_escape_0(self): + self.compare(r"""k\t\:y: \a\b\f\n\r\t\v""", + r"""k\t\:y: \x07\x08\x0c\n\r\t\x0b +""") + + def test_escape_1(self): + self.compare(r"""k\x00: \x12A\x45""", + r"""k\x00: \x12AE +""") + + def test_escape_2(self): + self.compare(r"""k\u0045y: \u1234A\uABc6""", + u"""kEy: \u1234A\uabc6 +""") + + def test_escape_3(self): + self.compare(r"""k\u0045y: \u1234A\uABc6""", + u"""kEy: \u1234A\uabc6 +""") + + def test_escape_4(self): + self.compare(r"""key: '\u1234A\uABc6'""", + u"""key: \u1234A\uabc6 +""") + + def test_escape_5(self): + self.compare(r"""key: [\u1234A\uABc6]""", + u"""key: [\u1234A\uabc6] +""") + + def test_escape_6(self): + self.compare(r"""key: [\u1234A\uABc6\,]""", + u"""key: ["\u1234A\uabc6,"] +""") + + def test_escape_7(self): + self.compare(r"""key: [\,\]\#]""", + r"""key: [",]#"] +""") + + def test_escape_8(self): + self.compare(r"""key: \#""", + r"""key: "#" +""") + + def test_escape_9(self): + self.compare(r"""key: \U10FFFFabc""", + u"""key: \U0010FFFFabc +""") + + def test_escape_10(self): + self.compare(r"""key: \u10FFab""", + u"""key: \u10FFab +""") + + def test_escape_11(self): + self.compare(r"""key: \\ab +""") + + def test_atom_1(self): + self.compare(r"""key: @True +""") + + def test_atom_2(self): + self.compare(r"""key: @False +""") + + def test_atom_3(self): + self.compare(r"""key: @Reset +""") + + def test_atom_4(self): + self.compare(r"""key: [a, @Reset, b] +""") diff --git a/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_static.py b/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_static.py new file mode 100644 index 000000000..5bd270d9f --- /dev/null +++ b/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_static.py @@ -0,0 +1,105 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +import unittest + +from cStringIO import StringIO + +from ..backends import static + +# There aren't many tests here because it turns out to be way more convenient to +# use test_serializer for the majority of cases + + +class TestStatic(unittest.TestCase): + def parse(self, input_str): + return self.parser.parse(StringIO(input_str)) + + def compile(self, input_text, input_data): + return static.compile(input_text, input_data) + + def test_get_0(self): + data = """ +key: value + +[Heading 1] + other_key: + if a == 1: value_1 + if a == 2: value_2 + value_3 +""" + + manifest = self.compile(data, {"a": 2}) + + self.assertEquals(manifest.get("key"), "value") + children = list(item for item in manifest.iterchildren()) + self.assertEquals(len(children), 1) + section = children[0] + self.assertEquals(section.name, "Heading 1") + + self.assertEquals(section.get("other_key"), "value_2") + self.assertEquals(section.get("key"), "value") + + def test_get_1(self): + data = """ +key: value + +[Heading 1] + other_key: + if a == 1: value_1 + if a == 2: value_2 + value_3 +""" + manifest = self.compile(data, {"a": 3}) + + children = list(item for item in manifest.iterchildren()) + section = children[0] + self.assertEquals(section.get("other_key"), "value_3") + + def test_get_3(self): + data = """key: + if a == "1": value_1 + if a[0] == "ab"[0]: value_2 +""" + manifest = self.compile(data, {"a": "1"}) + self.assertEquals(manifest.get("key"), "value_1") + + manifest = self.compile(data, {"a": "ac"}) + self.assertEquals(manifest.get("key"), "value_2") + + def test_get_4(self): + data = """key: + if not a: value_1 + value_2 +""" + manifest = self.compile(data, {"a": True}) + self.assertEquals(manifest.get("key"), "value_2") + + manifest = self.compile(data, {"a": False}) + self.assertEquals(manifest.get("key"), "value_1") + + def test_api(self): + data = """key: + if a == 1.5: value_1 + value_2 +key_1: other_value +""" + manifest = self.compile(data, {"a": 1.5}) + + self.assertFalse(manifest.is_empty) + self.assertEquals(manifest.root, manifest) + self.assertTrue(manifest.has_key("key_1")) + self.assertFalse(manifest.has_key("key_2")) + + self.assertEquals(set(manifest.iterkeys()), set(["key", "key_1"])) + self.assertEquals(set(manifest.itervalues()), set(["value_1", "other_value"])) + + def test_is_empty_1(self): + data = """ +[Section] + [Subsection] +""" + manifest = self.compile(data, {}) + + self.assertTrue(manifest.is_empty) diff --git a/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_tokenizer.py b/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_tokenizer.py new file mode 100644 index 000000000..939567713 --- /dev/null +++ b/testing/web-platform/harness/wptrunner/wptmanifest/tests/test_tokenizer.py @@ -0,0 +1,361 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +import sys +import os +import unittest + +sys.path.insert(0, os.path.abspath("..")) +from cStringIO import StringIO + +from .. import parser +from ..parser import token_types + + +class TokenizerTest(unittest.TestCase): + def setUp(self): + self.tokenizer = parser.Tokenizer() + + def tokenize(self, input_str): + rv = [] + for item in self.tokenizer.tokenize(StringIO(input_str)): + rv.append(item) + if item[0] == token_types.eof: + break + return rv + + def compare(self, input_text, expected): + expected = expected + [(token_types.eof, None)] + actual = self.tokenize(input_text) + self.assertEquals(actual, expected) + + def test_heading_0(self): + self.compare("""[Heading text]""", + [(token_types.paren, "["), + (token_types.string, "Heading text"), + (token_types.paren, "]")]) + + def test_heading_1(self): + self.compare("""[Heading [text\]]""", + [(token_types.paren, "["), + (token_types.string, "Heading [text]"), + (token_types.paren, "]")]) + + def test_heading_2(self): + self.compare("""[Heading #text]""", + [(token_types.paren, "["), + (token_types.string, "Heading #text"), + (token_types.paren, "]")]) + + def test_heading_3(self): + self.compare("""[Heading [\]text]""", + [(token_types.paren, "["), + (token_types.string, "Heading []text"), + (token_types.paren, "]")]) + + def test_heading_4(self): + with self.assertRaises(parser.ParseError): + self.tokenize("[Heading") + + def test_heading_5(self): + self.compare("""[Heading [\]text] #comment""", + [(token_types.paren, "["), + (token_types.string, "Heading []text"), + (token_types.paren, "]")]) + + def test_heading_6(self): + self.compare(r"""[Heading \ttext]""", + [(token_types.paren, "["), + (token_types.string, "Heading \ttext"), + (token_types.paren, "]")]) + + def test_key_0(self): + self.compare("""key:value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_key_1(self): + self.compare("""key : value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_key_2(self): + self.compare("""key : val ue""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "val ue")]) + + def test_key_3(self): + self.compare("""key: value#comment""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_key_4(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""ke y: value""") + + def test_key_5(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""key""") + + def test_key_6(self): + self.compare("""key: "value\"""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_key_7(self): + self.compare("""key: 'value'""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_key_8(self): + self.compare("""key: "#value\"""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "#value")]) + + def test_key_9(self): + self.compare("""key: '#value\'""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, "#value")]) + + def test_key_10(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""key: "value""") + + def test_key_11(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""key: 'value""") + + def test_key_12(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""key: 'value""") + + def test_key_13(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""key: 'value' abc""") + + def test_key_14(self): + self.compare(r"""key: \\nb""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.string, r"\nb")]) + + def test_list_0(self): + self.compare( +""" +key: []""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.list_start, "["), + (token_types.list_end, "]")]) + + def test_list_1(self): + self.compare( +""" +key: [a, "b"]""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.list_start, "["), + (token_types.string, "a"), + (token_types.string, "b"), + (token_types.list_end, "]")]) + + def test_list_2(self): + self.compare( +""" +key: [a, + b]""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.list_start, "["), + (token_types.string, "a"), + (token_types.string, "b"), + (token_types.list_end, "]")]) + + def test_list_3(self): + self.compare( +""" +key: [a, #b] + c]""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.list_start, "["), + (token_types.string, "a"), + (token_types.string, "c"), + (token_types.list_end, "]")]) + + def test_list_4(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""key: [a #b] + c]""") + + def test_list_5(self): + with self.assertRaises(parser.ParseError): + self.tokenize("""key: [a \\ + c]""") + + def test_list_6(self): + self.compare( +"""key: [a , b]""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.list_start, "["), + (token_types.string, "a"), + (token_types.string, "b"), + (token_types.list_end, "]")]) + + def test_expr_0(self): + self.compare( +""" +key: + if cond == 1: value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.ident, "cond"), + (token_types.ident, "=="), + (token_types.number, "1"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_expr_1(self): + self.compare( +""" +key: + if cond == 1: value1 + value2""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.ident, "cond"), + (token_types.ident, "=="), + (token_types.number, "1"), + (token_types.separator, ":"), + (token_types.string, "value1"), + (token_types.string, "value2")]) + + def test_expr_2(self): + self.compare( +""" +key: + if cond=="1": value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.ident, "cond"), + (token_types.ident, "=="), + (token_types.string, "1"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_expr_3(self): + self.compare( +""" +key: + if cond==1.1: value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.ident, "cond"), + (token_types.ident, "=="), + (token_types.number, "1.1"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_expr_4(self): + self.compare( + """ +key: + if cond==1.1 and cond2 == "a": value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.ident, "cond"), + (token_types.ident, "=="), + (token_types.number, "1.1"), + (token_types.ident, "and"), + (token_types.ident, "cond2"), + (token_types.ident, "=="), + (token_types.string, "a"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_expr_5(self): + self.compare( +""" +key: + if (cond==1.1 ): value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.paren, "("), + (token_types.ident, "cond"), + (token_types.ident, "=="), + (token_types.number, "1.1"), + (token_types.paren, ")"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_expr_6(self): + self.compare( +""" +key: + if "\\ttest": value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.string, "\ttest"), + (token_types.separator, ":"), + (token_types.string, "value")]) + + def test_expr_7(self): + with self.assertRaises(parser.ParseError): + self.tokenize( +""" +key: + if 1A: value""") + + def test_expr_8(self): + with self.assertRaises(parser.ParseError): + self.tokenize( +""" +key: + if 1a: value""") + + def test_expr_9(self): + with self.assertRaises(parser.ParseError): + self.tokenize( +""" +key: + if 1.1.1: value""") + + def test_expr_10(self): + self.compare( +""" +key: + if 1.: value""", + [(token_types.string, "key"), + (token_types.separator, ":"), + (token_types.group_start, None), + (token_types.ident, "if"), + (token_types.number, "1."), + (token_types.separator, ":"), + (token_types.string, "value")]) + +if __name__ == "__main__": + unittest.main() |