aboutsummaryrefslogtreecommitdiff
path: root/tests/test_cardinality.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_cardinality.py')
-rwxr-xr-xtests/test_cardinality.py556
1 files changed, 556 insertions, 0 deletions
diff --git a/tests/test_cardinality.py b/tests/test_cardinality.py
new file mode 100755
index 0000000..621e2e6
--- /dev/null
+++ b/tests/test_cardinality.py
@@ -0,0 +1,556 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Test suite to test the :mod:`parse_type.cardinality` module.
+"""
+
+from __future__ import absolute_import
+from .parse_type_test import ParseTypeTestCase, parse_number
+from parse_type import Cardinality, TypeBuilder, build_type_dict
+from parse import Parser
+import parse
+import unittest
+
+# -----------------------------------------------------------------------------
+# TEST CASE: TestCardinality
+# -----------------------------------------------------------------------------
+class TestCardinality(ParseTypeTestCase):
+
+ def test_enum_basics(self):
+ assert Cardinality.optional is Cardinality.zero_or_one
+ assert Cardinality.many0 is Cardinality.zero_or_more
+ assert Cardinality.many is Cardinality.one_or_more
+
+ def check_pattern_for_cardinality_one(self, pattern, new_pattern):
+ expected_pattern = Cardinality.one.make_pattern(pattern)
+ self.assertEqual(pattern, new_pattern)
+ self.assertEqual(new_pattern, expected_pattern)
+
+ def check_pattern_for_cardinality_zero_or_one(self, pattern, new_pattern):
+ expected_pattern = Cardinality.zero_or_one.schema % pattern
+ self.assertNotEqual(pattern, new_pattern)
+ self.assertEqual(new_pattern, expected_pattern)
+
+ def check_pattern_for_cardinality_zero_or_more(self, pattern, new_pattern):
+ expected_pattern = Cardinality.zero_or_more.make_pattern(pattern)
+ self.assertNotEqual(pattern, new_pattern)
+ self.assertEqual(new_pattern, expected_pattern)
+
+ def check_pattern_for_cardinality_one_or_more(self, pattern, new_pattern):
+ expected_pattern = Cardinality.one_or_more.make_pattern(pattern)
+ self.assertNotEqual(pattern, new_pattern)
+ self.assertEqual(new_pattern, expected_pattern)
+
+ def check_pattern_for_cardinality_optional(self, pattern, new_pattern):
+ expected = Cardinality.optional.make_pattern(pattern)
+ self.assertEqual(new_pattern, expected)
+ self.check_pattern_for_cardinality_zero_or_one(pattern, new_pattern)
+
+ def check_pattern_for_cardinality_many0(self, pattern, new_pattern):
+ expected = Cardinality.many0.make_pattern(pattern)
+ self.assertEqual(new_pattern, expected)
+ self.check_pattern_for_cardinality_zero_or_more(pattern, new_pattern)
+
+ def check_pattern_for_cardinality_many(self, pattern, new_pattern):
+ expected = Cardinality.many.make_pattern(pattern)
+ self.assertEqual(new_pattern, expected)
+ self.check_pattern_for_cardinality_one_or_more(pattern, new_pattern)
+
+ def test_make_pattern(self):
+ data = [
+ (Cardinality.one, r"\d+", r"\d+"),
+ (Cardinality.one, r"\w+", None),
+ (Cardinality.zero_or_one, r"\w+", None),
+ (Cardinality.one_or_more, r"\w+", None),
+ (Cardinality.optional, "XXX", Cardinality.zero_or_one.make_pattern("XXX")),
+ (Cardinality.many0, "XXX", Cardinality.zero_or_more.make_pattern("XXX")),
+ (Cardinality.many, "XXX", Cardinality.one_or_more.make_pattern("XXX")),
+ ]
+ for cardinality, pattern, expected_pattern in data:
+ if expected_pattern is None:
+ expected_pattern = cardinality.make_pattern(pattern)
+ new_pattern = cardinality.make_pattern(pattern)
+ self.assertEqual(new_pattern, expected_pattern)
+
+ name = cardinality.name
+ checker = getattr(self, "check_pattern_for_cardinality_%s" % name)
+ checker(pattern, new_pattern)
+
+ def test_make_pattern_for_zero_or_one(self):
+ patterns = [r"\d", r"\d+", r"\w+", r"XXX" ]
+ expecteds = [r"(\d)?", r"(\d+)?", r"(\w+)?", r"(XXX)?" ]
+ for pattern, expected in zip(patterns, expecteds):
+ new_pattern = Cardinality.zero_or_one.make_pattern(pattern)
+ self.assertEqual(new_pattern, expected)
+ self.check_pattern_for_cardinality_zero_or_one(pattern, new_pattern)
+
+ def test_make_pattern_for_zero_or_more(self):
+ pattern = "XXX"
+ expected = r"(XXX)?(\s*,\s*(XXX))*"
+ new_pattern = Cardinality.zero_or_more.make_pattern(pattern)
+ self.assertEqual(new_pattern, expected)
+ self.check_pattern_for_cardinality_zero_or_more(pattern, new_pattern)
+
+ def test_make_pattern_for_one_or_more(self):
+ pattern = "XXX"
+ expected = r"(XXX)(\s*,\s*(XXX))*"
+ new_pattern = Cardinality.one_or_more.make_pattern(pattern)
+ self.assertEqual(new_pattern, expected)
+ self.check_pattern_for_cardinality_one_or_more(pattern, new_pattern)
+
+ def test_is_many(self):
+ is_many_true_valueset = set(
+ [Cardinality.zero_or_more, Cardinality.one_or_more])
+
+ for cardinality in Cardinality:
+ expected = cardinality in is_many_true_valueset
+ self.assertEqual(cardinality.is_many(), expected)
+
+
+# -----------------------------------------------------------------------------
+# TEST CASE: CardinalityTypeBuilderTest
+# -----------------------------------------------------------------------------
+class CardinalityTypeBuilderTest(ParseTypeTestCase):
+
+ def check_parse_number_with_zero_or_one(self, parse_candidate,
+ type_name="OptionalNumber"):
+ schema = "Optional: {number:%s}" % type_name
+ type_dict = {
+ "Number": parse_number,
+ type_name: parse_candidate,
+ }
+ parser = parse.Parser(schema, type_dict)
+
+ # -- PERFORM TESTS:
+ self.assert_match(parser, "Optional: ", "number", None)
+ self.assert_match(parser, "Optional: 1", "number", 1)
+ self.assert_match(parser, "Optional: 42", "number", 42)
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "Optional: x", "number") # Not a Number.
+ self.assert_mismatch(parser, "Optional: -1", "number") # Negative.
+ self.assert_mismatch(parser, "Optional: a, b", "number") # List of ...
+
+ def check_parse_number_with_optional(self, parse_candidate,
+ type_name="OptionalNumber"):
+ self.check_parse_number_with_zero_or_one(parse_candidate, type_name)
+
+ def check_parse_number_with_zero_or_more(self, parse_candidate,
+ type_name="Numbers0"):
+ schema = "List: {numbers:%s}" % type_name
+ type_dict = {
+ type_name: parse_candidate,
+ }
+ parser = parse.Parser(schema, type_dict)
+
+ # -- PERFORM TESTS:
+ self.assert_match(parser, "List: ", "numbers", [ ])
+ self.assert_match(parser, "List: 1", "numbers", [ 1 ])
+ self.assert_match(parser, "List: 1, 2", "numbers", [ 1, 2 ])
+ self.assert_match(parser, "List: 1, 2, 3", "numbers", [ 1, 2, 3 ])
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "List: x", "numbers") # Not a Number.
+ self.assert_mismatch(parser, "List: -1", "numbers") # Negative.
+ self.assert_mismatch(parser, "List: 1,", "numbers") # Trailing sep.
+ self.assert_mismatch(parser, "List: a, b", "numbers") # List of ...
+
+ def check_parse_number_with_one_or_more(self, parse_candidate,
+ type_name="Numbers"):
+ schema = "List: {numbers:%s}" % type_name
+ type_dict = {
+ "Number": parse_number,
+ type_name: parse_candidate,
+ }
+ parser = parse.Parser(schema, type_dict)
+
+ # -- PERFORM TESTS:
+ self.assert_match(parser, "List: 1", "numbers", [ 1 ])
+ self.assert_match(parser, "List: 1, 2", "numbers", [ 1, 2 ])
+ self.assert_match(parser, "List: 1, 2, 3", "numbers", [ 1, 2, 3 ])
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "List: ", "numbers") # Zero items.
+ self.assert_mismatch(parser, "List: x", "numbers") # Not a Number.
+ self.assert_mismatch(parser, "List: -1", "numbers") # Negative.
+ self.assert_mismatch(parser, "List: 1,", "numbers") # Trailing sep.
+ self.assert_mismatch(parser, "List: a, b", "numbers") # List of ...
+
+ def check_parse_choice_with_optional(self, parse_candidate):
+ # Choice (["red", "green", "blue"])
+ schema = "Optional: {color:OptionalChoiceColor}"
+ parser = parse.Parser(schema, dict(OptionalChoiceColor=parse_candidate))
+
+ # -- PERFORM TESTS:
+ self.assert_match(parser, "Optional: ", "color", None)
+ self.assert_match(parser, "Optional: red", "color", "red")
+ self.assert_match(parser, "Optional: green", "color", "green")
+ self.assert_match(parser, "Optional: blue", "color", "blue")
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "Optional: r", "color") # Not a Color.
+ self.assert_mismatch(parser, "Optional: redx", "color") # Similar.
+ self.assert_mismatch(parser, "Optional: red, blue", "color") # List of ...
+
+
+ def check_parse_number_with_many(self, parse_candidate, type_name="Numbers"):
+ self.check_parse_number_with_one_or_more(parse_candidate, type_name)
+
+ def check_parse_number_with_many0(self, parse_candidate,
+ type_name="Numbers0"):
+ self.check_parse_number_with_zero_or_more(parse_candidate, type_name)
+
+
+# -----------------------------------------------------------------------------
+# TEST CASE: TestTypeBuilder4Cardinality
+# -----------------------------------------------------------------------------
+class TestTypeBuilder4Cardinality(CardinalityTypeBuilderTest):
+
+ def test_with_zero_or_one_basics(self):
+ parse_opt_number = TypeBuilder.with_zero_or_one(parse_number)
+ self.assertEqual(parse_opt_number.pattern, r"(\d+)?")
+
+ def test_with_zero_or_one__number(self):
+ parse_opt_number = TypeBuilder.with_zero_or_one(parse_number)
+ self.check_parse_number_with_zero_or_one(parse_opt_number)
+
+ def test_with_optional__number(self):
+ # -- ALIAS FOR: zero_or_one
+ parse_opt_number = TypeBuilder.with_optional(parse_number)
+ self.check_parse_number_with_optional(parse_opt_number)
+
+ def test_with_optional__choice(self):
+ # -- ALIAS FOR: zero_or_one
+ parse_color = TypeBuilder.make_choice(["red", "green", "blue"])
+ parse_opt_color = TypeBuilder.with_optional(parse_color)
+ self.check_parse_choice_with_optional(parse_opt_color)
+
+ def test_with_zero_or_more_basics(self):
+ parse_numbers = TypeBuilder.with_zero_or_more(parse_number)
+ self.assertEqual(parse_numbers.pattern, r"(\d+)?(\s*,\s*(\d+))*")
+
+ def test_with_zero_or_more__number(self):
+ parse_numbers = TypeBuilder.with_zero_or_more(parse_number)
+ self.check_parse_number_with_zero_or_more(parse_numbers)
+
+ def test_with_zero_or_more__choice(self):
+ parse_color = TypeBuilder.make_choice(["red", "green", "blue"])
+ parse_colors = TypeBuilder.with_zero_or_more(parse_color)
+ parse_colors.name = "Colors0"
+
+ extra_types = build_type_dict([ parse_colors ])
+ schema = "List: {colors:Colors0}"
+ parser = parse.Parser(schema, extra_types)
+
+ # -- PERFORM TESTS:
+ self.assert_match(parser, "List: ", "colors", [ ])
+ self.assert_match(parser, "List: green", "colors", [ "green" ])
+ self.assert_match(parser, "List: red, green", "colors", [ "red", "green" ])
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "List: x", "colors") # Not a Color.
+ self.assert_mismatch(parser, "List: black", "colors") # Unknown
+ self.assert_mismatch(parser, "List: red,", "colors") # Trailing sep.
+ self.assert_mismatch(parser, "List: a, b", "colors") # List of ...
+
+ def test_with_one_or_more_basics(self):
+ parse_numbers = TypeBuilder.with_one_or_more(parse_number)
+ self.assertEqual(parse_numbers.pattern, r"(\d+)(\s*,\s*(\d+))*")
+
+ def test_with_one_or_more_basics_with_other_separator(self):
+ parse_numbers2 = TypeBuilder.with_one_or_more(parse_number, listsep=';')
+ self.assertEqual(parse_numbers2.pattern, r"(\d+)(\s*;\s*(\d+))*")
+
+ parse_numbers2 = TypeBuilder.with_one_or_more(parse_number, listsep=':')
+ self.assertEqual(parse_numbers2.pattern, r"(\d+)(\s*:\s*(\d+))*")
+
+ def test_with_one_or_more(self):
+ parse_numbers = TypeBuilder.with_one_or_more(parse_number)
+ self.check_parse_number_with_one_or_more(parse_numbers)
+
+ def test_with_many(self):
+ # -- ALIAS FOR: one_or_more
+ parse_numbers = TypeBuilder.with_many(parse_number)
+ self.check_parse_number_with_many(parse_numbers)
+
+ def test_with_many0(self):
+ # -- ALIAS FOR: one_or_more
+ parse_numbers = TypeBuilder.with_many0(parse_number)
+ self.check_parse_number_with_many0(parse_numbers)
+
+ def test_with_one_or_more_choice(self):
+ parse_color = TypeBuilder.make_choice(["red", "green", "blue"])
+ parse_colors = TypeBuilder.with_one_or_more(parse_color)
+ parse_colors.name = "Colors"
+
+ extra_types = build_type_dict([ parse_colors ])
+ schema = "List: {colors:Colors}"
+ parser = parse.Parser(schema, extra_types)
+
+ # -- PERFORM TESTS:
+ self.assert_match(parser, "List: green", "colors", [ "green" ])
+ self.assert_match(parser, "List: red, green", "colors", [ "red", "green" ])
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "List: ", "colors") # Zero items.
+ self.assert_mismatch(parser, "List: x", "colors") # Not a Color.
+ self.assert_mismatch(parser, "List: black", "colors") # Unknown
+ self.assert_mismatch(parser, "List: red,", "colors") # Trailing sep.
+ self.assert_mismatch(parser, "List: a, b", "colors") # List of ...
+
+ def test_with_one_or_more_enum(self):
+ parse_color = TypeBuilder.make_enum({"red": 1, "green":2, "blue": 3})
+ parse_colors = TypeBuilder.with_one_or_more(parse_color)
+ parse_colors.name = "Colors"
+
+ extra_types = build_type_dict([ parse_colors ])
+ schema = "List: {colors:Colors}"
+ parser = parse.Parser(schema, extra_types)
+
+ # -- PERFORM TESTS:
+ self.assert_match(parser, "List: green", "colors", [ 2 ])
+ self.assert_match(parser, "List: red, green", "colors", [ 1, 2 ])
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "List: ", "colors") # Zero items.
+ self.assert_mismatch(parser, "List: x", "colors") # Not a Color.
+ self.assert_mismatch(parser, "List: black", "colors") # Unknown
+ self.assert_mismatch(parser, "List: red,", "colors") # Trailing sep.
+ self.assert_mismatch(parser, "List: a, b", "colors") # List of ...
+
+ def test_with_one_or_more_with_other_separator(self):
+ parse_numbers2 = TypeBuilder.with_one_or_more(parse_number, listsep=';')
+ parse_numbers2.name = "Numbers2"
+
+ extra_types = build_type_dict([ parse_numbers2 ])
+ schema = "List: {numbers:Numbers2}"
+ parser = parse.Parser(schema, extra_types)
+
+ # -- PERFORM TESTS:
+ self.assert_match(parser, "List: 1", "numbers", [ 1 ])
+ self.assert_match(parser, "List: 1; 2", "numbers", [ 1, 2 ])
+ self.assert_match(parser, "List: 1; 2; 3", "numbers", [ 1, 2, 3 ])
+
+ def test_with_cardinality_one(self):
+ parse_number2 = TypeBuilder.with_cardinality(Cardinality.one, parse_number)
+ assert parse_number2 is parse_number
+
+ def test_with_cardinality_zero_or_one(self):
+ parse_opt_number = TypeBuilder.with_cardinality(
+ Cardinality.zero_or_one, parse_number)
+ self.check_parse_number_with_zero_or_one(parse_opt_number)
+
+ def test_with_cardinality_zero_or_more(self):
+ parse_many0_numbers = TypeBuilder.with_cardinality(
+ Cardinality.zero_or_more, parse_number)
+ self.check_parse_number_with_zero_or_more(parse_many0_numbers)
+
+ def test_with_cardinality_one_or_more(self):
+ parse_many_numbers = TypeBuilder.with_cardinality(
+ Cardinality.one_or_more, parse_number)
+ self.check_parse_number_with_one_or_more(parse_many_numbers)
+
+ def test_with_cardinality_optional(self):
+ parse_opt_number = TypeBuilder.with_cardinality(
+ Cardinality.optional, parse_number)
+ self.check_parse_number_with_optional(parse_opt_number)
+
+ def test_with_cardinality_many0(self):
+ parse_many0_numbers = TypeBuilder.with_cardinality(
+ Cardinality.many0, parse_number)
+ self.check_parse_number_with_zero_or_more(parse_many0_numbers)
+
+ def test_with_cardinality_many(self):
+ parse_many_numbers = TypeBuilder.with_cardinality(
+ Cardinality.many, parse_number)
+ self.check_parse_number_with_many(parse_many_numbers)
+
+ def test_parse_with_optional_and_named_fields(self):
+ parse_opt_number = TypeBuilder.with_optional(parse_number)
+ parse_opt_number.name = "Number?"
+
+ type_dict = build_type_dict([parse_opt_number, parse_number])
+ schema = "Numbers: {number1:Number?} {number2:Number}"
+ parser = parse.Parser(schema, type_dict)
+
+ # -- CASE: Optional number is present
+ result = parser.parse("Numbers: 34 12")
+ expected = dict(number1=34, number2=12)
+ self.assertIsNotNone(result)
+ self.assertEqual(result.named, expected)
+
+ # -- CASE: Optional number is missing
+ result = parser.parse("Numbers: 12")
+ expected = dict(number1=None, number2=12)
+ self.assertIsNotNone(result)
+ self.assertEqual(result.named, expected)
+
+ def test_parse_with_optional_and_unnamed_fields(self):
+ # -- ENSURE: Cardinality.optional.group_count is correct
+ # REQUIRES: Parser := parse_type.Parser with group_count support
+ parse_opt_number = TypeBuilder.with_optional(parse_number)
+ parse_opt_number.name = "Number?"
+
+ type_dict = build_type_dict([parse_opt_number, parse_number])
+ schema = "Numbers: {:Number?} {:Number}"
+ parser = Parser(schema, type_dict)
+
+ # -- CASE: Optional number is present
+ result = parser.parse("Numbers: 34 12")
+ expected = (34, 12)
+ self.assertIsNotNone(result)
+ self.assertEqual(result.fixed, tuple(expected))
+
+ # -- CASE: Optional number is missing
+ result = parser.parse("Numbers: 12")
+ expected = (None, 12)
+ self.assertIsNotNone(result)
+ self.assertEqual(result.fixed, tuple(expected))
+
+ def test_parse_with_many_and_unnamed_fields(self):
+ # -- ENSURE: Cardinality.one_or_more.group_count is correct
+ # REQUIRES: Parser := parse_type.Parser with group_count support
+ parse_many_numbers = TypeBuilder.with_many(parse_number)
+ parse_many_numbers.name = "Number+"
+
+ type_dict = build_type_dict([parse_many_numbers, parse_number])
+ schema = "Numbers: {:Number+} {:Number}"
+ parser = Parser(schema, type_dict)
+
+ # -- CASE:
+ result = parser.parse("Numbers: 1, 2, 3 42")
+ expected = ([1, 2, 3], 42)
+ self.assertIsNotNone(result)
+ self.assertEqual(result.fixed, tuple(expected))
+
+ result = parser.parse("Numbers: 3 43")
+ expected = ([ 3 ], 43)
+ self.assertIsNotNone(result)
+ self.assertEqual(result.fixed, tuple(expected))
+
+ def test_parse_with_many0_and_unnamed_fields(self):
+ # -- ENSURE: Cardinality.zero_or_more.group_count is correct
+ # REQUIRES: Parser := parse_type.Parser with group_count support
+ parse_many0_numbers = TypeBuilder.with_many0(parse_number)
+ parse_many0_numbers.name = "Number*"
+
+ type_dict = build_type_dict([parse_many0_numbers, parse_number])
+ schema = "Numbers: {:Number*} {:Number}"
+ parser = Parser(schema, type_dict)
+
+ # -- CASE: Optional numbers are present
+ result = parser.parse("Numbers: 1, 2, 3 42")
+ expected = ([1, 2, 3], 42)
+ self.assertIsNotNone(result)
+ self.assertEqual(result.fixed, tuple(expected))
+
+ # -- CASE: Optional numbers are missing := EMPTY-LIST
+ result = parser.parse("Numbers: 43")
+ expected = ([ ], 43)
+ self.assertIsNotNone(result)
+ self.assertEqual(result.fixed, tuple(expected))
+
+
+# class TestParserWithManyTypedFields(ParseTypeTestCase):
+
+ #parse_variant1 = TypeBuilder.make_variant([parse_number, parse_yesno])
+ #parse_variant1.name = "Number_or_YesNo"
+ #parse_variant2 = TypeBuilder.make_variant([parse_color, parse_person_choice])
+ #parse_variant2.name = "Color_or_PersonChoice"
+ #TYPE_CONVERTERS = [
+ # parse_number,
+ # parse_yesno,
+ # parse_color,
+ # parse_person_choice,
+ # parse_variant1,
+ # parse_variant2,
+ #]
+ #
+# def test_parse_with_many_named_fields(self):
+# type_dict = build_type_dict(self.TYPE_CONVERTERS)
+# schema = """\
+#Number: {number:Number}
+#YesNo: {answer:YesNo}
+#Color: {color:Color}
+#Person: {person:PersonChoice}
+#Variant1: {variant1:Number_or_YesNo}
+#Variant2: {variant2:Color_or_PersonChoice}
+#"""
+# parser = parse.Parser(schema, type_dict)
+#
+# text = """\
+#Number: 12
+#YesNo: yes
+#Color: red
+#Person: Alice
+#Variant1: 42
+#Variant2: Bob
+#"""
+# expected = dict(
+# number=12,
+# answer=True,
+# color=Color.red,
+# person="Alice",
+# variant1=42,
+# variant2="Bob"
+# )
+#
+# result = parser.parse(text)
+# self.assertIsNotNone(result)
+# self.assertEqual(result.named, expected)
+
+# def test_parse_with_many_unnamed_fields(self):
+# type_dict = build_type_dict(self.TYPE_CONVERTERS)
+# schema = """\
+#Number: {:Number}
+#YesNo: {:YesNo}
+#Color: {:Color}
+#Person: {:PersonChoice}
+#"""
+# # -- OMIT: XFAIL, due to group_index delta counting => Parser problem.
+# # Variant2: {:Color_or_PersonChoice}
+# # Variant1: {:Number_or_YesNo}
+# parser = parse.Parser(schema, type_dict)
+#
+# text = """\
+#Number: 12
+#YesNo: yes
+#Color: red
+#Person: Alice
+#"""
+# # SKIP: Variant2: Bob
+# # SKIP: Variant1: 42
+# expected = [ 12, True, Color.red, "Alice", ] # -- SKIP: "Bob", 42 ]
+#
+# result = parser.parse(text)
+# self.assertIsNotNone(result)
+# self.assertEqual(result.fixed, tuple(expected))
+
+
+
+# -----------------------------------------------------------------------------
+# MAIN:
+# -----------------------------------------------------------------------------
+if __name__ == '__main__':
+ unittest.main()
+
+
+# Copyright (c) 2012-2013 by Jens Engel (https://github/jenisys/parse_type)
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.