From 122b77e154a2c26e03abe60c59b546a373ef3377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Fri, 4 Jun 2021 11:16:25 +0900 Subject: [PATCH 01/22] Create method `has_child_nodes()` (#16) --- w3/python/core/fundamental_interface/Node.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index ae27bb3..5fa6614 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -188,7 +188,7 @@ def first_child(self) -> Optional[_AnyNode]: If there is no such node, this returns `None`. """ - if not self.child_nodes: + if not self.has_child_nodes(): return None return self.child_nodes.item(0) @@ -198,7 +198,7 @@ def last_child(self) -> Optional[_AnyNode]: If there is no such node, this returns `None`. """ - if not self.child_nodes: + if not self.has_child_nodes(): return None return self.child_nodes.item(self.child_nodes.length-1) @@ -266,6 +266,14 @@ def _set_owner_document(self, """Indirect accessor to set the 'owner_document' property.""" self._owner_document = owner_document + def has_child_nodes(self) -> bool: + """This is a convenience method to allow easy determination of whether a node has any children. + + Returns: + `True` if the node has any children, `False` if the node has no children. + """ + return bool(self.child_nodes) + _AnyNode = Node _NamedNodeMap = Dict[str, _AnyNode] # TODO: Implement NamedNodeMap (#19) From fac414d40f88968234bb979d2665ce4a38aa264e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Fri, 4 Jun 2021 16:13:53 +0900 Subject: [PATCH 02/22] Create method `insert_before()` (#16) --- w3/python/core/fundamental_interface/Node.py | 42 ++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 5fa6614..556c051 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -266,6 +266,48 @@ def _set_owner_document(self, """Indirect accessor to set the 'owner_document' property.""" self._owner_document = owner_document + def insert_before(self, + new_child: _AnyNode, + ref_child: Optional[_AnyNode] = None) -> _AnyNode: + """Inserts the node `new_child` before the existing child node `ref_child`. If `ref_child` is `None`, insert `new_child` at the end of the list of children. + + If `new_child` is a `DocumentFragment` object, all of its children are inserted, in the same order, before `ref_child`. If the `new_child` is already in the tree, it is first removed. + + Args: + new_child: The node to insert. + ref_child: The reference node, i.e., the node before which the new node must be inserted. + + Returns: + The node being inserted. + + Raises: + DOMException: + - `HIERARCHY_REQUEST_ERR`: Raised if this node is of a type that does not allow children of the type of the `new_child` node, or if the node to insert is one of this node's ancestors. + - `WRONG_DOCUMENT_ERR`: Raised if `new_child` was created from a different document than the one that created this node. + - `NO_MODIFICATION_ALLOWED_ERR`: Raised if this node is readonly. + - `NOT_FOUND_ERR`: Raised if `ref_child` is not a child of this node. + """ + if self._read_only: + raise DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR) + if self.owner_document is not new_child.owner_document: + raise DOMException(DOMException.WRONG_DOCUMENT_ERR) + # `HIERARCHY_REQUEST_ERR` should be checked on subclasses by overriding. + if new_child in self.child_nodes: + self.child_nodes.remove(new_child) + if new_child.node_type == NodeType.DOCUMENT_FRAGMENT_NODE: + grand_child_node: _AnyNode + for grand_child_node in new_child.child_nodes: + self.insert_before(grand_child_node, ref_child) + elif ref_child is None: + self.child_nodes.append(new_child) + elif ref_child not in self.child_nodes: + raise DOMException(DOMException.NOT_FOUND_ERR) + else: + self.child_nodes.insert(self.child_nodes.index(ref_child), + new_child) + new_child._set_parent_node(self) + return new_child + def has_child_nodes(self) -> bool: """This is a convenience method to allow easy determination of whether a node has any children. From 59f56ba211f072d2c2562cfc1c13140962adfee2 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Fri, 4 Jun 2021 20:08:31 +0900 Subject: [PATCH 03/22] Update `parent_node` parameters of `Node.__init__` (#16) the `parent_node` cannot be set directly on constructor. since the parent node should have self in its `child_nodes`. the binding of parent-child nodes can be done with `insert_before`, `append_child` methods. --- w3/python/core/fundamental_interface/Node.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 556c051..109f78e 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -65,7 +65,6 @@ def __init__(self, node_type: NodeType, node_name: DOMString, node_value: Optional[DOMString] = None, - parent_node: Optional[_AnyNode] = None, child_nodes: Optional[Iterable[_AnyNode]] = None, attributes: Optional[Iterable[_AnyNode]] = None, owner_document: Optional[_Document] = None, @@ -76,7 +75,7 @@ def __init__(self, self._set_node_type(node_type) self._set_node_name(node_name) self._set_node_value(node_value) - self._set_parent_node(parent_node) + self._set_parent_node(None) self._init_child_nodes(child_nodes) self._init_attributes(attributes) self._set_owner_document(owner_document) @@ -85,7 +84,7 @@ def __init__(self, self._node_type: NodeType self._node_name: DOMString self._node_value: DOMString - self._parent_node: _AnyNode + self._parent_node: Optional[_AnyNode] self._child_nodes: NodeList self._attributes: _NamedNodeMap self._owner_document: _Document From 44cbde2874677ee8b41fc0d27f216ee0df9290d5 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Fri, 4 Jun 2021 20:13:10 +0900 Subject: [PATCH 04/22] Update `owner_document` parameters of `Node.__init__` (#16) A `Document` object; `owner_document` must be given when creating a `Node`. But if this node is a `Document`, `owner_document` is `None`. --- w3/python/core/fundamental_interface/Node.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 109f78e..e42cc47 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -64,10 +64,10 @@ class Node: def __init__(self, node_type: NodeType, node_name: DOMString, + owner_document: Optional[_Document], node_value: Optional[DOMString] = None, child_nodes: Optional[Iterable[_AnyNode]] = None, attributes: Optional[Iterable[_AnyNode]] = None, - owner_document: Optional[_Document] = None, read_only: bool = False) -> None: if node_value is None: node_value = '' @@ -87,7 +87,7 @@ def __init__(self, self._parent_node: Optional[_AnyNode] self._child_nodes: NodeList self._attributes: _NamedNodeMap - self._owner_document: _Document + self._owner_document: Optional[_Document] self._read_only: bool def _check_modifiable(self) -> None: @@ -256,13 +256,16 @@ def owner_document(self) -> Optional[_Document]: This is also the `Document` object used to create new nodes. When this node is a `Document` this is `None`. """ - if self.node_type == NodeType.DOCUMENT_NODE: - return None return self._owner_document def _set_owner_document(self, owner_document: Optional[_Document] = None) -> None: """Indirect accessor to set the 'owner_document' property.""" + if owner_document is None: + if self.node_type != NodeType.DOCUMENT_NODE: + raise ValueError('`Node` should have a `Document` object ', + 'which associated with this node, ', + 'Unless this node is a `Document`.') self._owner_document = owner_document def insert_before(self, From 35a51437e18cd4ca8761b9a5d0d271d73190168f Mon Sep 17 00:00:00 2001 From: Hepheir Date: Fri, 4 Jun 2021 21:10:54 +0900 Subject: [PATCH 05/22] Remove method `Node._check_modifiable()` (#16) --- w3/python/core/fundamental_interface/Node.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index e42cc47..f66c0b4 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -90,16 +90,6 @@ def __init__(self, self._owner_document: Optional[_Document] self._read_only: bool - def _check_modifiable(self) -> None: - """Checks if this node is modifiable. - - Raises: - DOMException: - - `NO_MODIFICATION_ALLOWED_ERR`: Raised when the node is readonly. - """ - if self._read_only: - raise DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR) - @property def node_name(self) -> DOMString: """Read only; The name of this node, depending on its type.""" @@ -131,7 +121,8 @@ def _set_node_value(self, value: DOMString) -> None: DOMException: - `NO_MODIFICATION_ALLOWED_ERR`: Raised when the node is readonly. """ - self._check_modifiable() + if self._read_only: + raise DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR) self._node_value = DOMString(value) @property From ed53b549c71e666e603addee6ae266b82c608ea9 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Fri, 4 Jun 2021 21:34:10 +0900 Subject: [PATCH 06/22] Create method `Node.append_child()` (#16) --- w3/python/core/fundamental_interface/Node.py | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index f66c0b4..801e4c9 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -301,6 +301,37 @@ def insert_before(self, new_child._set_parent_node(self) return new_child + def append_child(self, new_child: _AnyNode) -> _AnyNode: + """Adds the node `new_child` to the end of the list of children of this node. + + If the `new_child` is already in the tree, it is first removed. + + Args: + new_child: The node to add. If it is a `DocumentFragment` object, the entire contents of the document fragment are moved into the child list of this node + + Returns: + The node added. + + Raises: + DOMException: + - `HIERARCHY_REQUEST_ERR`: Raised if this node is of a type that does not allow children of the type of the `new_child` node, or if the node to append is one of this node's ancestors. + - `WRONG_DOCUMENT_ERR`: Raised if `new_child` was created from a different document than the one that created this node. + - `NO_MODIFICATION_ALLOWED_ERR`: Raised if this node is readonly. + """ + if self._read_only: + raise DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR) + if self.owner_document is not new_child.owner_document: + raise DOMException(DOMException.WRONG_DOCUMENT_ERR) + # `HIERARCHY_REQUEST_ERR` should be checked on subclasses by overriding. + if new_child.node_type == NodeType.DOCUMENT_FRAGMENT_NODE: + grand_child_node: _AnyNode + for grand_child_node in new_child.child_nodes: + self.append_child(grand_child_node) + else: + new_child._set_parent_node(self) + self.child_nodes.append(new_child) + return new_child + def has_child_nodes(self) -> bool: """This is a convenience method to allow easy determination of whether a node has any children. From a5b76562f4f0ad6564a3c6adb7b733e5fdcf98e5 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 13:32:10 +0900 Subject: [PATCH 07/22] Update unittests (#16, #17) --- .../fundamental_interface/NodeList_test.py | 86 +++++-- .../core/fundamental_interface/Node_test.py | 230 +++++++++++++++--- 2 files changed, 250 insertions(+), 66 deletions(-) diff --git a/w3/python/core/fundamental_interface/NodeList_test.py b/w3/python/core/fundamental_interface/NodeList_test.py index b66e4c8..3046d79 100644 --- a/w3/python/core/fundamental_interface/NodeList_test.py +++ b/w3/python/core/fundamental_interface/NodeList_test.py @@ -1,4 +1,4 @@ -from typing import Iterator +from typing import Iterator, Optional import unittest from w3.dom import Node @@ -6,7 +6,20 @@ from w3.dom import NodeList -def _make_nodes(n: int) -> Iterator[Node]: +def _create_document_node(): + return Node(node_type=NodeType.DOCUMENT_NODE, + node_name='#document', + owner_document=None) + + +def _create_text_node(document: Node): + assert document.node_type == NodeType.DOCUMENT_NODE + return Node(node_type=NodeType.TEXT_NODE, + node_name='#text', + owner_document=document) + + +def _make_nodes(n: int, document: Optional[Node] = None) -> Iterator[Node]: """Accessor to create `n` random nodes immediatly. Args: @@ -15,17 +28,21 @@ def _make_nodes(n: int) -> Iterator[Node]: Yields: A randomly generated node. """ + if document is None: + document = _create_document_node() for _ in range(n): - yield Node(NodeType.TEXT_NODE, '#text') + yield _create_text_node(document) -class Test_NodeList(unittest.TestCase): - def testInit(self): +class Test_Dunder(unittest.TestCase): + def testInit_Empty(self): NodeList() - # Initiate with a node + + def testInit_SingleNode(self): node = next(_make_nodes(1)) NodeList([node]) - # Initiate with multiple nodes. + + def testInit_MultipleNodes(self): NodeList(_make_nodes(4)) def testIter(self): @@ -51,39 +68,56 @@ def testGetItem(self): self.assertEqual(node_list[i], nodes[i]) def testSetItem(self): - node = Node(NodeType.TEXT_NODE, - '#text') - node_list = NodeList(_make_nodes(4)) - node_list[2] = node - self.assertEqual(node_list[2], node) + document = _create_document_node() + text_node = _create_text_node(document) + node_list = NodeList(_make_nodes(4, document)) + node_list[2] = text_node + self.assertEqual(node_list[2], text_node) + + def testContains(self): + nodes = [*_make_nodes(4)] + node_list = NodeList(nodes) + for n in node_list: + self.assertIn(n, node_list) + + def testContains_NotIn(self): + internal_nodes = [*_make_nodes(4)] + external_node = _make_nodes(1) + node_list = NodeList(internal_nodes) + self.assertNotIn(external_node, node_list) + + +class Test_Length(unittest.TestCase): + def test_Empty(self): + node_list = NodeList() + self.assertEqual(node_list.length, 0) - def testItem_inSize(self): + def test_OneItem(self): + node_list = NodeList(_make_nodes(1)) + self.assertEqual(node_list.length, 1) + + def test_SomeItems(self): + node_list = NodeList(_make_nodes(5)) + self.assertEqual(node_list.length, 5) + + +class Test_Item(unittest.TestCase): + def test_InSize(self): nodes = [*_make_nodes(5)] node_list = NodeList(nodes) for i in range(5): self.assertEqual(node_list.item(i), nodes[i]) - def testItem_greaterOrEqualThanSize(self): + def test_GreaterOrEqualThanSize(self): node_list = NodeList(_make_nodes(5)) for i in range(5, 8): self.assertIsNone(node_list.item(i)) - def testItem_notValid(self): + def test_InvalidIndex(self): node_list = NodeList(_make_nodes(5)) for idx in [-1, -9999, 'hi', '1', None, Node, NodeList, b'0']: self.assertIsNone(node_list.item(idx)) - def testLength(self): - # Empty NodeList - node_list = NodeList() - self.assertEqual(node_list.length, 0) - # NodeList with a node. - node_list = NodeList(_make_nodes(1)) - self.assertEqual(node_list.length, 1) - # NodeList with some items. - node_list = NodeList(_make_nodes(5)) - self.assertEqual(node_list.length, 5) - if __name__ == '__main__': unittest.main() diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index 556039c..fe6c631 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -5,72 +5,222 @@ from w3.dom import NodeType -class Test_Node(unittest.TestCase): - def test_init(self): - node = Node(node_type=NodeType.DOCUMENT_NODE, - node_name='#document', - read_only=False) - self.assertEqual(node.node_type, NodeType.DOCUMENT_NODE) - self.assertEqual(node.node_name, '#document') - self.assertEqual(node.node_value, '') +def _create_document_node(): + return Node(node_type=NodeType.DOCUMENT_NODE, + node_name='#document', + owner_document=None) + + +def _create_element_node(document: Node): + assert document.node_type == NodeType.DOCUMENT_NODE + return Node(node_type=NodeType.ELEMENT_NODE, + node_name='tagName', + owner_document=document) + + +class Test_Dunder(unittest.TestCase): + def testInit(self): + # Creating document node. + document = Node(node_type=NodeType.DOCUMENT_NODE, + node_name='#document', + owner_document=None, + read_only=False) + self.assertEqual(document.node_type, NodeType.DOCUMENT_NODE) + self.assertEqual(document.node_name, '#document') + self.assertEqual(document.node_value, '') - def testNodeValue_get(self): - node = Node(node_type=NodeType.TEXT_NODE, + +class Test_NodeValue(unittest.TestCase): + def testGetter(self): + document = _create_document_node() + text = Node(node_type=NodeType.TEXT_NODE, node_name='#text', + owner_document=document, node_value='lorem ipsum') - self.assertEqual(node.node_value, 'lorem ipsum') + self.assertEqual(text.node_value, 'lorem ipsum') - def testNodeValue_set(self): - # set value from constructor - node = Node(node_type=NodeType.TEXT_NODE, + def testConstructor(self): + document = _create_document_node() + text = Node(node_type=NodeType.TEXT_NODE, node_name='#text', + owner_document=document, node_value='foo', read_only=False) - self.assertEqual(node.node_value, 'foo') - # set using setter - node.node_value = 'bar' - self.assertEqual(node.node_value, 'bar') + self.assertEqual(text.node_value, 'foo') - def testNodeValue_setReadOnly(self): - node = Node(node_type=NodeType.TEXT_NODE, + def testSetter(self): + document = _create_document_node() + text = Node(node_type=NodeType.TEXT_NODE, node_name='#text', + owner_document=document, + read_only=False) + text.node_value = 'bar' + self.assertEqual(text.node_value, 'bar') + + def testSetter_ReadOnly(self): + document = _create_document_node() + text = Node(node_type=NodeType.TEXT_NODE, + node_name='#text', + owner_document=document, node_value='foo', read_only=True) try: - node.node_value = 'bar' + text.node_value = 'bar' except DOMException as e: code = e.args[0] self.assertEqual(code, DOMException.NO_MODIFICATION_ALLOWED_ERR) else: self.fail() # `node_value` should not be modified. - self.assertEqual(node.node_value, 'foo') + self.assertEqual(text.node_value, 'foo') + - def testNodeType_get(self): +class Test_NodeType(unittest.TestCase): + def testGetter(self): + document = _create_document_node() for node_type in NodeType: node = Node(node_type=node_type, - node_name='') + node_name='', + owner_document=document) self.assertEqual(node.node_type, node_type) - def testNodeType_setCorrectTypes(self): + def testSetter_CorrectTypes(self): + document = _create_document_node() for node_type in NodeType: - node = Node(node_type=node_type, - node_name='') - self.assertEqual(node.node_type, node_type) + Node(node_type=node_type, + node_name='', + owner_document=document) - def testNodeType_setWrongTypes(self): - for node_type in [-1, None, 'hi', Node, True, NodeType, 'DOCUMENT_NODE']: - with self.assertRaises(TypeError): + def testSetter_WrongTypes(self): + document = _create_document_node() + for node_type in [-1, None, 'hi', True, Node, NodeType, 'DOCUMENT_NODE']: + try: Node(node_type=node_type, - node_name='') - - def testParentNode_get(self): - parent_node = Node(node_type=NodeType.DOCUMENT_FRAGMENT_NODE, - node_name='#document-fragment') - node = Node(node_type=NodeType.ELEMENT_NODE, - node_name='tagName', - parent_node=parent_node) - self.assertEqual(node.parent_node, parent_node) + node_name='', + owner_document=document) + self.fail() + except Exception: + pass + + +class Test_ParentNode(unittest.TestCase): + def testConstrutor(self): + document = _create_document_node() + docfrag = Node(node_type=NodeType.DOCUMENT_FRAGMENT_NODE, + node_name='#document-fragment', + owner_document=document) + self.assertIsNone(docfrag.parent_node) + + def testGetter(self): + document = _create_document_node() + parent_node = _create_element_node(document) + child_node = _create_element_node(document) + # Warning: this is assuming that `append_child()` method works properly. + parent_node.append_child(child_node) + self.assertEqual(child_node.parent_node, parent_node) + + +class Test_InsertBefore(unittest.TestCase): + def test_WithoutRefNode(self): + document = _create_document_node() + parent_node = _create_element_node(document) + child_node = _create_element_node(document) + # Testing + parent_node.insert_before(child_node) + self.assertEqual(child_node.parent_node, parent_node) + self.assertEqual(parent_node.child_nodes.item(0), child_node) + self.assertEqual(parent_node.child_nodes.length, 1) + + def test_WithRefNode(self): + document = _create_document_node() + parent_node = _create_element_node(document) + first_child_node = _create_element_node(document) + second_child_node = _create_element_node(document) + # Warning: this is assuming that `append_child()` method works properly. + parent_node.append_child(second_child_node) + # Testing + parent_node.insert_before(first_child_node, second_child_node) + self.assertEqual(first_child_node.parent_node, parent_node) + self.assertEqual(parent_node.child_nodes.item(0), first_child_node) + self.assertEqual(parent_node.child_nodes.item(1), second_child_node) + self.assertEqual(parent_node.child_nodes.length, 2) + + def test_InsertExistingChild(self): + document = _create_document_node() + parent_node = _create_element_node(document) + first_child_node = _create_element_node(document) + second_child_node = _create_element_node(document) + # Warning: this is assuming that `append_child()` method works properly. + parent_node.append_child(first_child_node) + parent_node.append_child(second_child_node) + # Testing + parent_node.insert_before(second_child_node, first_child_node) + self.assertEqual(second_child_node.parent_node, parent_node) + self.assertEqual(parent_node.child_nodes.item(0), second_child_node) + self.assertEqual(parent_node.child_nodes.item(1), first_child_node) + self.assertEqual(parent_node.child_nodes.length, 2) + + def test_InsertDocumentFragmentNode(self): + document = _create_document_node() + parent_node = _create_element_node(document) + docfrag_node = Node(node_type=NodeType.DOCUMENT_FRAGMENT_NODE, + node_name='#document-fragment', + owner_document=document) + first_child_node = _create_element_node(document) + second_child_node = _create_element_node(document) + # Warning: this is assuming that `append_child()` method works properly. + docfrag_node.append_child(first_child_node) + docfrag_node.append_child(second_child_node) + # Testing + parent_node.insert_before(docfrag_node) + self.assertEqual(parent_node.child_nodes.item(0), first_child_node) + self.assertEqual(parent_node.child_nodes.item(1), second_child_node) + self.assertEqual(parent_node.child_nodes.length, 2) + + def test_Raises_HIERARCHY_REQUEST_ERR(self): + self.skipTest(NotImplemented) # TODO + + def test_Raises_WRONG_DOCUMENT_ERR(self): + document_1 = _create_document_node() + document_2 = _create_document_node() + elem_node_1 = _create_element_node(document_1) + elem_node_2 = _create_element_node(document_2) + try: + elem_node_1.insert_before(elem_node_2) + except DOMException as e: + code = e.args[0] + self.assertEqual(code, DOMException.WRONG_DOCUMENT_ERR) + else: + self.fail() + + def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): + document = _create_document_node() + elem_node_readonly = Node(node_type=NodeType.ELEMENT_NODE, + node_name='tagName', + owner_document=document, + read_only=True) + elem_node_child = _create_element_node(document) + try: + elem_node_readonly.insert_before(elem_node_child) + except DOMException as e: + code = e.args[0] + self.assertEqual(code, DOMException.NO_MODIFICATION_ALLOWED_ERR) + else: + self.fail() + + def test_Raises_NOT_FOUND_ERR(self): + document = _create_document_node() + elem_node_parent = _create_element_node(document) + elem_node_child = _create_element_node(document) + elem_node_error = _create_element_node(document) + # Testing + try: + elem_node_parent.insert_before(elem_node_child, elem_node_error) + except DOMException as e: + code = e.args[0] + self.assertEqual(code, DOMException.NOT_FOUND_ERR) + else: + self.fail() if __name__ == '__main__': From c5e0cc9f9e5e5a49373e985a3ec09be7a0e7fbbe Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 13:33:50 +0900 Subject: [PATCH 08/22] #16 Add unittest for `Node.parent_node` setter. --- w3/python/core/fundamental_interface/Node_test.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index fe6c631..ea5e10b 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -119,6 +119,16 @@ def testGetter(self): parent_node.append_child(child_node) self.assertEqual(child_node.parent_node, parent_node) + def testSetter_Raises_Exception(self): + document = _create_document_node() + parent_node = _create_element_node(document) + child_node = _create_element_node(document) + try: + child_node.parent_node = parent_node + except: + self.assertNotEqual(child_node.parent_node, parent_node) + else: + self.fail() class Test_InsertBefore(unittest.TestCase): def test_WithoutRefNode(self): From 3384e8d15705715cb7984e0b0aeefee1c3e5819a Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 13:48:18 +0900 Subject: [PATCH 09/22] #16 Add unittest for `Node.append_child()` --- .../core/fundamental_interface/Node_test.py | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index ea5e10b..18a39d7 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -233,5 +233,81 @@ def test_Raises_NOT_FOUND_ERR(self): self.fail() + +class Test_AppendChild(unittest.TestCase): + def test_AppendNewChild(self): + document = _create_document_node() + parent_node = _create_element_node(document) + child_node = _create_element_node(document) + # Testing + parent_node.append_child(child_node) + self.assertEqual(child_node.parent_node, parent_node) + self.assertEqual(parent_node.child_nodes.item(0), child_node) + self.assertEqual(parent_node.child_nodes.length, 1) + + def test_AppendExistingChild(self): + document = _create_document_node() + parent_node = _create_element_node(document) + first_child_node = _create_element_node(document) + second_child_node = _create_element_node(document) + # Warning: this is assuming that `append_child()` has passed `test_AppendNewChild()` test. + parent_node.append_child(first_child_node) + parent_node.append_child(second_child_node) + # Testing + parent_node.append_child(first_child_node) + self.assertEqual(second_child_node.parent_node, parent_node) + self.assertEqual(parent_node.child_nodes.item(0), second_child_node) + self.assertEqual(parent_node.child_nodes.item(1), first_child_node) + self.assertEqual(parent_node.child_nodes.length, 2) + + def test_AppendDocumentFragmentNode(self): + document = _create_document_node() + parent_node = _create_element_node(document) + docfrag_node = Node(node_type=NodeType.DOCUMENT_FRAGMENT_NODE, + node_name='#document-fragment', + owner_document=document) + first_child_node = _create_element_node(document) + second_child_node = _create_element_node(document) + # Warning: this is assuming that `append_child()` has passed `test_AppendNewChild()` test. + docfrag_node.append_child(first_child_node) + docfrag_node.append_child(second_child_node) + # Testing + parent_node.append_child(docfrag_node) + self.assertEqual(parent_node.child_nodes.item(0), first_child_node) + self.assertEqual(parent_node.child_nodes.item(1), second_child_node) + self.assertEqual(parent_node.child_nodes.length, 2) + + def test_Raises_HIERARCHY_REQUEST_ERR(self): + self.skipTest(NotImplemented) # TODO + + def test_Raises_WRONG_DOCUMENT_ERR(self): + document_1 = _create_document_node() + document_2 = _create_document_node() + elem_node_1 = _create_element_node(document_1) + elem_node_2 = _create_element_node(document_2) + try: + elem_node_1.append_child(elem_node_2) + except DOMException as e: + code = e.args[0] + self.assertEqual(code, DOMException.WRONG_DOCUMENT_ERR) + else: + self.fail() + + def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): + document = _create_document_node() + elem_node_readonly = Node(node_type=NodeType.ELEMENT_NODE, + node_name='tagName', + owner_document=document, + read_only=True) + elem_node_child = _create_element_node(document) + try: + elem_node_readonly.append_child(elem_node_child) + except DOMException as e: + code = e.args[0] + self.assertEqual(code, DOMException.NO_MODIFICATION_ALLOWED_ERR) + else: + self.fail() + + if __name__ == '__main__': unittest.main() From 25edea3d6c34d3a57f89c06235d8a3b652823d6d Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 13:55:53 +0900 Subject: [PATCH 10/22] #16 Disable linter for intended errors in unittest --- w3/python/core/fundamental_interface/Node_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index 18a39d7..7438862 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -124,12 +124,13 @@ def testSetter_Raises_Exception(self): parent_node = _create_element_node(document) child_node = _create_element_node(document) try: - child_node.parent_node = parent_node + child_node.parent_node = parent_node # type: ignore except: self.assertNotEqual(child_node.parent_node, parent_node) else: self.fail() + class Test_InsertBefore(unittest.TestCase): def test_WithoutRefNode(self): document = _create_document_node() @@ -233,7 +234,6 @@ def test_Raises_NOT_FOUND_ERR(self): self.fail() - class Test_AppendChild(unittest.TestCase): def test_AppendNewChild(self): document = _create_document_node() From ec6f7f958cf21330b7f92ee8a4d06ce25847bb83 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 13:57:32 +0900 Subject: [PATCH 11/22] #16 Fix for failed unittest of `Node.append_child()` failed test: `test_AppendExistingChild()` --- w3/python/core/fundamental_interface/Node.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 801e4c9..be69d10 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -322,7 +322,9 @@ def append_child(self, new_child: _AnyNode) -> _AnyNode: raise DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR) if self.owner_document is not new_child.owner_document: raise DOMException(DOMException.WRONG_DOCUMENT_ERR) - # `HIERARCHY_REQUEST_ERR` should be checked on subclasses by overriding. + # `HIERARCHY_REQUEST_ERR` should be checked on subclasses by overriding. # `HIERARCHY_REQUEST_ERR` should be checked on subclasses by overriding. + if new_child in self.child_nodes: + self.child_nodes.remove(new_child) if new_child.node_type == NodeType.DOCUMENT_FRAGMENT_NODE: grand_child_node: _AnyNode for grand_child_node in new_child.child_nodes: From f51f5a980e9ecb6b842866fba93ebf6ee8fb5914 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 14:41:31 +0900 Subject: [PATCH 12/22] #16 Create method `Node.replace_child()` --- w3/python/core/fundamental_interface/Node.py | 41 ++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index be69d10..8a383c2 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -301,6 +301,47 @@ def insert_before(self, new_child._set_parent_node(self) return new_child + def replace_child(self, + new_child: _AnyNode, + old_child: _AnyNode) -> _AnyNode: + """Replaces the child node `old_child` with `new_child` in the list of children, and returns the `old_child` node. + + If the `new_child` is already in the tree, it is first removed. + + Args: + new_child: The new node to put in the child list. + old_child: The node being replaced in the list. + + Returns: + The node replaced. + + Raisees: + DOMException: + - `HIERARCHY_REQUEST_ERR`: Raised if this node is of a type that does not allow children of the type of the `new_child` node, or it the node to put in is one of this node's ancestors. + - `WRONG_DOCUMENT_ERR`: Raised if `new_child` was created from a different document than the one that created this node. + - `NO_MODIFICATION_ALLOWED_ERR`: Raised if this node is readonly. + - `NOT_FOUND_ERR`: Raised if `old_child` is not a child of this node. + """ + # `HIERARCHY_REQUEST_ERR` should be checked on subclasses by overriding. + if self._read_only: + raise DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR) + if new_child.owner_document is not self.owner_document: + raise DOMException(DOMException.WRONG_DOCUMENT_ERR) + if old_child not in self.child_nodes: + raise DOMException(DOMException.NOT_FOUND_ERR) + # If `new_child` and `old_child` share the same reference, + # this method does nothing. + if new_child is old_child: + return old_child + # If the `new_child` is already in the tree, + # it is first removed. + if new_child in self.child_nodes: + self.child_nodes.remove(new_child) + repl_index = self.child_nodes.index(old_child) + self.child_nodes[repl_index] = new_child + new_child._set_parent_node(self) + return old_child + def append_child(self, new_child: _AnyNode) -> _AnyNode: """Adds the node `new_child` to the end of the list of children of this node. From 7c5ed537790bee97cc54104a9d617f6abc1f4579 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 15:12:18 +0900 Subject: [PATCH 13/22] #16 Add comment for `Node.insert_before()` --- w3/python/core/fundamental_interface/Node.py | 38 ++++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 8a383c2..3a180f3 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -280,24 +280,40 @@ def insert_before(self, - `NO_MODIFICATION_ALLOWED_ERR`: Raised if this node is readonly. - `NOT_FOUND_ERR`: Raised if `ref_child` is not a child of this node. """ + # `HIERARCHY_REQUEST_ERR` should be checked on subclasses by overriding. if self._read_only: raise DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR) - if self.owner_document is not new_child.owner_document: + if new_child.owner_document is not self.owner_document: raise DOMException(DOMException.WRONG_DOCUMENT_ERR) - # `HIERARCHY_REQUEST_ERR` should be checked on subclasses by overriding. - if new_child in self.child_nodes: - self.child_nodes.remove(new_child) + if ref_child is not None: + if ref_child not in self.child_nodes: + raise DOMException(DOMException.NOT_FOUND_ERR) + # If `new_child` and `old_child` share the same reference, + # this method does nothing. + if new_child is ref_child: + return new_child + # If `ref_child` is null, insert `new_child` at the end of the list of children. + # + # This operation is equivalent to the `append_child()` method. + if ref_child is None: + self.append_child(new_child) + return new_child + # If `new_child` is a `DocumentFragment` object, + # all of its children are inserted, in the same order. + # + # This is done by recursive calls. if new_child.node_type == NodeType.DOCUMENT_FRAGMENT_NODE: grand_child_node: _AnyNode for grand_child_node in new_child.child_nodes: self.insert_before(grand_child_node, ref_child) - elif ref_child is None: - self.child_nodes.append(new_child) - elif ref_child not in self.child_nodes: - raise DOMException(DOMException.NOT_FOUND_ERR) - else: - self.child_nodes.insert(self.child_nodes.index(ref_child), - new_child) + return new_child + # If the `new_child` is already in the tree, + # it is first removed. + if new_child in self.child_nodes: + self.child_nodes.remove(new_child) + # Otherwise, simply insert `new_child` using the methods of `NodeList(list)`. + ref_index = self.child_nodes.index(ref_child) + self.child_nodes.insert(ref_index, new_child) new_child._set_parent_node(self) return new_child From 2fcf3a099800f9a063b579e7715bd56c5f0d330d Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 15:12:30 +0900 Subject: [PATCH 14/22] #16 Add comment for `Node.append_child()` --- w3/python/core/fundamental_interface/Node.py | 21 +++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 3a180f3..a019163 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -375,20 +375,27 @@ def append_child(self, new_child: _AnyNode) -> _AnyNode: - `WRONG_DOCUMENT_ERR`: Raised if `new_child` was created from a different document than the one that created this node. - `NO_MODIFICATION_ALLOWED_ERR`: Raised if this node is readonly. """ + # `HIERARCHY_REQUEST_ERR` should be checked on subclasses by overriding. if self._read_only: raise DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR) - if self.owner_document is not new_child.owner_document: + if new_child.owner_document is not self.owner_document: raise DOMException(DOMException.WRONG_DOCUMENT_ERR) - # `HIERARCHY_REQUEST_ERR` should be checked on subclasses by overriding. # `HIERARCHY_REQUEST_ERR` should be checked on subclasses by overriding. - if new_child in self.child_nodes: - self.child_nodes.remove(new_child) + # If `new_child` is a `DocumentFragment` object, + # all of its children are appended, in the same order. + # + # This is done by recursive calls. if new_child.node_type == NodeType.DOCUMENT_FRAGMENT_NODE: grand_child_node: _AnyNode for grand_child_node in new_child.child_nodes: self.append_child(grand_child_node) - else: - new_child._set_parent_node(self) - self.child_nodes.append(new_child) + return new_child + # If the `new_child` is already in the tree, + # it is first removed. + if new_child in self.child_nodes: + self.child_nodes.remove(new_child) + # Otherwise, simply append `new_child` using the methods of `NodeList(list)`. + self.child_nodes.append(new_child) + new_child._set_parent_node(self) return new_child def has_child_nodes(self) -> bool: From ddb96756609fe73ca3ca8865dc8e61875013ba23 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 15:47:38 +0900 Subject: [PATCH 15/22] #16 Add comments; DOM structure prepared for unit testing --- .../core/fundamental_interface/Node_test.py | 268 ++++++++++++++---- 1 file changed, 216 insertions(+), 52 deletions(-) diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index 7438862..bd93191 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -133,45 +133,76 @@ def testSetter_Raises_Exception(self): class Test_InsertBefore(unittest.TestCase): def test_WithoutRefNode(self): + # ====================================== + # + # + # + # + # ====================================== document = _create_document_node() parent_node = _create_element_node(document) - child_node = _create_element_node(document) + new_child_node = _create_element_node(document) # Testing - parent_node.insert_before(child_node) - self.assertEqual(child_node.parent_node, parent_node) - self.assertEqual(parent_node.child_nodes.item(0), child_node) + parent_node.insert_before(new_child_node) + self.assertEqual(new_child_node.parent_node, parent_node) + self.assertEqual(parent_node.child_nodes.item(0), new_child_node) self.assertEqual(parent_node.child_nodes.length, 1) def test_WithRefNode(self): + # ====================================== + # + # + # + # + # + # + # + # ====================================== document = _create_document_node() parent_node = _create_element_node(document) - first_child_node = _create_element_node(document) - second_child_node = _create_element_node(document) - # Warning: this is assuming that `append_child()` method works properly. - parent_node.append_child(second_child_node) + new_child_node = _create_element_node(document) + ref_child_node = _create_element_node(document) + parent_node.append_child(ref_child_node) # Testing - parent_node.insert_before(first_child_node, second_child_node) - self.assertEqual(first_child_node.parent_node, parent_node) - self.assertEqual(parent_node.child_nodes.item(0), first_child_node) - self.assertEqual(parent_node.child_nodes.item(1), second_child_node) + parent_node.insert_before(new_child_node, ref_child_node) + self.assertEqual(new_child_node.parent_node, parent_node) + self.assertEqual(parent_node.child_nodes.item(0), new_child_node) + self.assertEqual(parent_node.child_nodes.item(1), ref_child_node) self.assertEqual(parent_node.child_nodes.length, 2) def test_InsertExistingChild(self): + # ====================================== + # + # + # + # + # + # + # ====================================== document = _create_document_node() parent_node = _create_element_node(document) - first_child_node = _create_element_node(document) - second_child_node = _create_element_node(document) - # Warning: this is assuming that `append_child()` method works properly. - parent_node.append_child(first_child_node) - parent_node.append_child(second_child_node) + ref_child_node = _create_element_node(document) + new_child_node = _create_element_node(document) + parent_node.append_child(ref_child_node) + parent_node.append_child(new_child_node) # Testing - parent_node.insert_before(second_child_node, first_child_node) - self.assertEqual(second_child_node.parent_node, parent_node) - self.assertEqual(parent_node.child_nodes.item(0), second_child_node) - self.assertEqual(parent_node.child_nodes.item(1), first_child_node) + parent_node.insert_before(new_child_node, ref_child_node) + self.assertEqual(new_child_node.parent_node, parent_node) + self.assertEqual(parent_node.child_nodes.item(0), new_child_node) + self.assertEqual(parent_node.child_nodes.item(1), ref_child_node) self.assertEqual(parent_node.child_nodes.length, 2) def test_InsertDocumentFragmentNode(self): + # ====================================== + # + # + # + # + # + # + # + # + # ====================================== document = _create_document_node() parent_node = _create_element_node(document) docfrag_node = Node(node_type=NodeType.DOCUMENT_FRAGMENT_NODE, @@ -179,7 +210,6 @@ def test_InsertDocumentFragmentNode(self): owner_document=document) first_child_node = _create_element_node(document) second_child_node = _create_element_node(document) - # Warning: this is assuming that `append_child()` method works properly. docfrag_node.append_child(first_child_node) docfrag_node.append_child(second_child_node) # Testing @@ -192,6 +222,15 @@ def test_Raises_HIERARCHY_REQUEST_ERR(self): self.skipTest(NotImplemented) # TODO def test_Raises_WRONG_DOCUMENT_ERR(self): + # ====================================== + # + # + # + # + # + # + # + # ====================================== document_1 = _create_document_node() document_2 = _create_document_node() elem_node_1 = _create_element_node(document_1) @@ -205,14 +244,20 @@ def test_Raises_WRONG_DOCUMENT_ERR(self): self.fail() def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): + # ====================================== + # + # + # + # + # ====================================== document = _create_document_node() - elem_node_readonly = Node(node_type=NodeType.ELEMENT_NODE, - node_name='tagName', - owner_document=document, - read_only=True) - elem_node_child = _create_element_node(document) + parent_node_readonly = Node(node_type=NodeType.ELEMENT_NODE, + node_name='tagName', + owner_document=document, + read_only=True) + new_child_node = _create_element_node(document) try: - elem_node_readonly.insert_before(elem_node_child) + parent_node_readonly.insert_before(new_child_node) except DOMException as e: code = e.args[0] self.assertEqual(code, DOMException.NO_MODIFICATION_ALLOWED_ERR) @@ -220,13 +265,20 @@ def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): self.fail() def test_Raises_NOT_FOUND_ERR(self): + # ====================================== + # + # + # + # + # + # ====================================== document = _create_document_node() - elem_node_parent = _create_element_node(document) - elem_node_child = _create_element_node(document) - elem_node_error = _create_element_node(document) + parent_node = _create_element_node(document) + new_child_node = _create_element_node(document) + ref_child_node = _create_element_node(document) # Testing try: - elem_node_parent.insert_before(elem_node_child, elem_node_error) + parent_node.insert_before(new_child_node, ref_child_node) except DOMException as e: code = e.args[0] self.assertEqual(code, DOMException.NOT_FOUND_ERR) @@ -236,31 +288,54 @@ def test_Raises_NOT_FOUND_ERR(self): class Test_AppendChild(unittest.TestCase): def test_AppendNewChild(self): + # ====================================== + # + # + # + # + # ====================================== document = _create_document_node() parent_node = _create_element_node(document) - child_node = _create_element_node(document) + new_child_node = _create_element_node(document) # Testing - parent_node.append_child(child_node) - self.assertEqual(child_node.parent_node, parent_node) - self.assertEqual(parent_node.child_nodes.item(0), child_node) + parent_node.append_child(new_child_node) + self.assertEqual(new_child_node.parent_node, parent_node) + self.assertEqual(parent_node.child_nodes.item(0), new_child_node) self.assertEqual(parent_node.child_nodes.length, 1) def test_AppendExistingChild(self): + # ====================================== + # + # + # + # + # + # + # ====================================== document = _create_document_node() parent_node = _create_element_node(document) - first_child_node = _create_element_node(document) - second_child_node = _create_element_node(document) - # Warning: this is assuming that `append_child()` has passed `test_AppendNewChild()` test. - parent_node.append_child(first_child_node) - parent_node.append_child(second_child_node) + new_child_node = _create_element_node(document) + old_child_node = _create_element_node(document) + parent_node.append_child(new_child_node) + parent_node.append_child(old_child_node) # Testing - parent_node.append_child(first_child_node) - self.assertEqual(second_child_node.parent_node, parent_node) - self.assertEqual(parent_node.child_nodes.item(0), second_child_node) - self.assertEqual(parent_node.child_nodes.item(1), first_child_node) + parent_node.append_child(new_child_node) + self.assertEqual(old_child_node.parent_node, parent_node) + self.assertEqual(parent_node.child_nodes.item(0), old_child_node) + self.assertEqual(parent_node.child_nodes.item(1), new_child_node) self.assertEqual(parent_node.child_nodes.length, 2) def test_AppendDocumentFragmentNode(self): + # ====================================== + # + # + # + # + # + # + # + # + # ====================================== document = _create_document_node() parent_node = _create_element_node(document) docfrag_node = Node(node_type=NodeType.DOCUMENT_FRAGMENT_NODE, @@ -268,7 +343,6 @@ def test_AppendDocumentFragmentNode(self): owner_document=document) first_child_node = _create_element_node(document) second_child_node = _create_element_node(document) - # Warning: this is assuming that `append_child()` has passed `test_AppendNewChild()` test. docfrag_node.append_child(first_child_node) docfrag_node.append_child(second_child_node) # Testing @@ -281,6 +355,15 @@ def test_Raises_HIERARCHY_REQUEST_ERR(self): self.skipTest(NotImplemented) # TODO def test_Raises_WRONG_DOCUMENT_ERR(self): + # ====================================== + # + # + # + # + # + # + # + # ====================================== document_1 = _create_document_node() document_2 = _create_document_node() elem_node_1 = _create_element_node(document_1) @@ -294,14 +377,95 @@ def test_Raises_WRONG_DOCUMENT_ERR(self): self.fail() def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): + # ====================================== + # + # + # + # + # ====================================== + document = _create_document_node() + parent_node_readonly = Node(node_type=NodeType.ELEMENT_NODE, + node_name='tagName', + owner_document=document, + read_only=True) + new_child_node = _create_element_node(document) + try: + parent_node_readonly.append_child(new_child_node) + except DOMException as e: + code = e.args[0] + self.assertEqual(code, DOMException.NO_MODIFICATION_ALLOWED_ERR) + else: + self.fail() + + +class Test_ReplaceChild(unittest.TestCase): + def test_ReplaceExistingChild(self): + # ====================================== + # + # + # + # + # + # + # + # ====================================== + document = _create_document_node() + parent_node = _create_element_node(document) + new_child_node = _create_element_node(document) + old_child_node = _create_element_node(document) + parent_node.append_child(old_child_node) + # Testing + parent_node.replace_child(new_child_node, old_child_node) + self.assertIn(new_child_node, parent_node.child_nodes) + self.assertNotIn(old_child_node, parent_node.child_nodes) + self.assertEqual(new_child_node.parent_node, parent_node) + self.assertEqual(parent_node.child_nodes.item(0), new_child_node) + self.assertEqual(parent_node.child_nodes.length, 1) + + def test_Raises_HIERARCHY_REQUEST_ERR(self): + self.skipTest(NotImplemented) # TODO + + def test_Raises_WRONG_DOCUMENT_ERR(self): + # ====================================== + # + # + # + # + # + # + # + # + # + # ====================================== + document_1 = _create_document_node() + document_2 = _create_document_node() + parent_node = _create_element_node(document_1) + old_child_node = _create_element_node(document_1) + new_child_node = _create_element_node(document_2) + parent_node.append_child(old_child_node) + try: + parent_node.replace_child(new_child_node, old_child_node) + except DOMException as e: + code = e.args[0] + self.assertEqual(code, DOMException.WRONG_DOCUMENT_ERR) + else: + self.fail() + + def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): + # ====================================== + # + # + # + # + # ====================================== document = _create_document_node() - elem_node_readonly = Node(node_type=NodeType.ELEMENT_NODE, - node_name='tagName', - owner_document=document, - read_only=True) - elem_node_child = _create_element_node(document) + parent_node_readonly = Node(node_type=NodeType.ELEMENT_NODE, + node_name='tagName', + owner_document=document, + read_only=True) + new_child_node = _create_element_node(document) try: - elem_node_readonly.append_child(elem_node_child) + parent_node_readonly.append_child(new_child_node) except DOMException as e: code = e.args[0] self.assertEqual(code, DOMException.NO_MODIFICATION_ALLOWED_ERR) From db8150238dde789434fd39db4cec27f54bbb6832 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 15:55:05 +0900 Subject: [PATCH 16/22] #16 Create method `Node.remove_child()` --- w3/python/core/fundamental_interface/Node.py | 31 ++++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index a019163..a85ced5 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -310,7 +310,7 @@ def insert_before(self, # If the `new_child` is already in the tree, # it is first removed. if new_child in self.child_nodes: - self.child_nodes.remove(new_child) + self.remove_child(new_child) # Otherwise, simply insert `new_child` using the methods of `NodeList(list)`. ref_index = self.child_nodes.index(ref_child) self.child_nodes.insert(ref_index, new_child) @@ -352,12 +352,37 @@ def replace_child(self, # If the `new_child` is already in the tree, # it is first removed. if new_child in self.child_nodes: - self.child_nodes.remove(new_child) + self.remove_child(new_child) repl_index = self.child_nodes.index(old_child) self.child_nodes[repl_index] = new_child new_child._set_parent_node(self) return old_child + def remove_child(self, + old_child: _AnyNode) -> _AnyNode: + """Removes the child node indicated by `old_chlid` from the list of children, and returns it. + + Args: + old_chlid: The node being removed. + + Returns: + The node removed. + + Raises: + DOMException: + - `NO_MODIFICATION_ALLOWED_ERR`: Raised if this node is readonly. + - `NOT_FOUND_ERR`: Raised if `old_chlid` is not a child of this node. + """ + # `HIERARCHY_REQUEST_ERR` should be checked on subclasses by overriding. + if self._read_only: + raise DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR) + if old_child not in self.child_nodes: + raise DOMException(DOMException.NOT_FOUND_ERR) + # Removes node using the method of `NodeList(list)`. + self.child_nodes.remove(old_child) + old_child._set_parent_node(None) + return old_child + def append_child(self, new_child: _AnyNode) -> _AnyNode: """Adds the node `new_child` to the end of the list of children of this node. @@ -392,7 +417,7 @@ def append_child(self, new_child: _AnyNode) -> _AnyNode: # If the `new_child` is already in the tree, # it is first removed. if new_child in self.child_nodes: - self.child_nodes.remove(new_child) + self.remove_child(new_child) # Otherwise, simply append `new_child` using the methods of `NodeList(list)`. self.child_nodes.append(new_child) new_child._set_parent_node(self) From 2e78547903eccdf5ed46d0a266dd4a3300ea4eda Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 17:13:25 +0900 Subject: [PATCH 17/22] #16 Create method `Node.clone_node()`. and its accessor methods; `Node._shallow_copy()` and `Node._deep_copy()` --- w3/python/core/fundamental_interface/Node.py | 46 ++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index a85ced5..a9b347a 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -431,6 +431,52 @@ def has_child_nodes(self) -> bool: """ return bool(self.child_nodes) + def clone_node(self, deep: bool = False) -> _AnyNode: + """Returns a duplicate of this node. + + i.e., serves as a generic copy constructor for nodes. The duplicate node has no parent (parentNode returns `None`.). + Cloning an `Element` copies all attributes and their values, including those generated by the XML processor to represent defaulted attributes, but this method does not copy any text it contains unless it is a deep clone, since the text is contained in a child `Text` node. + Cloning any other type of node simply returns a copy of this node. + + Args: + deep: If `True`, recursively clone the subtree under the specified node; if `False`, clone only the node itself (and its attributes, if it is an `Element`). + + Returns: + The duplicate node. + + This method raises no exceptions. + """ + if deep: + return self._deep_copy() + else: + return self._shallow_copy() + + def _shallow_copy(self) -> _AnyNode: + node = self.__class__( + owner_document=self.owner_document, + node_type=self.node_type, + node_name=self.node_name, + node_value=self.node_value, + read_only=self._read_only + ) + return node + + def _deep_copy(self) -> _AnyNode: + def copy_recursive(node_iterable: Iterable[_AnyNode]): + node: _AnyNode + for node in node_iterable: + yield node.clone_node(True) + node = self.__class__( + owner_document=self.owner_document, + node_type=self.node_type, + node_name=self.node_name, + node_value=self.node_value, + child_nodes=copy_recursive(self.child_nodes), + attributes=copy_recursive(self.attributes.values()), + read_only=self._read_only + ) + return node + _AnyNode = Node _NamedNodeMap = Dict[str, _AnyNode] # TODO: Implement NamedNodeMap (#19) From 243c96db7540ee88425233acea1a8b28a1dd9a72 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 17:15:30 +0900 Subject: [PATCH 18/22] #16 Create unittest for `Node.has_child_nodes()` --- .../core/fundamental_interface/Node_test.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index bd93191..475a241 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -473,5 +473,33 @@ def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): self.fail() +class Test_HasChild(unittest.TestCase): + def test_True(self): + # ====================================== + # + # + # + # + # + # ====================================== + document = _create_document_node() + parent_node = _create_element_node(document) + child_node = _create_element_node(document) + parent_node.append_child(child_node) + # Testing + self.assertTrue(parent_node.has_child_nodes()) + + def test_False(self): + # ====================================== + # + # + # + # ====================================== + document = _create_document_node() + node = _create_element_node(document) + # Testing + self.assertFalse(node.has_child_nodes()) + + if __name__ == '__main__': unittest.main() From 70a4885dc69a67678546461b49c8f4f379e5daac Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 18:06:43 +0900 Subject: [PATCH 19/22] #16 Rename test classes and test methods class name: `Test_` method name: `test_` --- .../fundamental_interface/NodeList_test.py | 32 ++++++++++++------- .../core/fundamental_interface/Node_test.py | 18 +++++------ 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/w3/python/core/fundamental_interface/NodeList_test.py b/w3/python/core/fundamental_interface/NodeList_test.py index 3046d79..402bf56 100644 --- a/w3/python/core/fundamental_interface/NodeList_test.py +++ b/w3/python/core/fundamental_interface/NodeList_test.py @@ -34,18 +34,20 @@ def _make_nodes(n: int, document: Optional[Node] = None) -> Iterator[Node]: yield _create_text_node(document) -class Test_Dunder(unittest.TestCase): - def testInit_Empty(self): +class TestDunder_Init(unittest.TestCase): + def test_EmptyList(self): NodeList() - def testInit_SingleNode(self): + def test_SingleNode(self): node = next(_make_nodes(1)) NodeList([node]) - def testInit_MultipleNodes(self): + def test_MultipleNodes(self): NodeList(_make_nodes(4)) - def testIter(self): + +class TestDunder_Iter(unittest.TestCase): + def test_ForLoop(self): nodes = [*_make_nodes(4)] node_list = NodeList(nodes) # Create an iterator for checking @@ -53,7 +55,9 @@ def testIter(self): for list_elem in node_list: self.assertEqual(list_elem, next(node_iter)) - def testBool(self): + +class TestDunder_Bool(unittest.TestCase): + def test_Raw(self): # Empty `NodeList` should equal False. node_list = NodeList() self.assertFalse(node_list) @@ -61,20 +65,26 @@ def testBool(self): node_list = NodeList(_make_nodes(2)) self.assertTrue(node_list) - def testGetItem(self): + +class TestDunder_GetItem(unittest.TestCase): + def test_IntegerIndex(self): nodes = [*_make_nodes(4)] node_list = NodeList(nodes) for i in range(4): self.assertEqual(node_list[i], nodes[i]) - def testSetItem(self): + +class TestDunder_SetItem(unittest.TestCase): + def test_IntegerIndex(self): document = _create_document_node() text_node = _create_text_node(document) node_list = NodeList(_make_nodes(4, document)) node_list[2] = text_node self.assertEqual(node_list[2], text_node) - def testContains(self): + +class TestDunder_Contains(unittest.TestCase): + def test_In(self): nodes = [*_make_nodes(4)] node_list = NodeList(nodes) for n in node_list: @@ -87,7 +97,7 @@ def testContains_NotIn(self): self.assertNotIn(external_node, node_list) -class Test_Length(unittest.TestCase): +class TestProperty_Length(unittest.TestCase): def test_Empty(self): node_list = NodeList() self.assertEqual(node_list.length, 0) @@ -101,7 +111,7 @@ def test_SomeItems(self): self.assertEqual(node_list.length, 5) -class Test_Item(unittest.TestCase): +class TestMethod_Item(unittest.TestCase): def test_InSize(self): nodes = [*_make_nodes(5)] node_list = NodeList(nodes) diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index 475a241..b06ad79 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -18,8 +18,8 @@ def _create_element_node(document: Node): owner_document=document) -class Test_Dunder(unittest.TestCase): - def testInit(self): +class TestDunder_Init(unittest.TestCase): + def test_Default(self): # Creating document node. document = Node(node_type=NodeType.DOCUMENT_NODE, node_name='#document', @@ -30,7 +30,7 @@ def testInit(self): self.assertEqual(document.node_value, '') -class Test_NodeValue(unittest.TestCase): +class TestProperty_NodeValue(unittest.TestCase): def testGetter(self): document = _create_document_node() text = Node(node_type=NodeType.TEXT_NODE, @@ -75,7 +75,7 @@ def testSetter_ReadOnly(self): self.assertEqual(text.node_value, 'foo') -class Test_NodeType(unittest.TestCase): +class TestProperty_NodeType(unittest.TestCase): def testGetter(self): document = _create_document_node() for node_type in NodeType: @@ -103,7 +103,7 @@ def testSetter_WrongTypes(self): pass -class Test_ParentNode(unittest.TestCase): +class TestProperty_ParentNode(unittest.TestCase): def testConstrutor(self): document = _create_document_node() docfrag = Node(node_type=NodeType.DOCUMENT_FRAGMENT_NODE, @@ -131,7 +131,7 @@ def testSetter_Raises_Exception(self): self.fail() -class Test_InsertBefore(unittest.TestCase): +class TestMethod_InsertBefore(unittest.TestCase): def test_WithoutRefNode(self): # ====================================== # @@ -286,7 +286,7 @@ def test_Raises_NOT_FOUND_ERR(self): self.fail() -class Test_AppendChild(unittest.TestCase): +class TestMethod_AppendChild(unittest.TestCase): def test_AppendNewChild(self): # ====================================== # @@ -398,7 +398,7 @@ def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): self.fail() -class Test_ReplaceChild(unittest.TestCase): +class TestMethod_ReplaceChild(unittest.TestCase): def test_ReplaceExistingChild(self): # ====================================== # @@ -473,7 +473,7 @@ def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): self.fail() -class Test_HasChild(unittest.TestCase): +class TestMethod_HasChild(unittest.TestCase): def test_True(self): # ====================================== # From 2cfc7c5465b28f055b9af550c18aca10137b57d5 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 20:28:10 +0900 Subject: [PATCH 20/22] Use `TestCase.setUp()` for prepraing each test cases. --- .../core/fundamental_interface/Node_test.py | 229 ++++++++++++------ 1 file changed, 149 insertions(+), 80 deletions(-) diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index b06ad79..dc9d7c3 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -31,37 +31,37 @@ def test_Default(self): class TestProperty_NodeValue(unittest.TestCase): + def setUp(self) -> None: + self.document = _create_document_node() + return super().setUp() + def testGetter(self): - document = _create_document_node() text = Node(node_type=NodeType.TEXT_NODE, node_name='#text', - owner_document=document, + owner_document=self.document, node_value='lorem ipsum') self.assertEqual(text.node_value, 'lorem ipsum') def testConstructor(self): - document = _create_document_node() text = Node(node_type=NodeType.TEXT_NODE, node_name='#text', - owner_document=document, + owner_document=self.document, node_value='foo', read_only=False) self.assertEqual(text.node_value, 'foo') def testSetter(self): - document = _create_document_node() text = Node(node_type=NodeType.TEXT_NODE, node_name='#text', - owner_document=document, + owner_document=self.document, read_only=False) text.node_value = 'bar' self.assertEqual(text.node_value, 'bar') def testSetter_ReadOnly(self): - document = _create_document_node() text = Node(node_type=NodeType.TEXT_NODE, node_name='#text', - owner_document=document, + owner_document=self.document, node_value='foo', read_only=True) try: @@ -76,53 +76,58 @@ def testSetter_ReadOnly(self): class TestProperty_NodeType(unittest.TestCase): + def setUp(self) -> None: + self.document = _create_document_node() + return super().setUp() + def testGetter(self): - document = _create_document_node() for node_type in NodeType: node = Node(node_type=node_type, node_name='', - owner_document=document) + owner_document=self.document) self.assertEqual(node.node_type, node_type) def testSetter_CorrectTypes(self): - document = _create_document_node() for node_type in NodeType: - Node(node_type=node_type, - node_name='', - owner_document=document) + with self.subTest(node_type=node_type): + Node(node_type=node_type, + node_name='', + owner_document=self.document) def testSetter_WrongTypes(self): - document = _create_document_node() for node_type in [-1, None, 'hi', True, Node, NodeType, 'DOCUMENT_NODE']: - try: - Node(node_type=node_type, - node_name='', - owner_document=document) - self.fail() - except Exception: - pass + with self.subTest(node_type=node_type): + try: + Node(node_type=node_type, + node_name='', + owner_document=self.document) + except Exception: + pass + else: + self.fail() class TestProperty_ParentNode(unittest.TestCase): + def setUp(self) -> None: + self.document = _create_document_node() + return super().setUp() + def testConstrutor(self): - document = _create_document_node() docfrag = Node(node_type=NodeType.DOCUMENT_FRAGMENT_NODE, node_name='#document-fragment', - owner_document=document) + owner_document=self.document) self.assertIsNone(docfrag.parent_node) def testGetter(self): - document = _create_document_node() - parent_node = _create_element_node(document) - child_node = _create_element_node(document) + parent_node = _create_element_node(self.document) + child_node = _create_element_node(self.document) # Warning: this is assuming that `append_child()` method works properly. parent_node.append_child(child_node) self.assertEqual(child_node.parent_node, parent_node) def testSetter_Raises_Exception(self): - document = _create_document_node() - parent_node = _create_element_node(document) - child_node = _create_element_node(document) + parent_node = _create_element_node(self.document) + child_node = _create_element_node(self.document) try: child_node.parent_node = parent_node # type: ignore except: @@ -132,6 +137,10 @@ def testSetter_Raises_Exception(self): class TestMethod_InsertBefore(unittest.TestCase): + def setUp(self) -> None: + self.document = _create_document_node() + return super().setUp() + def test_WithoutRefNode(self): # ====================================== # @@ -139,9 +148,8 @@ def test_WithoutRefNode(self): # # # ====================================== - document = _create_document_node() - parent_node = _create_element_node(document) - new_child_node = _create_element_node(document) + parent_node = _create_element_node(self.document) + new_child_node = _create_element_node(self.document) # Testing parent_node.insert_before(new_child_node) self.assertEqual(new_child_node.parent_node, parent_node) @@ -158,10 +166,9 @@ def test_WithRefNode(self): # # # ====================================== - document = _create_document_node() - parent_node = _create_element_node(document) - new_child_node = _create_element_node(document) - ref_child_node = _create_element_node(document) + parent_node = _create_element_node(self.document) + new_child_node = _create_element_node(self.document) + ref_child_node = _create_element_node(self.document) parent_node.append_child(ref_child_node) # Testing parent_node.insert_before(new_child_node, ref_child_node) @@ -179,10 +186,9 @@ def test_InsertExistingChild(self): # # # ====================================== - document = _create_document_node() - parent_node = _create_element_node(document) - ref_child_node = _create_element_node(document) - new_child_node = _create_element_node(document) + parent_node = _create_element_node(self.document) + ref_child_node = _create_element_node(self.document) + new_child_node = _create_element_node(self.document) parent_node.append_child(ref_child_node) parent_node.append_child(new_child_node) # Testing @@ -203,13 +209,12 @@ def test_InsertDocumentFragmentNode(self): # # # ====================================== - document = _create_document_node() - parent_node = _create_element_node(document) + parent_node = _create_element_node(self.document) docfrag_node = Node(node_type=NodeType.DOCUMENT_FRAGMENT_NODE, node_name='#document-fragment', - owner_document=document) - first_child_node = _create_element_node(document) - second_child_node = _create_element_node(document) + owner_document=self.document) + first_child_node = _create_element_node(self.document) + second_child_node = _create_element_node(self.document) docfrag_node.append_child(first_child_node) docfrag_node.append_child(second_child_node) # Testing @@ -250,12 +255,11 @@ def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): # # # ====================================== - document = _create_document_node() parent_node_readonly = Node(node_type=NodeType.ELEMENT_NODE, node_name='tagName', - owner_document=document, + owner_document=self.document, read_only=True) - new_child_node = _create_element_node(document) + new_child_node = _create_element_node(self.document) try: parent_node_readonly.insert_before(new_child_node) except DOMException as e: @@ -272,10 +276,9 @@ def test_Raises_NOT_FOUND_ERR(self): # # # ====================================== - document = _create_document_node() - parent_node = _create_element_node(document) - new_child_node = _create_element_node(document) - ref_child_node = _create_element_node(document) + parent_node = _create_element_node(self.document) + new_child_node = _create_element_node(self.document) + ref_child_node = _create_element_node(self.document) # Testing try: parent_node.insert_before(new_child_node, ref_child_node) @@ -287,6 +290,10 @@ def test_Raises_NOT_FOUND_ERR(self): class TestMethod_AppendChild(unittest.TestCase): + def setUp(self) -> None: + self.document = _create_document_node() + return super().setUp() + def test_AppendNewChild(self): # ====================================== # @@ -294,9 +301,8 @@ def test_AppendNewChild(self): # # # ====================================== - document = _create_document_node() - parent_node = _create_element_node(document) - new_child_node = _create_element_node(document) + parent_node = _create_element_node(self.document) + new_child_node = _create_element_node(self.document) # Testing parent_node.append_child(new_child_node) self.assertEqual(new_child_node.parent_node, parent_node) @@ -312,10 +318,9 @@ def test_AppendExistingChild(self): # # # ====================================== - document = _create_document_node() - parent_node = _create_element_node(document) - new_child_node = _create_element_node(document) - old_child_node = _create_element_node(document) + parent_node = _create_element_node(self.document) + new_child_node = _create_element_node(self.document) + old_child_node = _create_element_node(self.document) parent_node.append_child(new_child_node) parent_node.append_child(old_child_node) # Testing @@ -336,13 +341,12 @@ def test_AppendDocumentFragmentNode(self): # # # ====================================== - document = _create_document_node() - parent_node = _create_element_node(document) + parent_node = _create_element_node(self.document) docfrag_node = Node(node_type=NodeType.DOCUMENT_FRAGMENT_NODE, node_name='#document-fragment', - owner_document=document) - first_child_node = _create_element_node(document) - second_child_node = _create_element_node(document) + owner_document=self.document) + first_child_node = _create_element_node(self.document) + second_child_node = _create_element_node(self.document) docfrag_node.append_child(first_child_node) docfrag_node.append_child(second_child_node) # Testing @@ -383,12 +387,11 @@ def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): # # # ====================================== - document = _create_document_node() parent_node_readonly = Node(node_type=NodeType.ELEMENT_NODE, node_name='tagName', - owner_document=document, + owner_document=self.document, read_only=True) - new_child_node = _create_element_node(document) + new_child_node = _create_element_node(self.document) try: parent_node_readonly.append_child(new_child_node) except DOMException as e: @@ -399,6 +402,10 @@ def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): class TestMethod_ReplaceChild(unittest.TestCase): + def setUp(self) -> None: + self.document = _create_document_node() + return super().setUp() + def test_ReplaceExistingChild(self): # ====================================== # @@ -409,10 +416,9 @@ def test_ReplaceExistingChild(self): # # # ====================================== - document = _create_document_node() - parent_node = _create_element_node(document) - new_child_node = _create_element_node(document) - old_child_node = _create_element_node(document) + parent_node = _create_element_node(self.document) + new_child_node = _create_element_node(self.document) + old_child_node = _create_element_node(self.document) parent_node.append_child(old_child_node) # Testing parent_node.replace_child(new_child_node, old_child_node) @@ -458,12 +464,11 @@ def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): # # # ====================================== - document = _create_document_node() parent_node_readonly = Node(node_type=NodeType.ELEMENT_NODE, node_name='tagName', - owner_document=document, + owner_document=self.document, read_only=True) - new_child_node = _create_element_node(document) + new_child_node = _create_element_node(self.document) try: parent_node_readonly.append_child(new_child_node) except DOMException as e: @@ -474,6 +479,10 @@ def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): class TestMethod_HasChild(unittest.TestCase): + def setUp(self) -> None: + self.document = _create_document_node() + return super().setUp() + def test_True(self): # ====================================== # @@ -482,9 +491,8 @@ def test_True(self): # # # ====================================== - document = _create_document_node() - parent_node = _create_element_node(document) - child_node = _create_element_node(document) + parent_node = _create_element_node(self.document) + child_node = _create_element_node(self.document) parent_node.append_child(child_node) # Testing self.assertTrue(parent_node.has_child_nodes()) @@ -495,11 +503,72 @@ def test_False(self): # # # ====================================== - document = _create_document_node() - node = _create_element_node(document) + node = _create_element_node(self.document) # Testing self.assertFalse(node.has_child_nodes()) +class TestMethod_RemoveChild(unittest.TestCase): + def setUp(self) -> None: + self.document = _create_document_node() + return super().setUp() + + def test_RemoveExistingChlid(self): + # ====================================== + # + # + # + # + # + # ====================================== + parent_node = _create_element_node(self.document) + child_node = _create_element_node(self.document) + parent_node.append_child(child_node) + # Testing + parent_node.remove_child(child_node) + self.assertNotIn(child_node, parent_node.child_nodes) + self.assertIsNone(child_node.parent_node) + + def test_Raises_NOT_FOUND_ERR(self): + # ====================================== + # + # + # + # + # ====================================== + parent_node = _create_element_node(self.document) + child_node = _create_element_node(self.document) + # Testing + try: + parent_node.remove_child(child_node) + except DOMException as de: + self.assertEqual(de.args[0], DOMException.NOT_FOUND_ERR) + else: + self.fail() + + def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): + # ====================================== + # + # + # + # + # + # ====================================== + child_node = _create_element_node(self.document) + parent_node = Node(node_type=NodeType.ELEMENT_NODE, + node_name='tagName', + owner_document=self.document, + child_nodes=[child_node], + read_only=True) + # Testing + try: + parent_node.remove_child(child_node) + except DOMException as de: + code = de.args[0] + self.assertEqual(code, DOMException.NO_MODIFICATION_ALLOWED_ERR) + else: + self.fail() + + if __name__ == '__main__': unittest.main() From 74d7f7d292a5537e3b0ed3147cda765b08fd6abe Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 20:34:25 +0900 Subject: [PATCH 21/22] Use `with` statement rather than `try ... except` for unit testing. --- .../core/fundamental_interface/Node_test.py | 103 +++++++----------- 1 file changed, 39 insertions(+), 64 deletions(-) diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index dc9d7c3..281c547 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -64,13 +64,11 @@ def testSetter_ReadOnly(self): owner_document=self.document, node_value='foo', read_only=True) - try: + # Testing + with self.assertRaises(DOMException) as context_manager: text.node_value = 'bar' - except DOMException as e: - code = e.args[0] - self.assertEqual(code, DOMException.NO_MODIFICATION_ALLOWED_ERR) - else: - self.fail() + self.assertEqual(context_manager.exception.args[0], + DOMException.NO_MODIFICATION_ALLOWED_ERR) # `node_value` should not be modified. self.assertEqual(text.node_value, 'foo') @@ -97,14 +95,10 @@ def testSetter_CorrectTypes(self): def testSetter_WrongTypes(self): for node_type in [-1, None, 'hi', True, Node, NodeType, 'DOCUMENT_NODE']: with self.subTest(node_type=node_type): - try: + with self.assertRaises((TypeError, ValueError)): Node(node_type=node_type, node_name='', owner_document=self.document) - except Exception: - pass - else: - self.fail() class TestProperty_ParentNode(unittest.TestCase): @@ -128,6 +122,7 @@ def testGetter(self): def testSetter_Raises_Exception(self): parent_node = _create_element_node(self.document) child_node = _create_element_node(self.document) + # Testing try: child_node.parent_node = parent_node # type: ignore except: @@ -240,13 +235,11 @@ def test_Raises_WRONG_DOCUMENT_ERR(self): document_2 = _create_document_node() elem_node_1 = _create_element_node(document_1) elem_node_2 = _create_element_node(document_2) - try: + # Testing + with self.assertRaises(DOMException) as context_manager: elem_node_1.insert_before(elem_node_2) - except DOMException as e: - code = e.args[0] - self.assertEqual(code, DOMException.WRONG_DOCUMENT_ERR) - else: - self.fail() + self.assertEqual(context_manager.exception.args[0], + DOMException.WRONG_DOCUMENT_ERR) def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): # ====================================== @@ -260,13 +253,11 @@ def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): owner_document=self.document, read_only=True) new_child_node = _create_element_node(self.document) - try: + # Testing + with self.assertRaises(DOMException) as context_manager: parent_node_readonly.insert_before(new_child_node) - except DOMException as e: - code = e.args[0] - self.assertEqual(code, DOMException.NO_MODIFICATION_ALLOWED_ERR) - else: - self.fail() + self.assertEqual(context_manager.exception.args[0], + DOMException.NO_MODIFICATION_ALLOWED_ERR) def test_Raises_NOT_FOUND_ERR(self): # ====================================== @@ -280,13 +271,10 @@ def test_Raises_NOT_FOUND_ERR(self): new_child_node = _create_element_node(self.document) ref_child_node = _create_element_node(self.document) # Testing - try: + with self.assertRaises(DOMException) as context_manager: parent_node.insert_before(new_child_node, ref_child_node) - except DOMException as e: - code = e.args[0] - self.assertEqual(code, DOMException.NOT_FOUND_ERR) - else: - self.fail() + self.assertEqual(context_manager.exception.args[0], + DOMException.NOT_FOUND_ERR) class TestMethod_AppendChild(unittest.TestCase): @@ -372,13 +360,11 @@ def test_Raises_WRONG_DOCUMENT_ERR(self): document_2 = _create_document_node() elem_node_1 = _create_element_node(document_1) elem_node_2 = _create_element_node(document_2) - try: + # Testing + with self.assertRaises(DOMException) as context_manager: elem_node_1.append_child(elem_node_2) - except DOMException as e: - code = e.args[0] - self.assertEqual(code, DOMException.WRONG_DOCUMENT_ERR) - else: - self.fail() + self.assertEqual(context_manager.exception.args[0], + DOMException.WRONG_DOCUMENT_ERR) def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): # ====================================== @@ -392,13 +378,11 @@ def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): owner_document=self.document, read_only=True) new_child_node = _create_element_node(self.document) - try: + # Testing + with self.assertRaises(DOMException) as context_manager: parent_node_readonly.append_child(new_child_node) - except DOMException as e: - code = e.args[0] - self.assertEqual(code, DOMException.NO_MODIFICATION_ALLOWED_ERR) - else: - self.fail() + self.assertEqual(context_manager.exception.args[0], + DOMException.NO_MODIFICATION_ALLOWED_ERR) class TestMethod_ReplaceChild(unittest.TestCase): @@ -449,13 +433,11 @@ def test_Raises_WRONG_DOCUMENT_ERR(self): old_child_node = _create_element_node(document_1) new_child_node = _create_element_node(document_2) parent_node.append_child(old_child_node) - try: + # Testing + with self.assertRaises(DOMException) as context_manager: parent_node.replace_child(new_child_node, old_child_node) - except DOMException as e: - code = e.args[0] - self.assertEqual(code, DOMException.WRONG_DOCUMENT_ERR) - else: - self.fail() + self.assertEqual(context_manager.exception.args[0], + DOMException.WRONG_DOCUMENT_ERR) def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): # ====================================== @@ -469,13 +451,11 @@ def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): owner_document=self.document, read_only=True) new_child_node = _create_element_node(self.document) - try: + # Testing + with self.assertRaises(DOMException) as context_manager: parent_node_readonly.append_child(new_child_node) - except DOMException as e: - code = e.args[0] - self.assertEqual(code, DOMException.NO_MODIFICATION_ALLOWED_ERR) - else: - self.fail() + self.assertEqual(context_manager.exception.args[0], + DOMException.NO_MODIFICATION_ALLOWED_ERR) class TestMethod_HasChild(unittest.TestCase): @@ -539,12 +519,10 @@ def test_Raises_NOT_FOUND_ERR(self): parent_node = _create_element_node(self.document) child_node = _create_element_node(self.document) # Testing - try: + with self.assertRaises(DOMException) as context_manager: parent_node.remove_child(child_node) - except DOMException as de: - self.assertEqual(de.args[0], DOMException.NOT_FOUND_ERR) - else: - self.fail() + self.assertEqual(context_manager.exception.args[0], + DOMException.NOT_FOUND_ERR) def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): # ====================================== @@ -561,13 +539,10 @@ def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): child_nodes=[child_node], read_only=True) # Testing - try: + with self.assertRaises(DOMException) as context_manager: parent_node.remove_child(child_node) - except DOMException as de: - code = de.args[0] - self.assertEqual(code, DOMException.NO_MODIFICATION_ALLOWED_ERR) - else: - self.fail() + self.assertEqual(context_manager.exception.args[0], + DOMException.NO_MODIFICATION_ALLOWED_ERR) if __name__ == '__main__': From 42fb1842253addc6f6f8f113b9299086e30c3c8b Mon Sep 17 00:00:00 2001 From: Hepheir Date: Sun, 6 Jun 2021 20:39:21 +0900 Subject: [PATCH 22/22] Open an issue Make a unittest for `Node.clone_node()` #31 --- w3/python/core/fundamental_interface/Node_test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index 281c547..73c27ce 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -545,5 +545,10 @@ def test_Raises_NO_MODIFICATION_ALLOWED_ERR(self): DOMException.NO_MODIFICATION_ALLOWED_ERR) +class TestMethod_CloneNode(unittest.TestCase): + # TODO + pass + + if __name__ == '__main__': unittest.main()