def test_next_node_when_given_qname_matches_dataclass_var( self, mock_ctx_fetch, mock_element_xsi_type): ele = Element("a") ctx = XmlContext() cfg = ParserConfig() var = XmlElement(name="a", qname=QName("a"), types=[Foo], dataclass=True) meta = XmlMeta( name="foo", clazz=None, qname=QName("foo"), source_qname=QName("foo"), nillable=False, vars=[var], ) xsi_type = QName("foo") namespace = meta.qname.namespace mock_ctx_fetch.return_value = replace(meta) mock_element_xsi_type.return_value = xsi_type node = ElementNode(position=0, meta=meta, config=cfg) actual = node.next_node(ele, 10, ctx) self.assertIsInstance(actual, ElementNode) self.assertEqual(10, actual.position) self.assertIs(mock_ctx_fetch.return_value, actual.meta) mock_ctx_fetch.assert_called_once_with(var.clazz, namespace, xsi_type)
def test_bind_with_mixed_flag_true( self, mock_bind_attrs, mock_bind_content, mock_bind_objects ): mock_bind_attrs.side_effect = add_attr mock_bind_content.side_effect = add_text mock_bind_objects.side_effect = add_child node = ElementNode( position=0, meta=self.context.build(Foo), context=self.context, config=ParserConfig(), attrs={"a": "b"}, ns_map={"ns0": "xsdata"}, mixed=True, ) objects = [] self.assertTrue(node.bind("foo", "text", " ", objects)) self.assertEqual(1, len(objects)) objects = [] self.assertTrue(node.bind("foo", "text", " tail ", objects)) self.assertEqual(2, len(objects)) self.assertEqual(None, objects[-1][0]) self.assertEqual(" tail ", objects[-1][1])
def test_bind( self, mock_bind_attrs, mock_bind_content, mock_bind_wild_content, mock_bind_objects, ): mock_bind_attrs.side_effect = add_attr mock_bind_content.side_effect = add_text mock_bind_objects.side_effect = add_child node = ElementNode( position=0, meta=self.context.build(Foo), context=self.context, config=ParserConfig(), attrs={"a": "b"}, ns_map={"ns0": "xsdata"}, ) objects = [1, 2, 3] self.assertTrue(node.bind("foo", "text", "tail", objects)) self.assertEqual("foo", objects[-1][0]) self.assertEqual(Foo(1, 2, 3), objects[-1][1]) mock_bind_attrs.assert_called_once_with( mock.ANY, node.meta, node.attrs, node.ns_map ) mock_bind_content.assert_called_once_with( mock.ANY, node.meta, "text", node.ns_map ) mock_bind_objects.assert_called_once_with(mock.ANY, node.meta, 0, objects) self.assertEqual(0, mock_bind_wild_content.call_count)
def setUp(self) -> None: super().setUp() self.context = XmlContext() self.meta = XmlMeta(clazz=Foo, qname="foo", source_qname="foo", nillable=False) self.node = ElementNode( position=0, meta=self.meta, context=self.context, config=ParserConfig(), attrs={}, ns_map={}, )
def test_next_node_when_config_fail_on_unknown_properties_is_false(self): ele = Element("nope") ctx = XmlContext() cfg = ParserConfig(fail_on_unknown_properties=False) meta = XmlMeta( name="foo", clazz=None, qname=QName("foo"), source_qname=QName("foo"), nillable=False, ) node = ElementNode(position=0, meta=meta, config=cfg) actual = node.next_node(ele, 10, ctx) self.assertEqual(SkipNode(position=10), actual)
def test_start_with_undefined_class(self): parser = self.parser queue = [] objects = [] attrs = {"k": "v"} ns_map = {"a": "b"} expected_node = ElementNode( position=0, context=parser.context, meta=parser.context.build(Books), config=parser.config, attrs=attrs, ns_map=ns_map, ) parser.start(None, queue, objects, "{urn:books}books", attrs, ns_map) self.assertEqual(1, len(queue)) self.assertEqual(expected_node, queue[0]) with self.assertRaises(ParserError) as cm: parser.start(None, [], [], "{unknown}hopefully", {}, {}) self.assertEqual( "No class found matching root: {unknown}hopefully", str(cm.exception) )
def test_start(self): queue = [] objects = [] attrs = {"k": "v"} ns_map = {"a": "b"} expected_node = ElementNode( position=0, context=self.parser.context, meta=self.parser.context.build(Books), config=self.parser.config, attrs=attrs, ns_map=ns_map, ) self.parser.start(Books, queue, objects, "{urn:books}books", attrs, ns_map) self.assertEqual(1, len(queue)) self.assertEqual(expected_node, queue[0]) expected_node = replace( expected_node, meta=self.parser.context.build(BookForm), attrs={}, ns_map={} ) self.parser.start(Books, queue, objects, "book", {}, {}) self.assertEqual(2, len(queue)) self.assertEqual(expected_node, queue[-1])
def test_bind_with_derived_element(self): a = make_dataclass("A", fields=[]) node = ElementNode( position=0, meta=self.context.build(a), context=self.context, config=ParserConfig(), attrs={}, ns_map={}, derived=True, ) objects = [] self.assertTrue(node.bind("foo", None, None, objects)) self.assertEqual("foo", objects[-1][0]) self.assertEqual(DerivedElement("foo", a()), objects[-1][1])
def test_parse_element( self, mock_bind_element_attrs, mock_bind_element_text, mock_bind_element_children, mock_bind_element_wild_text, ): def add_attr(x, *args): x["a"] = 1 def add_text(x, *args): x["b"] = 2 def add_child(x, *args): x["c"] = 3 def add_wild_text(x, *args): x["d"] = 4 mock_bind_element_attrs.side_effect = add_attr mock_bind_element_text.side_effect = add_text mock_bind_element_children.side_effect = add_child mock_bind_element_wild_text.side_effect = add_wild_text ctx = XmlContext() meta = ctx.build(Foo) ele = Element("foo") pool = [1, 2, 3] node = ElementNode(position=0, meta=meta, default=None, config=ParserConfig()) qname, obj = node.parse_element(ele, pool) self.assertEqual(QName(ele.tag), qname) self.assertEqual(Foo(1, 2, 3, 4), obj) mock_bind_element_attrs.assert_called_once_with(mock.ANY, meta, ele) mock_bind_element_text.assert_called_once_with(mock.ANY, meta, ele) mock_bind_element_children.assert_called_once_with( mock.ANY, meta, 0, pool) mock_bind_element_wild_text.assert_called_once_with( mock.ANY, meta, ele)
def test_next_node_when_given_qname_does_not_match_any_var(self): ele = Element("nope") ctx = XmlContext() cfg = ParserConfig() meta = XmlMeta( name="foo", clazz=None, qname=QName("foo"), source_qname=QName("foo"), nillable=False, ) node = ElementNode(position=0, meta=meta, config=cfg) with self.assertRaises(XmlContextError) as cm: node.next_node(ele, 10, ctx) self.assertEqual("foo does not support mixed content: nope", str(cm.exception))
def test_next_node_when_given_qname_matches_primitive_var(self): ele = Element("a") ctx = XmlContext() cfg = ParserConfig() var = XmlText(name="a", qname=QName("a"), types=[int], default=100) meta = XmlMeta( name="foo", clazz=None, qname=QName("foo"), source_qname=QName("foo"), nillable=False, vars=[var], ) node = ElementNode(position=0, meta=meta, config=cfg) actual = node.next_node(ele, 10, ctx) self.assertIsInstance(actual, PrimitiveNode) self.assertEqual(10, actual.position) self.assertEqual(var, actual.var)
def test_next_node_when_given_qname_matches_any_element_var(self): ele = Element("a") ctx = XmlContext() cfg = ParserConfig() var = XmlWildcard(name="a", qname=QName("a"), types=[], dataclass=False) meta = XmlMeta( name="foo", clazz=None, qname=QName("foo"), source_qname=QName("foo"), nillable=False, vars=[var], ) node = ElementNode(position=0, meta=meta, config=cfg) actual = node.next_node(ele, 10, ctx) self.assertIsInstance(actual, WildcardNode) self.assertEqual(10, actual.position) self.assertEqual(var.qname, actual.qname)
def test_bind_with_wildcard_var( self, mock_bind_attrs, mock_bind_content, mock_bind_wild_content, mock_bind_objects, mock_find_var, ): mock_bind_attrs.side_effect = add_attr mock_bind_content.return_value = False mock_bind_wild_content.side_effect = add_text mock_bind_objects.side_effect = add_child mock_find_var.return_value = XmlVar(wildcard=True, qname="b", name="b") node = ElementNode( position=0, meta=self.context.build(Foo), context=self.context, config=ParserConfig(), attrs={"a": "b"}, ns_map={"ns0": "xsdata"}, ) objects = [1, 2, 3] self.assertTrue(node.bind("foo", "text", "tail", objects)) self.assertEqual("foo", objects[-1][0]) self.assertEqual(Foo(1, 2, 3), objects[-1][1]) mock_bind_attrs.assert_called_once_with( mock.ANY, node.meta, node.attrs, node.ns_map ) mock_bind_content.assert_called_once_with( mock.ANY, node.meta, "text", node.ns_map ) mock_bind_objects.assert_called_once_with(mock.ANY, node.meta, 0, objects)
def test_start_with_any_type_root(self): parser = self.parser queue = [] objects = [] attrs = {QNames.XSI_TYPE: "bk:books"} ns_map = {"bk": "urn:books", "xsi": Namespace.XSI.uri} expected_node = ElementNode( position=0, context=parser.context, meta=parser.context.build(Books), config=parser.config, attrs=attrs, ns_map=ns_map, derived=True, ) parser.start(None, queue, objects, "doc", attrs, ns_map) self.assertEqual(1, len(queue)) self.assertEqual(expected_node, queue[0])
def test_start_with_derived_class(self): a = make_dataclass("a", fields=[]) b = make_dataclass("b", fields=[], bases=(a,)) parser = NodeParser() queue = [] objects = [] attrs = {QNames.XSI_TYPE: "b"} ns_map = {} parser.start(a, queue, objects, "a", attrs, ns_map) expected_node = ElementNode( position=0, context=parser.context, meta=parser.context.build(b), config=parser.config, attrs=attrs, ns_map={}, derived=True, ) self.assertEqual(1, len(queue)) self.assertEqual(expected_node, queue[-1])
class ElementNodeTests(TestCase): def setUp(self) -> None: super().setUp() self.context = XmlContext() self.meta = XmlMeta(clazz=Foo, qname="foo", source_qname="foo", nillable=False) self.node = ElementNode( position=0, meta=self.meta, context=self.context, config=ParserConfig(), attrs={}, ns_map={}, ) @mock.patch.object(ParserUtils, "bind_objects") @mock.patch.object(ParserUtils, "bind_wild_content") @mock.patch.object(ParserUtils, "bind_content") @mock.patch.object(ParserUtils, "bind_attrs") def test_bind( self, mock_bind_attrs, mock_bind_content, mock_bind_wild_content, mock_bind_objects, ): mock_bind_attrs.side_effect = add_attr mock_bind_content.side_effect = add_text mock_bind_objects.side_effect = add_child node = ElementNode( position=0, meta=self.context.build(Foo), context=self.context, config=ParserConfig(), attrs={"a": "b"}, ns_map={"ns0": "xsdata"}, ) objects = [1, 2, 3] self.assertTrue(node.bind("foo", "text", "tail", objects)) self.assertEqual("foo", objects[-1][0]) self.assertEqual(Foo(1, 2, 3), objects[-1][1]) mock_bind_attrs.assert_called_once_with( mock.ANY, node.meta, node.attrs, node.ns_map ) mock_bind_content.assert_called_once_with( mock.ANY, node.meta, "text", node.ns_map ) mock_bind_objects.assert_called_once_with(mock.ANY, node.meta, 0, objects) self.assertEqual(0, mock_bind_wild_content.call_count) def test_bind_with_derived_element(self): a = make_dataclass("A", fields=[]) node = ElementNode( position=0, meta=self.context.build(a), context=self.context, config=ParserConfig(), attrs={}, ns_map={}, derived=True, ) objects = [] self.assertTrue(node.bind("foo", None, None, objects)) self.assertEqual("foo", objects[-1][0]) self.assertEqual(DerivedElement("foo", a()), objects[-1][1]) @mock.patch.object(XmlMeta, "find_var") @mock.patch.object(ParserUtils, "bind_objects") @mock.patch.object(ParserUtils, "bind_wild_content") @mock.patch.object(ParserUtils, "bind_content") @mock.patch.object(ParserUtils, "bind_attrs") def test_bind_with_wildcard_var( self, mock_bind_attrs, mock_bind_content, mock_bind_wild_content, mock_bind_objects, mock_find_var, ): mock_bind_attrs.side_effect = add_attr mock_bind_content.return_value = False mock_bind_wild_content.side_effect = add_text mock_bind_objects.side_effect = add_child mock_find_var.return_value = XmlVar(wildcard=True, qname="b", name="b") node = ElementNode( position=0, meta=self.context.build(Foo), context=self.context, config=ParserConfig(), attrs={"a": "b"}, ns_map={"ns0": "xsdata"}, ) objects = [1, 2, 3] self.assertTrue(node.bind("foo", "text", "tail", objects)) self.assertEqual("foo", objects[-1][0]) self.assertEqual(Foo(1, 2, 3), objects[-1][1]) mock_bind_attrs.assert_called_once_with( mock.ANY, node.meta, node.attrs, node.ns_map ) mock_bind_content.assert_called_once_with( mock.ANY, node.meta, "text", node.ns_map ) mock_bind_objects.assert_called_once_with(mock.ANY, node.meta, 0, objects) @mock.patch.object(ParserUtils, "bind_objects") @mock.patch.object(ParserUtils, "bind_content") @mock.patch.object(ParserUtils, "bind_attrs") def test_bind_with_mixed_flag_true( self, mock_bind_attrs, mock_bind_content, mock_bind_objects ): mock_bind_attrs.side_effect = add_attr mock_bind_content.side_effect = add_text mock_bind_objects.side_effect = add_child node = ElementNode( position=0, meta=self.context.build(Foo), context=self.context, config=ParserConfig(), attrs={"a": "b"}, ns_map={"ns0": "xsdata"}, mixed=True, ) objects = [] self.assertTrue(node.bind("foo", "text", " ", objects)) self.assertEqual(1, len(objects)) objects = [] self.assertTrue(node.bind("foo", "text", " tail ", objects)) self.assertEqual(2, len(objects)) self.assertEqual(None, objects[-1][0]) self.assertEqual(" tail ", objects[-1][1]) @mock.patch.object(ParserUtils, "bind_mixed_objects") @mock.patch.object(ParserUtils, "bind_wild_content") @mock.patch.object(ParserUtils, "bind_attrs") def test_bind_with_mixed_content_var( self, mock_bind_attrs, mock_bind_wild_content, mock_bind_mixed_objects, ): mock_bind_attrs.side_effect = add_attr mock_bind_wild_content.side_effect = add_text mock_bind_mixed_objects.side_effect = add_content node = ElementNode( position=0, meta=self.context.build(FooMixed), context=self.context, config=ParserConfig(), attrs={"a": "b"}, ns_map={"ns0": "xsdata"}, ) objects = [1, 2, 3] self.assertTrue(node.bind("foo", "text", "tail", objects)) self.assertEqual("foo", objects[-1][0]) self.assertEqual(FooMixed(1, 2, 3), objects[-1][1]) mock_bind_attrs.assert_called_once_with( mock.ANY, node.meta, node.attrs, node.ns_map ) mock_bind_wild_content.assert_called_once_with( mock.ANY, node.meta.vars[2], "text", "tail", node.attrs, node.ns_map ) mock_bind_mixed_objects.assert_called_once_with( mock.ANY, node.meta.vars[2], 0, objects ) def test_fetch_vars(self): elem = XmlVar(element=True, name="a", qname="a", types=[Foo], dataclass=True) wild = XmlVar(wildcard=True, name="a", qname="a", types=[Foo], dataclass=True) self.meta.vars.extend((wild, elem)) matching_vars = self.node.fetch_vars("a") self.assertIsInstance(matching_vars, Generator) self.assertEqual([(id(elem), elem), (None, wild)], list(matching_vars)) def test_fetch_vars_with_elements_var(self): elem = XmlVar(element=True, name="a", qname="a", types=[Foo], dataclass=True) elems = XmlVar(elements=True, name="compound", qname="compound", choices=[elem]) self.meta.vars.append(elems) matching_vars = self.node.fetch_vars("a") self.assertIsInstance(matching_vars, Generator) self.assertEqual((None, elem), next(matching_vars)) @mock.patch.object(ElementNode, "fetch_vars") def test_child(self, mock_match_vars): var = XmlVar(element=True, name="a", qname="a", types=[Foo], dataclass=True) attrs = {"a": "b"} ns_map = {"ns0": "xsdata"} position = 1 mock_match_vars.return_value = [(id(var), var)] actual = self.node.child("a", attrs, ns_map, position) self.assertIsInstance(actual, ElementNode) self.assertEqual(attrs, actual.attrs) self.assertEqual(ns_map, actual.ns_map) self.assertEqual(position, actual.position) def test_child_unique_vars(self): single = XmlVar(element=True, name="a", qname="a", types=[Foo], dataclass=True) wildcard = XmlVar(wildcard=True, name="a", qname="a", types=[object]) self.meta.vars.append(single) self.meta.vars.append(wildcard) attrs = {"a": "b"} ns_map = {"ns0": "xsdata"} position = 1 actual = self.node.child("a", attrs, ns_map, position) self.assertIsInstance(actual, ElementNode) self.assertIn(id(single), self.node.assigned) actual = self.node.child("a", attrs, ns_map, position) self.assertIsInstance(actual, WildcardNode) self.assertNotIn(id(wildcard), self.node.assigned) @mock.patch.object(ElementNode, "build_node") def test_child_when_failed_to_build_next_node(self, mock_build_node): mock_build_node.return_value = None self.meta.vars.append(XmlVar(element=True, name="a", qname="a")) self.meta.vars.append(XmlVar(wildcard=True, name="a", qname="a")) with self.assertRaises(ParserError) as cm: self.node.child("a", {}, {}, 0) self.assertEqual("Unknown property foo:a", str(cm.exception)) self.node.config.fail_on_unknown_properties = False actual = self.node.child("foobar", {}, {}, 0) self.assertIsInstance(actual, SkipNode) def test_build_node_with_dataclass_union_var(self): var = XmlVar( element=True, name="a", qname="a", types=[Foo, FooMixed], dataclass=True ) attrs = {"a": "b"} ns_map = {"ns0": "xsdata"} actual = self.node.build_node(var, attrs, ns_map, 10) self.assertIsInstance(actual, UnionNode) self.assertEqual(10, actual.position) self.assertIs(var, actual.var) self.assertEqual(attrs, actual.attrs) self.assertEqual(ns_map, actual.ns_map) self.assertEqual(0, actual.level) self.assertEqual(0, len(actual.events)) @mock.patch.object(ParserUtils, "xsi_type", return_value="foo") @mock.patch.object(XmlContext, "fetch") def test_build_node_with_dataclass_var(self, mock_ctx_fetch, mock_xsi_type): var = XmlVar( element=True, name="a", qname="a", types=[Foo], dataclass=True, derived=True ) xsi_type = "foo" namespace = self.meta.namespace mock_ctx_fetch.return_value = self.meta mock_xsi_type.return_value = xsi_type attrs = {"a": "b"} ns_map = {"ns0": "xsdata"} actual = self.node.build_node(var, attrs, ns_map, 10) self.assertIsInstance(actual, ElementNode) self.assertEqual(10, actual.position) self.assertTrue(actual.derived) self.assertIs(mock_ctx_fetch.return_value, actual.meta) mock_xsi_type.assert_called_once_with(attrs, ns_map) mock_ctx_fetch.assert_called_once_with(var.clazz, namespace, xsi_type) @mock.patch.object(XmlContext, "fetch") def test_build_node_with_dataclass_var_validates_nillable(self, mock_ctx_fetch): var = XmlVar(element=True, name="a", qname="a", types=[Foo], dataclass=True) ns_map = {} nillable_meta = replace(self.meta, nillable=True) mock_ctx_fetch.side_effect = [self.meta, self.meta, nillable_meta] attrs = {QNames.XSI_NIL: "false"} self.assertIsNotNone(self.node.build_node(var, attrs, ns_map, 10)) attrs = {QNames.XSI_NIL: "true"} self.assertIsNotNone(self.node.build_node(var, attrs, ns_map, 10)) attrs = {QNames.XSI_NIL: "false"} self.assertIsNone(self.node.build_node(var, attrs, ns_map, 10)) def test_build_node_with_any_type_var_with_matching_xsi_type(self): var = XmlVar(element=True, name="a", qname="a", types=[object], any_type=True) attrs = {QNames.XSI_TYPE: "bk:books"} ns_map = {"bk": "urn:books"} actual = self.node.build_node(var, attrs, ns_map, 10) self.assertIsInstance(actual, ElementNode) self.assertEqual(10, actual.position) self.assertEqual(self.context.build(Books), actual.meta) self.assertEqual(attrs, actual.attrs) self.assertEqual(ns_map, actual.ns_map) self.assertFalse(actual.mixed) def test_build_node_with_any_type_var_with_datatype(self): var = XmlVar(element=True, name="a", qname="a", types=[object], any_type=True) attrs = {QNames.XSI_TYPE: "xs:hexBinary"} ns_map = {Namespace.XS.prefix: Namespace.XS.uri} actual = self.node.build_node(var, attrs, ns_map, 10) self.assertIsInstance(actual, StandardNode) self.assertEqual(ns_map, actual.ns_map) self.assertEqual(DataType.HEX_BINARY, actual.datatype) self.assertEqual(var.derived, actual.derived) def test_build_node_with_any_type_var_with_no_matching_xsi_type(self): var = XmlVar(element=True, name="a", qname="a", types=[object], any_type=True) attrs = {QNames.XSI_TYPE: "noMatch"} actual = self.node.build_node(var, attrs, {}, 10) self.assertIsInstance(actual, WildcardNode) self.assertEqual(10, actual.position) self.assertEqual(var, actual.var) self.assertEqual(attrs, actual.attrs) self.assertEqual({}, actual.ns_map) def test_build_node_with_any_type_var_with_no_xsi_type(self): var = XmlVar(element=True, name="a", qname="a", types=[object], any_type=True) attrs = {} actual = self.node.build_node(var, attrs, {}, 10) self.assertIsInstance(actual, WildcardNode) self.assertEqual(10, actual.position) self.assertEqual(var, actual.var) self.assertEqual(attrs, actual.attrs) self.assertEqual({}, actual.ns_map) def test_build_node_with_wildcard_var(self): var = XmlVar(wildcard=True, name="a", qname="a", types=[], dataclass=False) actual = self.node.build_node(var, {}, {}, 10) self.assertIsInstance(actual, WildcardNode) self.assertEqual(10, actual.position) self.assertEqual(var, actual.var) def test_build_node_with_primitive_var(self): var = XmlVar(text=True, name="a", qname="a", types=[int], default=100) attrs = {"a": "b"} ns_map = {"ns0": "xsdata"} actual = self.node.build_node(var, attrs, ns_map, 10) self.assertIsInstance(actual, PrimitiveNode) self.assertEqual(ns_map, actual.ns_map) self.assertEqual(var, actual.var)