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
def setUpClass(cls): a = Tree('a', root='.') b1 = Tree('b1', parent=a, root='.') b2 = Tree('b2', parent=a, root='.') c1 = Tree('c1', parent=b2, root='.') c2 = Tree('c2', parent=b2, root='.') a.children = [b1, b2] b2.children = [c1, c2] cls.tree = a
def build(cwd=None, root=None): """Build a tree from the current working directory or explicit root. :param cwd: current working directory :param root: path to root of the working copy :raises: :class:`~doorstop.common.DoorstopError` when the tree cannot be built :return: new :class:`~doorstop.core.tree.Tree` """ documents = [] # Find the root of the working copy cwd = cwd or os.getcwd() root = root or vcs.find_root(cwd) # Find all documents in the working copy log.info("looking for documents in {}...".format(root)) _document_from_path(root, root, documents) for dirpath, dirnames, _filenames in os.walk(root): for dirname in dirnames: path = os.path.join(dirpath, dirname) _document_from_path(path, root, documents) # Build the tree if not documents: log.info("no documents found in: {}".format(root)) log.info("building tree...") tree = Tree.from_list(documents, root=root) log.info("built tree: {}".format(tree)) return tree
def setUp(self): # Create default item attributes self.uid = 'PREFIX-00042' # Ensure the tree is reloaded mock_document = Mock() mock_document.root = self.root mock_document.prefix = self.prefix self.mock_tree = Tree(mock_document) _set_tree(self.mock_tree)
def test_create_document_explicit_tree(self, mock_new, mock_get_tree): """Verify a new document can be created for import (explicit tree).""" mock_document = Mock() mock_document.root = None tree = Tree(document=mock_document) importer.create_document(self.prefix, self.path, tree=tree) self.assertFalse(mock_get_tree.called) mock_new.assert_called_once_with(self.path, self.prefix, parent=None) self.assertIn(mock_document, tree)
def test_place_no_parent(self): """Verify an error occurs when a node is missing a parent.""" a = MockDocumentSkip(EMPTY) a.prefix = 'A' b = MockDocumentSkip(EMPTY) b.prefix = 'B' tree = Tree(a) self.assertRaises(DoorstopError, tree._place, b) # pylint: disable=W0212
def setUp(self): # Create default document options self.prefix = 'PREFIX' self.root = 'ROOT' self.path = os.path.join(self.root, 'DIRECTORY') self.parent = 'PARENT_PREFIX' # Ensure the tree is reloaded mock_document = Mock() mock_document.root = self.root self.mock_tree = Tree(mock_document) _set_tree(self.mock_tree)
def setUpClass(cls): a = Tree('a', root='.') b1 = Tree('b1', parent=a, root='.') d = Tree('d', parent=b1, root='.') e = Tree('e', parent=d, root='.') b2 = Tree('b2', parent=a, root='.') c1 = Tree('c1', parent=b2, root='.') c2 = Tree('c2', parent=b2, root='.') a.children = [b1, b2] b1.children = [d] d.children = [e] b2.children = [c1, c2] cls.tree = a
class TestModule(unittest.TestCase): """Unit tests for the doorstop.core.builder module.""" @patch('doorstop.core.vcs.find_root', Mock(return_value=EMPTY)) def test_run_empty(self): """Verify an empty directory is an empty hierarchy.""" tree = build(EMPTY) self.assertEqual(0, len(tree)) @patch('doorstop.core.document.Document', MockDocumentNoSkip) @patch('doorstop.core.vcs.find_root', Mock(return_value=FILES)) def test_build(self): """Verify a tree can be built.""" tree = build(FILES) self.assertEqual(4, len(tree)) @patch('doorstop.core.document.Document', MockDocumentSkip) @patch('doorstop.core.vcs.find_root', Mock(return_value=FILES)) def test_build_with_skips(self): """Verify documents can be skipped while building a tree.""" tree = build(FILES) self.assertEqual(0, len(tree)) @patch('doorstop.core.builder.build', Mock(return_value=Tree(Mock()))) @patch('doorstop.core.tree.Tree.find_document') def test_find_document(self, mock_find_document): # pylint: disable=R0201 """Verify documents can be found using a convenience function.""" _clear_tree() prefix = 'req' find_document(prefix) mock_find_document.assert_called_once_with(prefix) @patch('doorstop.core.builder.build', Mock(return_value=Tree(Mock()))) @patch('doorstop.core.tree.Tree.find_item') def test_find_item(self, mock_find_item): # pylint: disable=R0201 """Verify items can be found using a convenience function.""" _clear_tree() uid = 'req1' find_item(uid) mock_find_item.assert_called_once_with(uid)
def test_from_list(self): """Verify a tree can be created from a list.""" a = MockDocumentSkip(EMPTY) a.prefix = 'A' b = MockDocumentSkip(EMPTY) b.prefix = 'B' b.parent = 'A' c = MockDocumentSkip(EMPTY) c.prefix = 'C' c.parent = 'B' docs = [a, b, c] tree = Tree.from_list(docs) self.assertEqual(3, len(tree)) self.assertTrue(tree.validate())
def build(cwd=None, root=None, request_next_number=None) -> Tree: """Build a tree from the current working directory or explicit root. :param cwd: current working directory :param root: path to root of the working copy :param request_next_number: server method to get a document's next number :raises: :class:`~doorstop.common.DoorstopError` when the tree cannot be built :return: new :class:`~doorstop.core.tree.Tree` """ documents: List[Document] = [] # Find the root of the working copy cwd = cwd or os.getcwd() root = root or vcs.find_root(cwd) # Find all documents in the working copy log.info("looking for documents in {}...".format(root)) skip_file_name = '.doorstop.skip-all' if not os.path.isfile(os.path.join(root, skip_file_name)): _document_from_path(root, root, documents) exclude_dirnames = {'.git'} if not os.path.isfile(os.path.join(root, skip_file_name)): for dirpath, dirnames, _ in os.walk(root, topdown=True): whilelist_dirnames = [] for dirname in dirnames: if dirname in exclude_dirnames: continue path = os.path.join(dirpath, dirname) if os.path.isfile(os.path.join(path, skip_file_name)): continue whilelist_dirnames.append(dirname) _document_from_path(path, root, documents) dirnames[:] = whilelist_dirnames # Build the tree if not documents: log.info("no documents found in: {}".format(root)) log.info("building tree...") tree = Tree.from_list(documents, root=root) tree.request_next_number = request_next_number if len(tree): # pylint: disable=len-as-condition log.info("built tree: {}".format(tree)) else: log.info("tree is empty") return tree
def build(cwd=None, root=None, request_next_number=None): """Build a tree from the current working directory or explicit root. :param cwd: current working directory :param root: path to root of the working copy :param request_next_number: server method to get a document's next number :raises: :class:`~doorstop.common.DoorstopError` when the tree cannot be built :return: new :class:`~doorstop.core.tree.Tree` """ documents = [] # Find the root of the working copy cwd = cwd or os.getcwd() root = root or vcs.find_root(cwd) # Find all documents in the working copy log.info("looking for documents in {}...".format(root)) _document_from_path(root, root, documents) for dirpath, dirnames, _ in os.walk(root): for dirname in dirnames: path = os.path.join(dirpath, dirname) _document_from_path(path, root, documents) # Build the tree if not documents: log.info("no documents found in: {}".format(root)) log.info("building tree...") tree = Tree.from_list(documents, root=root) tree.request_next_number = request_next_number if len(tree): # pylint: disable=len-as-condition log.info("built tree: {}".format(tree)) else: log.info("tree is empty") return tree
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 TestModule(unittest.TestCase): """Unit tests for the doorstop.core.builder module.""" @patch('doorstop.core.vcs.find_root', Mock(return_value=EMPTY)) def test_run_empty(self): """Verify an empty directory is an empty hierarchy.""" tree = build(EMPTY) self.assertEqual(0, len(tree)) @patch('doorstop.core.document.Document', MockDocumentNoSkip) @patch('doorstop.core.vcs.find_root', Mock(return_value=FILES)) def test_build(self): """Verify a tree can be built.""" tree = build(FILES) self.assertEqual(4, len(tree)) @patch('doorstop.core.document.Document', MockDocumentSkip) @patch('doorstop.core.vcs.find_root', Mock(return_value=FILES)) def test_build_with_skips(self): """Verify documents can be skipped while building a tree.""" tree = build(FILES) self.assertEqual(0, len(tree)) @patch('doorstop.core.builder.build', Mock(return_value=Tree(Mock()))) @patch('doorstop.core.tree.Tree.find_document') def test_find_document(self, mock_find_document): # pylint: disable=R0201 """Verify documents can be found using a convenience function.""" _clear_tree() prefix = 'req' find_document(prefix) mock_find_document.assert_called_once_with(prefix) @patch('doorstop.core.builder.build', Mock(return_value=Tree(Mock()))) @patch('doorstop.core.tree.Tree.find_item') def test_find_item(self, mock_find_item): # pylint: disable=R0201 """Verify items can be found using a convenience function.""" _clear_tree() uid = 'req1' find_item(uid) mock_find_item.assert_called_once_with(uid) def test_tree_finds_documents(self): """Verify items can be found using a convenience function.""" temp = tempfile.mkdtemp() cwd = temp root = temp # Step 1: Create a new tree with one item. tree = build(cwd, root) document = tree.create_document(cwd, 'TST') item = Item.new(tree, document, cwd, cwd, "TST-001") item.save() # Step 2: Find a newly created tree same_tree_again = build(cwd, root) # Verify that that the tree, document and its item can be found. self.assertEqual(1, len(same_tree_again.documents)) document = same_tree_again.document self.assertIsNotNone(document) self.assertEqual(1, len(document.items)) item = document.items[0] self.assertEqual('TST-001', item.uid) def test_tree_does_not_find_documents_when_skipall_file_present(self): """Verify items can be found using a convenience function.""" temp = tempfile.mkdtemp() cwd = temp root = temp # Step 1: Create a new tree with one item. tree = build(cwd, root) document = tree.create_document(cwd, 'TST') item = Item.new(tree, document, cwd, cwd, "TST-001") item.save() # Step 2: Put a .doorstop.skip-all to the root of the tree. path = os.path.join(temp, '.doorstop.skip-all') open(path, 'a').close() # Step 3: Find a newly created tree same_tree_again = build(cwd, root) # Verify that the tree does not have a document because it was ignored. document = same_tree_again.document self.assertIsNone(document) def test_tree_finds_subdocuments(self): """Verify items can be found using a convenience function.""" temp = tempfile.mkdtemp() cwd = temp root = temp # Step 1: Create a new tree with one item in a document in a subfolder. tree = build(cwd, root) document = tree.create_document(cwd, 'TST') subfolder = os.path.join(temp, 'SUBFOLDER') os.makedirs(os.path.join(temp, subfolder)) sub_document = tree.create_document(subfolder, 'TST_SUB', parent='TST') item = Item.new(tree, sub_document, subfolder, cwd, "TST_SUB-001") item.save() # Step 2: Read existing tree same_tree_again = build(cwd, root) # Verify that the tree has: # - both root-level and subfolder documents # - item in a subdocument self.assertEqual(2, len(same_tree_again.documents)) sub_document = same_tree_again.documents[1] self.assertIsNotNone(document) self.assertEqual(1, len(sub_document.items)) item = sub_document.items[0] self.assertEqual('TST_SUB-001', item.uid) def test_tree_skips_subdocuments_when_skipall_file_present(self): """Verify items can be found using a convenience function.""" temp = tempfile.mkdtemp() cwd = temp root = temp # Step 1: Create a new tree with one item in a document in a subfolder. tree = build(cwd, root) tree.create_document(cwd, 'TST') subfolder = os.path.join(temp, 'SUBFOLDER') os.makedirs(os.path.join(temp, subfolder)) sub_document = tree.create_document(subfolder, 'TST_SUB', parent='TST') item = Item.new(tree, sub_document, subfolder, cwd, "TST_SUB-001") item.save() # Step 2: Put a .doorstop.skip-all into the subfolder. path = os.path.join(subfolder, '.doorstop.skip-all') open(path, 'a').close() # Verify that building tree ignores subfolder's document. same_tree_again = build(cwd, root) self.assertEqual(1, len(same_tree_again.documents))
def test_validate_no_documents(self): """Verify an empty tree can be checked.""" tree = Tree(None, root='.') self.assertTrue(tree.validate())
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
def setUp(self): self.tree = Tree(Document(SYS)) self.tree._place(Document(FILES)) # pylint: disable=W0212
class TestTree(unittest.TestCase): # pylint: disable=R0904 """Unit tests for the Tree class.""" # pylint: disable=C0103 def setUp(self): self.tree = Tree(Document(SYS)) self.tree._place(Document(FILES)) # 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 = MockDocument.new(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 = MockDocument.new(os.path.join(EMPTY, 'temp'), EMPTY, 'TEMP', parent='REQ') self.assertRaises(DoorstopError, tree._place, doc) # pylint: disable=W0212 @patch('doorstop.core.document.Document.issues') def test_valid(self, mock_issues): """Verify trees can be checked.""" logging.info("tree: {}".format(self.tree)) self.assertTrue(self.tree.valid()) self.assertEqual(2, mock_issues.call_count) @unittest.skipUnless(os.getenv(ENV), REASON) def test_valid_long(self): """Verify trees can be checked (long).""" logging.info("tree: {}".format(self.tree)) self.assertTrue(self.tree.valid()) def test_valid_no_documents(self): """Verify an empty tree can be checked.""" tree = Tree(None, root='.') self.assertTrue(tree.valid()) def test_valid_document(self): """Verify an document error fails the tree valid.""" mock_issues = Mock(return_value=[DoorstopError('e'), DoorstopWarning('w'), DoorstopInfo('i')]) with patch.object(self.tree, 'issues', mock_issues): self.assertFalse(self.tree.valid()) @patch('doorstop.core.document.Document.issues', Mock(return_value=[])) def test_valid_hook(self): """Verify a document hook can be called.""" mock_hook = MagicMock() self.tree.valid(document_hook=mock_hook) self.assertEqual(2, mock_hook.call_count) def test_new(self): """Verify a new document can be created on a tree.""" self.tree.new(EMPTY, '_TEST', parent='REQ') def test_new_unknown_parent(self): """Verify an exception is raised for an unknown parent.""" temp = tempfile.mkdtemp() self.assertRaises(DoorstopError, self.tree.new, temp, '_TEST', parent='UNKNOWN') self.assertFalse(os.path.exists(temp)) @patch('doorstop.core.vcs.git.WorkingCopy.lock') @patch('doorstop.core.document.Document.add') def test_add(self, mock_add, mock_lock): """Verify an item can be added to a document.""" self.tree.add('REQ') mock_add.assert_called_once_with() path = os.path.join(FILES, '.doorstop.yml') mock_lock.assert_called_once_with(path) def test_add_unknown_prefix(self): """Verify an exception is raised for an unknown prefix (item).""" # Cache miss self.assertRaises(DoorstopError, self.tree.add, 'UNKNOWN') # Cache hit self.assertRaises(DoorstopError, self.tree.add, 'UNKNOWN') @patch('doorstop.core.item.Item.delete') def test_remove(self, mock_delete): """Verify an item can be removed from a document.""" self.tree.remove('req1') mock_delete.assert_called_once_with() def test_remove_unknown_item(self): """Verify an exception is raised removing an unknown item.""" self.assertRaises(DoorstopError, self.tree.remove, 'req9999') @patch('doorstop.core.item.Item.add_link') def test_link(self, mock_add_link): """Verify two items can be linked.""" self.tree.link('req1', 'req2') mock_add_link.assert_called_once_with('REQ002') def test_link_unknown_child_prefix(self): """Verify an exception is raised with an unknown child prefix.""" self.assertRaises(DoorstopError, self.tree.link, 'unknown1', 'req2') def test_link_unknown_child_number(self): """Verify an exception is raised with an unknown child number.""" self.assertRaises(DoorstopError, self.tree.link, 'req9999', 'req2') def test_link_unknown_parent_prefix(self): """Verify an exception is raised with an unknown parent prefix.""" self.assertRaises(DoorstopError, self.tree.link, 'req1', 'unknown1') def test_link_unknown_parent_number(self): """Verify an exception is raised with an unknown parent prefix.""" self.assertRaises(DoorstopError, self.tree.link, 'req1', 'req9999') @patch('doorstop.core.item.Item.remove_link') def test_unlink(self, mock_add_link): """Verify two items can be unlinked.""" self.tree.unlink('req3', 'req1') mock_add_link.assert_called_once_with('REQ001') def test_unlink_unknown_child_prefix(self): """Verify an exception is raised with an unknown child prefix.""" self.assertRaises(DoorstopError, self.tree.unlink, 'unknown1', 'req1') def test_unlink_unknown_child_number(self): """Verify an exception is raised with an unknown child number.""" self.assertRaises(DoorstopError, self.tree.unlink, 'req9999', 'req1') def test_unlink_unknown_parent_prefix(self): """Verify an exception is raised with an unknown parent prefix.""" # Cache miss self.assertRaises(DoorstopError, self.tree.unlink, 'req3', 'unknown1') # Cache hit self.assertRaises(DoorstopError, self.tree.unlink, 'req3', 'unknown1') def test_unlink_unknown_parent_number(self): """Verify an exception is raised with an unknown parent prefix.""" self.assertRaises(DoorstopError, self.tree.unlink, 'req3', 'req9999') @patch('doorstop.core.vcs.git.WorkingCopy.lock') @patch('doorstop.core.tree._open') def test_edit(self, mock_open, mock_lock): """Verify an item can be edited in a tree.""" self.tree.edit('req2', launch=True) path = os.path.join(FILES, 'REQ002.yml') mock_open.assert_called_once_with(path, tool=None) mock_lock.assert_called_once_with(path) def test_edit_unknown_prefix(self): """Verify an exception is raised for an unknown prefix (document).""" self.assertRaises(DoorstopError, self.tree.edit, 'unknown1') def test_edit_unknown_number(self): """Verify an exception is raised for an unknown number.""" self.assertRaises(DoorstopError, self.tree.edit, 'req9999') def test_find_item(self): """Verify an item can be found by exact ID.""" # 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