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 test_from_list(self):
     """Verify a tree can be created from a list."""
     a = MockDocument(EMPTY)
     a.prefix = 'A'
     b = MockDocument(EMPTY)
     b.prefix = 'B'
     b.parent = 'A'
     c = MockDocument(EMPTY)
     c.prefix = 'C'
     c.parent = 'B'
     docs = [a, b, c]
     tree = Tree.from_list(docs)
     self.assertEqual(3, len(tree))
     self.assertTrue(tree.valid())
 def setUp(self):
     self.tree = Tree(Document(SYS))
     self.tree._place(Document(FILES))  # pylint: disable=W0212
 def test_valid_no_documents(self):
     """Verify an empty tree can be checked."""
     tree = Tree(None, root='.')
     self.assertTrue(tree.valid())
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('demo.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('demo.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(DemoError, tree._place, doc)  # pylint: disable=W0212

    @patch('demo.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=[DemoError('e'),
                                         DemoWarning('w'),
                                         DemoInfo('i')])
        with patch.object(self.tree, 'issues', mock_issues):
            self.assertFalse(self.tree.valid())

    @patch('demo.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(DemoError, self.tree.new,
                          temp, '_TEST', parent='UNKNOWN')
        self.assertFalse(os.path.exists(temp))

    @patch('demo.core.vcs.git.WorkingCopy.lock')
    @patch('demo.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(DemoError, self.tree.add, 'UNKNOWN')
        # Cache hit
        self.assertRaises(DemoError, self.tree.add, 'UNKNOWN')

    @patch('demo.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(DemoError, self.tree.remove, 'req9999')

    @patch('demo.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(DemoError, self.tree.link, 'unknown1', 'req2')

    def test_link_unknown_child_number(self):
        """Verify an exception is raised with an unknown child number."""
        self.assertRaises(DemoError, self.tree.link, 'req9999', 'req2')

    def test_link_unknown_parent_prefix(self):
        """Verify an exception is raised with an unknown parent prefix."""
        self.assertRaises(DemoError, self.tree.link, 'req1', 'unknown1')

    def test_link_unknown_parent_number(self):
        """Verify an exception is raised with an unknown parent prefix."""
        self.assertRaises(DemoError, self.tree.link, 'req1', 'req9999')

    @patch('demo.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(DemoError, self.tree.unlink, 'unknown1', 'req1')

    def test_unlink_unknown_child_number(self):
        """Verify an exception is raised with an unknown child number."""
        self.assertRaises(DemoError, 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(DemoError, self.tree.unlink, 'req3', 'unknown1')
        # Cache hit
        self.assertRaises(DemoError, self.tree.unlink, 'req3', 'unknown1')

    def test_unlink_unknown_parent_number(self):
        """Verify an exception is raised with an unknown parent prefix."""
        self.assertRaises(DemoError, self.tree.unlink, 'req3', 'req9999')

    @patch('demo.core.vcs.git.WorkingCopy.lock')
    @patch('demo.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(DemoError, self.tree.edit, 'unknown1')

    def test_edit_unknown_number(self):
        """Verify an exception is raised for an unknown number."""
        self.assertRaises(DemoError, 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