class TestTree(unittest.TestCase): """Unit tests for the Tree class.""" def setUp(self): document = Document(SYS) self.tree = Tree(document) document.tree = self.tree document = Document(FILES) self.tree._place(document) # pylint: disable=W0212 document.tree = self.tree self.tree._vcs = Mock() # pylint: disable=W0212 @patch('doorstop.core.vcs.find_root', Mock(return_value=EMPTY)) def test_palce_empty(self): """Verify a document can be placed in an empty tree.""" tree = build(EMPTY) doc = MockDocumentSkip.new(tree, os.path.join(EMPTY, 'temp'), EMPTY, 'TEMP') tree._place(doc) # pylint: disable=W0212 self.assertEqual(1, len(tree)) @patch('doorstop.core.vcs.find_root', Mock(return_value=EMPTY)) def test_palce_empty_no_parent(self): """Verify a document with parent cannot be placed in an empty tree.""" tree = build(EMPTY) doc = MockDocumentSkip.new(tree, os.path.join(EMPTY, 'temp'), EMPTY, 'TEMP', parent='REQ') self.assertRaises(DoorstopError, tree._place, doc) # pylint: disable=W0212 def test_documents(self): """Verify the documents in a tree can be accessed.""" documents = self.tree.documents self.assertEqual(2, len(documents)) for document in self.tree: logging.debug("document: {}".format(document)) self.assertIs(self.tree, document.tree) @patch('doorstop.core.document.Document.get_issues') def test_validate(self, mock_get_issues): """Verify trees can be checked.""" logging.info("tree: {}".format(self.tree)) self.assertTrue(self.tree.validate()) self.assertEqual(2, mock_get_issues.call_count) def test_validate_no_documents(self): """Verify an empty tree can be checked.""" tree = Tree(None, root='.') self.assertTrue(tree.validate()) @patch('doorstop.settings.REORDER', False) @patch('doorstop.core.document.Document.get_issues', Mock(return_value=[ DoorstopError('error'), DoorstopWarning('warning'), DoorstopInfo('info') ])) def test_validate_document(self): """Verify a document error fails the tree validation.""" self.assertFalse(self.tree.validate()) @patch('doorstop.core.document.Document.get_issues', Mock(return_value=[])) def test_validate_hook(self): """Verify a document hook can be called.""" mock_hook = MagicMock() self.tree.validate(document_hook=mock_hook) self.assertEqual(2, mock_hook.call_count) @patch('doorstop.core.tree.Tree.get_issues', Mock(return_value=[])) def test_issues(self): """Verify an tree's issues convenience property can be accessed.""" self.assertEqual(0, len(self.tree.issues)) def test_get_traceability(self): """Verify traceability rows are correct.""" rows = [ (self.tree.find_item('SYS001'), self.tree.find_item('REQ001')), (self.tree.find_item('SYS002'), self.tree.find_item('REQ001')), (None, self.tree.find_item('REQ002')), (None, self.tree.find_item('REQ004')), ] # Act rows2 = self.tree.get_traceability() # Assert self.maxDiff = None self.assertListEqual(rows, rows2) def test_new_document(self): """Verify a new document can be created on a tree.""" self.tree.create_document(EMPTY, '_TEST', parent='REQ') def test_new_document_unknown_parent(self): """Verify an exception is raised for an unknown parent.""" temp = tempfile.mkdtemp() self.assertRaises(DoorstopError, self.tree.create_document, temp, '_TEST', parent='UNKNOWN') self.assertFalse(os.path.exists(temp)) @patch('doorstop.core.document.Document.add_item') def test_add_item(self, mock_add_item): """Verify an item can be added to a document.""" self.tree.add_item('REQ') mock_add_item.assert_called_once_with(number=None, level=None, reorder=True) @patch('doorstop.core.document.Document.add_item') def test_add_item_level(self, mock_add): """Verify an item can be added to a document with a level.""" self.tree.add_item('REQ', level='1.2.3') mock_add.assert_called_once_with(number=None, level='1.2.3', reorder=True) def test_add_item_unknown_prefix(self): """Verify an exception is raised for an unknown prefix (item).""" # Cache miss self.assertRaises(DoorstopError, self.tree.add_item, 'UNKNOWN') # Cache hit self.assertRaises(DoorstopError, self.tree.add_item, 'UNKNOWN') @patch('doorstop.settings.REORDER', False) @patch('doorstop.core.item.Item.delete') def test_remove_item(self, mock_delete): """Verify an item can be removed from a document.""" self.tree.remove_item('req1', reorder=False) mock_delete.assert_called_once_with() def test_remove_item_unknown_item(self): """Verify an exception is raised removing an unknown item.""" self.assertRaises(DoorstopError, self.tree.remove_item, 'req9999') @patch('doorstop.core.item.Item.link') def test_link_items(self, mock_link): """Verify two items can be linked.""" self.tree.link_items('req1', 'req2') mock_link.assert_called_once_with('REQ002') def test_link_items_unknown_child_prefix(self): """Verify an exception is raised with an unknown child prefix.""" self.assertRaises(DoorstopError, self.tree.link_items, 'unknown1', 'req2') def test_link_items_unknown_child_number(self): """Verify an exception is raised with an unknown child number.""" self.assertRaises(DoorstopError, self.tree.link_items, 'req9999', 'req2') def test_link_items_unknown_parent_prefix(self): """Verify an exception is raised with an unknown parent prefix.""" self.assertRaises(DoorstopError, self.tree.link_items, 'req1', 'unknown1') def test_link_items_unknown_parent_number(self): """Verify an exception is raised with an unknown parent prefix.""" self.assertRaises(DoorstopError, self.tree.link_items, 'req1', 'req9999') @patch('doorstop.core.item.Item.unlink') def test_unlink_items(self, mock_unlink): """Verify two items can be unlinked.""" self.tree.unlink_items('req3', 'req1') mock_unlink.assert_called_once_with('REQ001') def test_unlink_items_unknown_child_prefix(self): """Verify an exception is raised with an unknown child prefix.""" self.assertRaises(DoorstopError, self.tree.unlink_items, 'unknown1', 'req1') def test_unlink_items_unknown_child_number(self): """Verify an exception is raised with an unknown child number.""" self.assertRaises(DoorstopError, self.tree.unlink_items, 'req9999', 'req1') def test_unlink_items_unknown_parent_prefix(self): """Verify an exception is raised with an unknown parent prefix.""" # Cache miss self.assertRaises(DoorstopError, self.tree.unlink_items, 'req3', 'unknown1') # Cache hit self.assertRaises(DoorstopError, self.tree.unlink_items, 'req3', 'unknown1') def test_unlink_items_unknown_parent_number(self): """Verify an exception is raised with an unknown parent prefix.""" self.assertRaises(DoorstopError, self.tree.unlink_items, 'req3', 'req9999') @patch('doorstop.core.editor.launch') def test_edit_item(self, mock_launch): """Verify an item can be edited in a tree.""" self.tree.edit_item('req2', launch=True) path = os.path.join(FILES, 'REQ002.yml') mock_launch.assert_called_once_with(path, tool=None) def test_edit_item_unknown_prefix(self): """Verify an exception is raised for an unknown prefix (document).""" self.assertRaises(DoorstopError, self.tree.edit_item, 'unknown1') def test_edit_item_unknown_number(self): """Verify an exception is raised for an unknown number.""" self.assertRaises(DoorstopError, self.tree.edit_item, 'req9999') def test_find_item(self): """Verify an item can be found by exact UID.""" # Cache miss item = self.tree.find_item('req2-001') self.assertIsNot(None, item) # Cache hit item2 = self.tree.find_item('req2-001') self.assertIs(item2, item) def test_find_document(self): """Verify an document can be found by prefix""" # Cache miss document = self.tree.find_document('req') self.assertIsNot(None, document) # Cache hit document2 = self.tree.find_document('req') self.assertIs(document2, document) def test_load(self): """Verify an a tree can be reloaded.""" self.tree.load() self.tree.load() # should return immediately @patch('doorstop.core.document.Document.delete') def test_delete(self, mock_delete): """Verify a tree can be deleted.""" self.tree.delete() self.assertEqual(0, len(self.tree)) self.assertEqual(2, mock_delete.call_count) self.tree.delete() # ensure a second delete is ignored
class TestTree(unittest.TestCase): """Unit tests for the Tree class.""" def setUp(self): document = Document(SYS) self.tree = Tree(document) document.tree = self.tree document = Document(FILES) self.tree._place(document) # pylint: disable=W0212 document.tree = self.tree self.tree._vcs = Mock() # pylint: disable=W0212 @patch('doorstop.core.vcs.find_root', Mock(return_value=EMPTY)) def test_palce_empty(self): """Verify a document can be placed in an empty tree.""" tree = build(EMPTY) doc = MockDocumentSkip.new(tree, os.path.join(EMPTY, 'temp'), EMPTY, 'TEMP') tree._place(doc) # pylint: disable=W0212 self.assertEqual(1, len(tree)) @patch('doorstop.core.vcs.find_root', Mock(return_value=EMPTY)) def test_palce_empty_no_parent(self): """Verify a document with parent cannot be placed in an empty tree.""" tree = build(EMPTY) doc = MockDocumentSkip.new(tree, os.path.join(EMPTY, 'temp'), EMPTY, 'TEMP', parent='REQ') self.assertRaises(DoorstopError, tree._place, doc) # pylint: disable=W0212 def test_documents(self): """Verify the documents in a tree can be accessed.""" documents = self.tree.documents self.assertEqual(2, len(documents)) for document in self.tree: logging.debug("document: {}".format(document)) self.assertIs(self.tree, document.tree) @patch('doorstop.core.document.Document.get_issues') def test_validate(self, mock_get_issues): """Verify trees can be checked.""" logging.info("tree: {}".format(self.tree)) self.assertTrue(self.tree.validate()) self.assertEqual(2, mock_get_issues.call_count) def test_validate_no_documents(self): """Verify an empty tree can be checked.""" tree = Tree(None, root='.') self.assertTrue(tree.validate()) @patch('doorstop.settings.REORDER', False) @patch('doorstop.core.document.Document.get_issues', Mock(return_value=[DoorstopError('error'), DoorstopWarning('warning'), DoorstopInfo('info')])) def test_validate_document(self): """Verify a document error fails the tree validation.""" self.assertFalse(self.tree.validate()) @patch('doorstop.core.document.Document.get_issues', Mock(return_value=[])) def test_validate_hook(self): """Verify a document hook can be called.""" mock_hook = MagicMock() self.tree.validate(document_hook=mock_hook) self.assertEqual(2, mock_hook.call_count) @patch('doorstop.core.tree.Tree.get_issues', Mock(return_value=[])) def test_issues(self): """Verify an tree's issues convenience property can be accessed.""" self.assertEqual(0, len(self.tree.issues)) def test_get_traceability(self): """Verify traceability rows are correct.""" rows = [ (self.tree.find_item('SYS001'), self.tree.find_item('REQ001')), (self.tree.find_item('SYS002'), self.tree.find_item('REQ001')), (None, self.tree.find_item('REQ002')), (None, self.tree.find_item('REQ004')), ] # Act rows2 = self.tree.get_traceability() # Assert self.maxDiff = None self.assertListEqual(rows, rows2) def test_new_document(self): """Verify a new document can be created on a tree.""" self.tree.create_document(EMPTY, '_TEST', parent='REQ') def test_new_document_unknown_parent(self): """Verify an exception is raised for an unknown parent.""" temp = tempfile.mkdtemp() self.assertRaises(DoorstopError, self.tree.create_document, temp, '_TEST', parent='UNKNOWN') self.assertFalse(os.path.exists(temp)) @patch('doorstop.core.document.Document.add_item') def test_add_item(self, mock_add_item): """Verify an item can be added to a document.""" self.tree.add_item('REQ') mock_add_item.assert_called_once_with(number=None, level=None, reorder=True) @patch('doorstop.core.document.Document.add_item') def test_add_item_level(self, mock_add): """Verify an item can be added to a document with a level.""" self.tree.add_item('REQ', level='1.2.3') mock_add.assert_called_once_with(number=None, level='1.2.3', reorder=True) def test_add_item_unknown_prefix(self): """Verify an exception is raised for an unknown prefix (item).""" # Cache miss self.assertRaises(DoorstopError, self.tree.add_item, 'UNKNOWN') # Cache hit self.assertRaises(DoorstopError, self.tree.add_item, 'UNKNOWN') @patch('doorstop.settings.REORDER', False) @patch('doorstop.core.item.Item.delete') def test_remove_item(self, mock_delete): """Verify an item can be removed from a document.""" self.tree.remove_item('req1', reorder=False) mock_delete.assert_called_once_with() def test_remove_item_unknown_item(self): """Verify an exception is raised removing an unknown item.""" self.assertRaises(DoorstopError, self.tree.remove_item, 'req9999') @patch('doorstop.core.item.Item.link') def test_link_items(self, mock_link): """Verify two items can be linked.""" self.tree.link_items('req1', 'req2') mock_link.assert_called_once_with('REQ002') def test_link_items_unknown_child_prefix(self): """Verify an exception is raised with an unknown child prefix.""" self.assertRaises(DoorstopError, self.tree.link_items, 'unknown1', 'req2') def test_link_items_unknown_child_number(self): """Verify an exception is raised with an unknown child number.""" self.assertRaises(DoorstopError, self.tree.link_items, 'req9999', 'req2') def test_link_items_unknown_parent_prefix(self): """Verify an exception is raised with an unknown parent prefix.""" self.assertRaises(DoorstopError, self.tree.link_items, 'req1', 'unknown1') def test_link_items_unknown_parent_number(self): """Verify an exception is raised with an unknown parent prefix.""" self.assertRaises(DoorstopError, self.tree.link_items, 'req1', 'req9999') @patch('doorstop.core.item.Item.unlink') def test_unlink_items(self, mock_unlink): """Verify two items can be unlinked.""" self.tree.unlink_items('req3', 'req1') mock_unlink.assert_called_once_with('REQ001') def test_unlink_items_unknown_child_prefix(self): """Verify an exception is raised with an unknown child prefix.""" self.assertRaises(DoorstopError, self.tree.unlink_items, 'unknown1', 'req1') def test_unlink_items_unknown_child_number(self): """Verify an exception is raised with an unknown child number.""" self.assertRaises(DoorstopError, self.tree.unlink_items, 'req9999', 'req1') def test_unlink_items_unknown_parent_prefix(self): """Verify an exception is raised with an unknown parent prefix.""" # Cache miss self.assertRaises(DoorstopError, self.tree.unlink_items, 'req3', 'unknown1') # Cache hit self.assertRaises(DoorstopError, self.tree.unlink_items, 'req3', 'unknown1') def test_unlink_items_unknown_parent_number(self): """Verify an exception is raised with an unknown parent prefix.""" self.assertRaises(DoorstopError, self.tree.unlink_items, 'req3', 'req9999') @patch('doorstop.core.editor.launch') def test_edit_item(self, mock_launch): """Verify an item can be edited in a tree.""" self.tree.edit_item('req2', launch=True) path = os.path.join(FILES, 'REQ002.yml') mock_launch.assert_called_once_with(path, tool=None) def test_edit_item_unknown_prefix(self): """Verify an exception is raised for an unknown prefix (document).""" self.assertRaises(DoorstopError, self.tree.edit_item, 'unknown1') def test_edit_item_unknown_number(self): """Verify an exception is raised for an unknown number.""" self.assertRaises(DoorstopError, self.tree.edit_item, 'req9999') def test_find_item(self): """Verify an item can be found by exact UID.""" # Cache miss item = self.tree.find_item('req2-001') self.assertIsNot(None, item) # Cache hit item2 = self.tree.find_item('req2-001') self.assertIs(item2, item) def test_find_document(self): """Verify an document can be found by prefix""" # Cache miss document = self.tree.find_document('req') self.assertIsNot(None, document) # Cache hit document2 = self.tree.find_document('req') self.assertIs(document2, document) def test_load(self): """Verify an a tree can be reloaded.""" self.tree.load() self.tree.load() # should return immediately @patch('doorstop.core.document.Document.delete') def test_delete(self, mock_delete): """Verify a tree can be deleted.""" self.tree.delete() self.assertEqual(0, len(self.tree)) self.assertEqual(2, mock_delete.call_count) self.tree.delete() # ensure a second delete is ignored