def test_match_type_mixed(self): datatype = Union( str, # XXX add dedicated enums Enum(int, (1, 2, 3)), Basic, Array(str), Array(int), Union(int, bool), ) param = UnionParameter(datatype) tests = [ ('spam', SimpleParameter.HANDLER(str)), (2, EnumParameter.HANDLER(int, (1, 2, 3))), (BASIC_FULL, ComplexParameter(Basic).match_type(BASIC_FULL)), (['spam'], ArrayParameter.HANDLER(Array(str))), ([], ArrayParameter.HANDLER(Array(str))), ([10], ArrayParameter.HANDLER(Array(int))), (10, SimpleParameter.HANDLER(int)), (True, SimpleParameter.HANDLER(bool)), # no match (Integer(2), None), ([True], None), ({}, None), ] for value, expected in tests: with self.subTest(value): handler = param.match_type(value) self.assertEqual(handler, expected)
def test_supported(self): handler = DatatypeHandler(str) tests = [ (Parameter(str), Parameter(str)), (handler, Parameter(str, handler)), (Fields(Field('spam')), ComplexParameter(Fields(Field('spam')))), (Field('spam'), SimpleParameter(str)), (Field('spam', str, enum={'a'}), EnumParameter(str, {'a'})), (ANY, NoopParameter()), (None, SingletonParameter(None)), (str, SimpleParameter(str)), (int, SimpleParameter(int)), (bool, SimpleParameter(bool)), (Enum(str, {'a'}), EnumParameter(str, {'a'})), (Union(str, int), UnionParameter(Union(str, int))), ({str, int}, UnionParameter(Union(str, int))), (frozenset([str, int]), UnionParameter(Union(str, int))), (Array(str), ArrayParameter(Array(str))), ([str], ArrayParameter(Array(str))), ((str, ), ArrayParameter(Array(str))), (Basic, ComplexParameter(Basic)), ] for datatype, expected in tests: with self.subTest(datatype): param = param_from_datatype(datatype) self.assertEqual(param, expected)
def test_normalize_declarative(self): class Spam(FieldsNamespace): FIELDS = [ Field('a'), Field('b', bool), Field.START_OPTIONAL, Field('c', {int, str}), Field('d', [int]), Field('e', ANY), Field('f', '<ref>'), ] class Ham(FieldsNamespace): FIELDS = [ Field('w', Spam), Field('x', int), Field('y', frozenset({int, str})), Field('z', (int, )), ] class Eggs(FieldsNamespace): FIELDS = [ Field('b', [Ham]), Field('x', [{str, ('<ref>', )}], optional=True), Field('d', {Spam, '<ref>'}, optional=True), ] Eggs.normalize() self.assertEqual( Spam.FIELDS, Fields( Field('a'), Field('b', bool), Field('c', Union(int, str), optional=True), Field('d', Array(int), optional=True), Field('e', ANY, optional=True), Field('f', Spam, optional=True), )) self.assertEqual( Ham.FIELDS, Fields( Field('w', Spam), Field('x', int), Field('y', Union(int, str)), Field('z', Array(int)), )) self.assertEqual( Eggs.FIELDS, Fields( Field('b', Array(Ham)), Field('x', Array(Union.unordered(str, Array(Eggs))), optional=True), Field('d', Union.unordered(Spam, Eggs), optional=True), ))
def test_traverse_changed(self): calls = [] op = (lambda dt: calls.append(dt) or str) array = Array(ANY) transformed = array.traverse(op) self.assertIsNot(transformed, array) self.assertEqual(transformed, Array(str)) self.assertEqual(calls, [ ANY, ])
def test_match_type_match(self): param = ArrayParameter(Array(str)) expected = ArrayParameter.HANDLER(Array(str)) values = [ ['a', 'b', 'c'], [], ] for value in values: with self.subTest(value): handler = param.match_type(value) self.assertEqual(handler, expected)
def test_normalize_datatype(self): class Spam: @classmethod def normalize(cls): return OKAY OKAY = object() NOOP = object() param = SimpleParameter(str) tests = [ # explicitly handled (REF, TYPE_REFERENCE), (TYPE_REFERENCE, NOOP), (ANY, NOOP), (None, NOOP), (int, NOOP), (str, NOOP), (bool, NOOP), (Enum(str, ('spam', )), NOOP), (Union(str, int), NOOP), ({str, int}, Union(str, int)), (frozenset([str, int]), Union(str, int)), (Array(str), NOOP), ([str], Array(str)), ((str, ), Array(str)), (Mapping(str), NOOP), ({ str: str }, Mapping(str)), # others (Field('spam'), NOOP), (Fields(Field('spam')), NOOP), (param, NOOP), (DatatypeHandler(str), NOOP), (Arg(param, 'spam'), NOOP), (SimpleParameter(str), NOOP), (UnionParameter(Union(str)), NOOP), (ArrayParameter(Array(str)), NOOP), (ComplexParameter(Fields()), NOOP), (NOT_SET, NOOP), (object(), NOOP), (object, NOOP), (type, NOOP), (Spam, OKAY), ] for datatype, expected in tests: if expected is NOOP: expected = datatype with self.subTest(datatype): datatype = _normalize_datatype(datatype) self.assertEqual(datatype, expected)
def test_traverse_noop(self): calls = [] op = (lambda dt: calls.append(dt) or dt) array = Array(Union(str, int)) transformed = array.traverse(op) self.assertIs(transformed, array) self.assertCountEqual( calls, [ # Note that it did not recurse into Union(str, int). Union(str, int), ])
def test_traverse_noop(self): calls = [] op = (lambda dt: calls.append(dt) or dt) union = Union(str, Array(int), int) transformed = union.traverse(op) self.assertIs(transformed, union) self.assertCountEqual( calls, [ str, # Note that it did not recurse into Array(int). Array(int), int, ])
def test_transform_datatype_simple(self): datatypes = [ REF, TYPE_REFERENCE, ANY, None, int, str, bool, {str, int}, frozenset([str, int]), [str], (str, ), Parameter(object()), DatatypeHandler(str), Arg(SimpleParameter(str), 'spam'), SimpleParameter(str), UnionParameter(Union(str, int)), ArrayParameter(Array(str)), ComplexParameter(Fields()), NOT_SET, object(), object, type, ] for expected in datatypes: transformed = [] op = (lambda dt: transformed.append(dt) or dt) with self.subTest(expected): datatype = _transform_datatype(expected, op) self.assertIs(datatype, expected) self.assertEqual(transformed, [expected])
def test_normalized(self): tests = [ (REF, TYPE_REFERENCE), ({str, int}, Union(*{str, int})), (frozenset([str, int]), Union(*frozenset([str, int]))), ([str], Array(str)), ((str, ), Array(str)), ({ str: str }, Mapping(str)), (None, None), ] for datatype, expected in tests: with self.subTest(datatype): union = Union(int, datatype, str) self.assertEqual(union, Union(int, expected, str))
def test_normalize_with_op_changed(self): class Spam(FieldsNamespace): FIELDS = Fields(Field('spam', Array(ANY)), ) op = (lambda dt: int if dt is ANY else dt) Spam.normalize(op) self.assertEqual(Spam.FIELDS, Fields(Field('spam', Array(int)), ))
def test_normalized(self): tests = [ (REF, TYPE_REFERENCE), ({str, int}, Union(str, int)), (frozenset([str, int]), Union(str, int)), ([str], Array(str)), ((str, ), Array(str)), ({ str: str }, Mapping(str)), (None, None), ] for datatype, expected in tests: with self.subTest(datatype): field = Field('spam', datatype) self.assertEqual(field, Field('spam', expected))
def test_coerce_simple(self): param = ArrayParameter(Array(str)) values = [ ['a', 'b', 'c'], [], ] for value in values: with self.subTest(value): handler = param.match_type(value) coerced = handler.coerce(value) self.assertEqual(coerced, value)
def test_match_type_no_match(self): param = ArrayParameter(Array(str)) values = [ ['a', 1, 'c'], ('a', 'b', 'c'), 'spam', ] for value in values: with self.subTest(value): handler = param.match_type(value) self.assertIs(handler, None)
def test_as_dict(self): fields = Fields( Field('spam', int), Field('ham'), Field('eggs', Array(str)), ) result = fields.as_dict() self.assertEqual(result, { 'spam': fields[0], 'ham': fields[1], 'eggs': fields[2], })
def test_normalize_with_ops_noop(self): fieldlist = [ Field('spam'), Field('ham', int), Field('eggs', Array(ANY)), ] fields = Fields(*fieldlist) class Spam(FieldsNamespace): FIELDS = fields calls = [] op1 = (lambda dt: calls.append((op1, dt)) or dt) op2 = (lambda dt: calls.append((op2, dt)) or dt) Spam.normalize(op1, op2) self.assertIs(Spam.FIELDS, fields) for i, field in enumerate(Spam.FIELDS): self.assertIs(field, fieldlist[i]) self.maxDiff = None self.assertEqual(calls, [ (op1, fields), (op1, Field('spam')), (op1, str), (op1, Field('ham', int)), (op1, int), (op1, Field('eggs', Array(ANY))), (op1, Array(ANY)), (op1, ANY), (op2, fields), (op2, Field('spam')), (op2, str), (op2, Field('ham', int)), (op2, int), (op2, Field('eggs', Array(ANY))), (op2, Array(ANY)), (op2, ANY), ])
def test_normalized_transformed(self): calls = 0 class Spam: @classmethod def traverse(cls, op): nonlocal calls calls += 1 return cls array = Array(Spam) self.assertIs(array.itemtype, Spam) self.assertEqual(calls, 1)
def test_as_data_complicated(self): param = ArrayParameter(Array(Union(str, Basic))) value = [ 'a', BASIC_FULL, 'c', ] handler = param.match_type(value) data = handler.as_data([ 'a', Basic(name='spam', value='eggs'), 'c', ]) self.assertEqual(data, value)
def test_coerce_complicated(self): param = ArrayParameter(Array(Union(str, Basic))) value = [ 'a', BASIC_FULL, 'c', ] handler = param.match_type(value) coerced = handler.coerce(value) self.assertEqual(coerced, [ 'a', Basic(name='spam', value='eggs'), 'c', ])
def test_match_type(self): values = [ object(), '', 'spam', b'spam', 0, 10, 10.0, 10 + 0j, ('spam', ), (), ['spam'], [], { 'spam': 42 }, {}, {'spam'}, set(), object, type, NoopParameterTests, True, None, ..., NotImplemented, NOT_SET, ANY, Union(str, int), Union(), Array(str), Field('spam'), Fields(Field('spam')), Fields(), Basic, ] for value in values: with self.subTest(value): param = NoopParameter() handler = param.match_type(value) self.assertIs(type(handler), DatatypeHandler) self.assertIs(handler.datatype, ANY)
class Spam(FieldsNamespace): FIELDS = Fields(Field('spam', Array(ANY)), )
def test_validate(self): param = ArrayParameter(Array(str)) handler = param.match_type(['a', 'b', 'c']) handler.validate(['a', 'b', 'c'])
def test_as_data_simple(self): param = ArrayParameter(Array(str)) handler = param.match_type(['a', 'b', 'c']) data = handler.as_data(['a', 'b', 'c']) self.assertEqual(data, ['a', 'b', 'c'])
def test_transform_datatype_container(self): class Spam(FieldsNamespace): FIELDS = [Field('a'), Field('b', {str: str})] fields = Fields(Field('...')) field_spam = Field('spam', ANY) field_ham = Field('ham', Union(Array(Spam), )) field_eggs = Field('eggs', Array(TYPE_REFERENCE)) nested = Fields( Field('???', fields), field_spam, field_ham, field_eggs, ) tests = { Array(str): [ Array(str), str, ], Field('...'): [ Field('...'), str, ], fields: [ fields, Field('...'), str, ], nested: [ nested, # ... Field('???', fields), fields, Field('...'), str, # ... Field('spam', ANY), ANY, # ... field_ham, Union(Array(Spam)), Array(Spam), Spam, Field('a'), str, Field('b', Mapping(str)), Mapping(str), str, str, # ... field_eggs, Array(TYPE_REFERENCE), TYPE_REFERENCE, ], } self.maxDiff = None for datatype, expected in tests.items(): calls = [] op = (lambda dt: calls.append(dt) or dt) with self.subTest(datatype): transformed = _transform_datatype(datatype, op) self.assertIs(transformed, datatype) self.assertEqual(calls, expected) # Check Union separately due to set iteration order. calls = [] op = (lambda dt: calls.append(dt) or dt) datatype = Union(str, int) transformed = _transform_datatype(datatype, op) self.assertIs(transformed, datatype) self.assertEqual(calls[0], Union(str, int)) self.assertEqual(set(calls[1:]), {str, int})