def test_fuzz(self):
        """Perform some basic randomized input testing."""
        repeat_times = 5
        sample_set = range(-1000, 1001)

        bst = BinarySearchTree()
        for i in range(repeat_times):
            # Insert elements
            for j in random.sample(sample_set, len(sample_set)):
                bst.insert(j)

            # Search for elements
            for j in random.sample(sample_set, len(sample_set)):
                self.assertEqual(j, bst.search(j))

            # Delete elements
            for j in random.sample(sample_set, len(sample_set)):
                self.assertTrue(bst.delete(j))
                self.assertIsNone(bst.search(j))
    def test_basic_checks(self):
        bst = BinarySearchTree()

        # Root node: 7
        bst.insert(7)
        self.assertEqual(7, bst.root.key, "Insert key as root")

        #   7
        #  /
        # 3
        bst.insert(3)
        self.assertEqual(3, bst.root.left.key, "Insert key as root's left child")

        #   7
        #  / \
        # 3   11
        bst.insert(11)
        self.assertEqual(11, bst.root.right.key, "Insert key as root's right child")

        #     7
        #    / \
        #   3   11
        #  /
        # 1
        bst.insert(1)
        self.assertEqual(1, bst.root.left.left.key, "Insert key as left child of non-root node")

        #     7
        #    / \
        #   3   11
        #  /     \
        # 1       13
        bst.insert(13)
        self.assertEqual(13, bst.root.right.right.key, "Insert key as right child of non-root node")

        #     7
        #    / \
        #   3   11
        #  /   / \
        # 1   9   13
        bst.insert(9)
        self.assertEqual(9, bst.root.right.left.key, "Insert key as left child of right child")

        #      7
        #    /   \
        #   3     11
        #  / \    / \
        # 1   5  9   13
        bst.insert(5)
        self.assertEqual(5, bst.root.left.right.key, "Insert key as right child of left child")

        for i in range(1, 14, 2):
            self.assertEqual(i, bst.search(i), "Search full tree for {}.".format(i))

        for i in range(0, 15, 2):
            self.assertIsNone(bst.search(i), "Search full tree for nonexistent items.")

        # By adding a few more elements, we can test all basic deletion cases with a bit of planning.
        # (Some corner cases may not be covered, e.g. testing whether a replacement works with both None and Node)
        #      7
        #    /   \
        #   3     11
        #  / \    / \
        # 1   5  9   13
        #       /   /
        #      8  12
        bst.insert(8)
        bst.insert(12)

        # Possible deletion cases:
        # A - delete root with successor as leftmost child of right subtree (IOS)
        # B - delete root with left and right children, right has no left subtree
        # C - delete root with only right child
        # D - delete root with only left child
        # E - delete root with no children, leaving an empty tree
        # F - delete non-root node with successor as leftmost child of right subtree (IOS)
        # G - delete non-root node with only right child
        # H - delete non-root node with only left child
        # I - delete non-root node with left and right children, right child is a leaf
        # J - delete non-root leaf

        # Deletions, in order, matched with cases above:
        # 7  - A
        # 3  - I
        # 11 - F
        # 9  - J
        # 5  - H
        # 12 - G
        # 8  - B
        # 13 - D
        # This leaves a tree with one node, 1.

        # Then we'll insert 2 to form the tree
        #    1
        #     \
        #      2
        # And we'll delete:
        # 1 - C
        # 2 - E

        for i in [7, 3, 11, 9, 5, 12, 8, 13]:
            self.assertTrue(bst.delete(i), "Test deletion cases")
            self.assertIsNone(bst.search(i), "Search for deleted item")

        bst.insert(2)
        for i in [1, 2]:
            self.assertTrue(bst.delete(i), "Test deletion cases")
            self.assertIsNone(bst.search(i), "Search for deleted item")

        self.assertFalse(bst.delete(6), "Delete item that's not in the tree")
        self.assertFalse(bst.delete(7), "Delete item previously removed from tree")
        self.assertIsNone(bst.search(1), "Search empty tree")