class Ham(FieldsNamespace): FIELDS = [ Field('w', Spam), Field('x', int), Field('y', frozenset({int, str})), Field('z', (int, )), ]
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_traverse_changed(self): calls = [] op = (lambda dt: calls.append(dt) or str) field = Field('spam', ANY) transformed = field.traverse(op) self.assertIsNot(transformed, field) self.assertEqual(transformed, Field('spam', str)) self.assertEqual(calls, [ ANY, ])
def test_match_type_missing_optional(self): fields = Fields( Field('name'), Field.START_OPTIONAL, Field('value'), ) param = ComplexParameter(fields) handler = param.match_type({'name': 'spam'}) self.assertIs(type(handler), ComplexParameter.HANDLER) self.assertEqual(handler.datatype.FIELDS, fields) self.assertNotIn('value', handler.handlers)
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_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_traverse_noop(self): calls = [] op = (lambda dt: calls.append(dt) or dt) field = Field('spam', Union(str, int)) transformed = field.traverse(op) self.assertIs(transformed, field) self.assertCountEqual( calls, [ # Note that it did not recurse into Union(str, int). Union(str, int), ])
def test_normalize_unnormalized(self): fieldlist = [ Field('spam'), Field('ham'), Field('eggs'), ] class Spam(FieldsNamespace): FIELDS = fieldlist Spam.normalize() self.assertIsInstance(Spam.FIELDS, Fields) for i, field in enumerate(Spam.FIELDS): self.assertIs(field, fieldlist[i])
def test_normalize_without_ops(self): fieldlist = [ Field('spam'), Field('ham'), Field('eggs'), ] fields = Fields(*fieldlist) class Spam(FieldsNamespace): FIELDS = fields Spam.normalize() self.assertIs(Spam.FIELDS, fields) for i, field in enumerate(Spam.FIELDS): self.assertIs(field, fieldlist[i])
def test_defaults(self): field = Field('spam') self.assertEqual(field.name, 'spam') self.assertIs(field.datatype, str) self.assertIs(field.default, NOT_SET) self.assertFalse(field.optional)
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_with_START_OPTIONAL(self): fields = Fields( Field('spam'), Field('ham', optional=True), Field('eggs'), Field.START_OPTIONAL, Field('a'), Field('b', optional=False), ) self.assertEqual(fields, [ Field('spam'), Field('ham', optional=True), Field('eggs'), Field('a', optional=True), Field('b', optional=True), ])
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_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)
def test_traverse_changed(self): class Spam(FieldsNamespace): FIELDS = Fields( Field('spam', ANY), Field('eggs', None), ) calls = [] op = (lambda dt: calls.append(dt) or Field(dt.name, str)) transformed = Spam.traverse(op) self.assertIs(transformed, Spam) self.assertEqual(transformed.FIELDS, Fields( Field('spam', str), Field('eggs', str), )) self.assertEqual(calls, [ Field('spam', ANY), Field('eggs', None), ])
def test_traverse_noop(self): fields = [ Field('spam'), Field('ham'), Field('eggs'), ] class Spam(FieldsNamespace): FIELDS = Fields(*fields) calls = [] op = (lambda dt: calls.append(dt) or dt) transformed = Spam.traverse(op) self.assertIs(transformed, Spam) self.assertIs(transformed.FIELDS, Spam.FIELDS) for i, field in enumerate(Spam.FIELDS): self.assertIs(field, fields[i]) self.assertCountEqual( calls, [ # Note that it did not recurse into the fields. Field('spam'), Field('ham'), Field('eggs'), ])
def test_normalized_transformed(self): calls = 0 class Spam: @classmethod def traverse(cls, op): nonlocal calls calls += 1 return cls field = Field('spam', Spam) self.assertIs(field.datatype, Spam) self.assertEqual(calls, 1)
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>'), ]
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_multiple(self): fields = Fields( Field('spam'), Field('ham'), Field('eggs'), ) self.assertEqual(fields, [ Field('spam'), Field('ham'), Field('eggs'), ])
def test_traverse_changed(self): calls = [] op = (lambda dt: calls.append(dt) or Field(dt.name, str)) fields = Fields( Field('spam', ANY), Field('eggs', None), ) transformed = fields.traverse(op) self.assertIsNot(transformed, fields) self.assertEqual(transformed, Fields( Field('spam', str), Field('eggs', str), )) self.assertEqual(calls, [ Field('spam', ANY), Field('eggs', None), ])
def test_traverse_noop(self): calls = [] op = (lambda dt: calls.append(dt) or dt) fields = Fields( Field('spam'), Field('ham'), Field('eggs'), ) transformed = fields.traverse(op) self.assertIs(transformed, fields) self.assertCountEqual( calls, [ # Note that it did not recurse into the fields. Field('spam'), Field('ham'), Field('eggs'), ])
def test_traverse_unnormalized(self): fields = [ Field('spam'), Field('ham'), Field('eggs'), ] class Spam(FieldsNamespace): FIELDS = fields calls = [] op = (lambda dt: calls.append(dt) or dt) transformed = Spam.traverse(op) self.assertIs(transformed, Spam) self.assertIsInstance(transformed.FIELDS, Fields) for i, field in enumerate(Spam.FIELDS): self.assertIs(field, fields[i]) self.assertCountEqual(calls, [ Field('spam'), Field('ham'), Field('eggs'), ])
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})
class Spam(FieldsNamespace): PARAM_TYPE = Param FIELDS = [ Field('a'), ]
class Spam(FieldsNamespace): FIELDS = [ Field('a'), ]
def test_single(self): fields = Fields(Field('spam'), ) self.assertEqual(fields, [ Field('spam'), ])
class Spam(FieldsNamespace): FIELDS = Fields( Field('spam', ANY), Field('eggs', None), )
class Spam(FieldsNamespace): FIELDS = [Field('a'), Field('b', {str: str})]
def test_enum(self): field = Field('spam', str, enum=('a', 'b', 'c')) self.assertEqual(field.datatype, Enum(str, ('a', 'b', 'c')))