def test_setitem_adds_root(self): """Does __setitem__ correctly add the tree's root when called on an empty tree?""" empty_tree = TreeMap() test_key = 12 empty_tree[test_key] = "test value" self.assertEqual(test_key, empty_tree.root().key())
def setUp(self): self.tree = TreeMap() self.val = self.tree._Node("filler value") # filler value # NB these keys must be numbers (or else ._node objects?) self.root_key = 44 self.root_val = self.tree._Node("root value") self.root = self.tree._add_root( self.tree._Item(self.root_key, self.root_val)) # First layer: 44 with children 17 and 88 self.pos17 = self.tree._add_left( # Todo this shouldn't be necessary self.tree.root(), self.tree._Item( 17, self.val)) # setitem is supposed to know left vs right self.pos88 = self.tree._add_right(self.tree.root(), self.tree._Item(88, self.val)) # Children of 17: 8 and 32 self.pos8 = self.tree._add_left(self.pos17, self.tree._Item(8, self.val)) self.pos32 = self.tree._add_right(self.pos17, self.tree._Item(32, self.val)) # Children of 88: 65 and 97 self.val_65 = self.tree._Node("value at key 65") self.tree[65] = self.val_65 self.tree[97] = self.tree._Node("value at key 97")
def test_set_and_get(self): ht = TreeMap() ht.set('I', 1) ht.set('V', 5) ht.set('X', 10) assert ht.get('I') == 1 assert ht.get('V') == 5 assert ht.get('X') == 10 assert ht.size == 3 with self.assertRaises(KeyError): ht.get('A') # Key does not exist
def test_contains(self): ht = TreeMap() ht.set('I', 1) ht.set('V', 5) ht.set('X', 10) assert ht.contains('I') is True assert ht.contains('V') is True assert ht.contains('X') is True assert ht.contains('A') is False
def test_size(self): ht = TreeMap() assert ht.size == 0 ht.set('I', 1) assert ht.size == 1 ht.set('V', 5) assert ht.size == 2 ht.set('X', 10) assert ht.size == 3
def test_getitem_raises_key_error_for_empty(self): """ Does __getitem__ raise KeyError when called on an empty tree?""" empty_tree = TreeMap() with self.assertRaises(KeyError): item = empty_tree[12]
def test_simple_single_rotation(self): tree = TreeMap() z = tree._add_root(tree._Item(1, "z")) # z starts as root assert tree.root().key() == 1 y = tree._add_right(p=z, e=tree._Item(2, "y")) # y starts as right child of z x = tree._add_right(p=y, e=tree._Item(3, "x")) # x starts as right child of y, grandchild of z assert len(tree) == 3 tree._restructure(x) self.assertEqual("y", tree.root().value()) # y should be root self.assertEqual("z", tree.left(tree.root()).value()) # z should be left self.assertEqual("x", tree.right(tree.root()).value()) # x should be right # y should now have no parent self.assertIsNone(tree.parent(y)) # z and x should now be leaves with no children self.assertIsNone(tree.right(x)) self.assertIsNone(tree.left(x)) #print(f"\n\n***********{tree.right(z).value()}*************\n\n") self.assertIsNone(tree.right(z)) self.assertIsNone(tree.left(z))
def test_find_ge_empty(self): """Does the method return None when called on an empty tree?""" empty_tree = TreeMap() self.assertIsNone(empty_tree.find_ge(44))
class TestSimpleTreeMap(unittest.TestCase): """Quick basic-functionality tests using a simple instance of a TreeMap object. """ # The tree is the one from DSAP 463 figure 11.2(a). With root 44, "first" # (min value leftmost external node) 8, "last" 97. def setUp(self): self.tree = TreeMap() self.val = self.tree._Node("filler value") # filler value # NB these keys must be numbers (or else ._node objects?) self.root_key = 44 self.root_val = self.tree._Node("root value") self.root = self.tree._add_root( self.tree._Item(self.root_key, self.root_val)) # First layer: 44 with children 17 and 88 self.pos17 = self.tree._add_left( # Todo this shouldn't be necessary self.tree.root(), self.tree._Item( 17, self.val)) # setitem is supposed to know left vs right self.pos88 = self.tree._add_right(self.tree.root(), self.tree._Item(88, self.val)) # Children of 17: 8 and 32 self.pos8 = self.tree._add_left(self.pos17, self.tree._Item(8, self.val)) self.pos32 = self.tree._add_right(self.pos17, self.tree._Item(32, self.val)) # Children of 88: 65 and 97 self.val_65 = self.tree._Node("value at key 65") self.tree[65] = self.val_65 self.tree[97] = self.tree._Node("value at key 97") ### TreeMap.__getitem__ def test_getitem(self): """Does TM's __getitem__ method return the value associated with a key?""" expected = self.root_val self.assertEqual(expected, self.tree[self.root_key]) def test_getitem_for_external_setitem_call(self): """Does getitem return the expected value for an item that was added through dictionary-style syntax rather than by directly calling internal setter methods?""" expected = self.val_65 self.assertEqual(expected, self.tree[65]) def test_getitem_raises_key_error_for_empty(self): """ Does __getitem__ raise KeyError when called on an empty tree?""" empty_tree = TreeMap() with self.assertRaises(KeyError): item = empty_tree[12] def test_getitem_raises_key_error(self): """Does __getitem__ raise KeyError when called with a key that isn't in the tree?""" with self.assertRaises(KeyError): item = self.tree[9001] ### TreeMap.__setitem__ def test_setitem_adds_root(self): """Does __setitem__ correctly add the tree's root when called on an empty tree?""" empty_tree = TreeMap() test_key = 12 empty_tree[test_key] = "test value" self.assertEqual(test_key, empty_tree.root().key()) ### TreeMap._subtree_search def test_subtree_search_left_case(self): # subtree search for key k=8 on subtree from position with key=17 should # return Position of 8. expected = self.pos8 actual = self.tree._subtree_search(p=self.pos17, k=8) self.assertEqual(expected, actual) def test_subtree_search_right_case(self): expected = self.pos32 actual = self.tree._subtree_search(p=self.pos17, k=32) self.assertEqual(expected, actual) def test_subtree_search_no_match(self): """Does the method return the subtree's root position when the searched- for key isn't in the subtree?""" expected = self.pos32 actual = self.tree._subtree_search(p=self.pos17, k=9001) self.assertEqual(expected, actual) ### TreeMap._subtree_first_position def test_subtree_first_position_full_tree(self): """Does it correctly return 8, the minimum value in this test tree?""" expected = self.pos8 actual = self.tree._subtree_first_position(self.tree.root()) self.assertEqual(expected, actual) def test_subtree_first_position_not_tree_min(self): # Todo test will break if more layers added to build the full tree # from the diagram. """When called on a subtree that isn't root, and whose "last" key is greater than the full tree's last, does the method correctly return the subtree last?""" # Min for subtree at 88 is 65 expected = 65 actual = self.tree._subtree_first_position(self.pos88).key() # Call key() method to return the actual int rather than a position # object. self.assertEqual(expected, actual) ### TreeMap._subtree_last_position def test_subtree_last_position_full_tree(self): """When called on the full tree, does the method return the key with the max value in the tree?""" # max is 97 right now expected = 97 actual = self.tree._subtree_last_position(self.tree.root()).key() self.assertEqual(expected, actual) def test_subtree_first_position_not_tree_max(self): """When called on a subtree whose "last" isn't the same as the full tree's last, does the method correctly return the subtree's last?""" # max on the 17 subtree is 32 expected = 32 actual = self.tree._subtree_last_position(self.pos17).key() self.assertEqual(expected, actual) ### def test_first(self): """Does the method return the first position in the tree?""" expected = self.pos8 actual = self.tree.first() self.assertEqual(expected, actual) def test_last(self): """Does the method return the last position in the full tree?""" expected = 97 actual = self.tree.last().key() self.assertEqual(expected, actual) ### TreeMap.before def test_before_root(self): """Does the method correctly return the position just before root when called on root?""" expected = 32 actual = self.tree.before(self.tree.root()).key() self.assertEqual(expected, actual) def test_before_first(self): """Does the method return None when called with the first position?""" self.assertIsNone(self.tree.before(self.tree.first())) ### TreeMap.after def test_after_root(self): expected = 65 assert self.tree.root().key() == 44 actual = self.tree.after(self.tree.root()).key() self.assertEqual(expected, actual) def test_after_last(self): """Does the method return None when called with the last position?""" self.assertIsNone(self.tree.after(self.tree.last())) ### def test_find_position_root(self): """Does the method return root when called with root's key?""" self.assertEqual(self.tree.root(), self.tree.find_position(44)) def test_find_position_midlevel(self): """Does the method return the correct key when called with the key of an internal node with two children?""" self.assertEqual(self.pos17, self.tree.find_position(17)) def test_find_position_leaf(self): """Does the method return the correct key when called with a leaf?""" self.assertEqual(self.pos8, self.tree.find_position(8)) def test_find_position_empty(self): """Does the method return None when called on an empty tree?""" empty_tree = TreeMap() self.assertIsNone(empty_tree.find_position(44)) ### def test_find_min(self): val_8 = self.tree._Node("value at 8") self.tree[8] = val_8 # put a distinct value at 8 expected = (8, val_8) self.assertEqual(expected, self.tree.find_min()) def test_find_min_empty(self): """Does the method return None when called on an empty tree?""" empty_tree = TreeMap() self.assertIsNone(empty_tree.find_min()) ### TreeMap.find_ge def test_find_ge_no_exact_match(self): # Least key greater than or equal to 45 should be 65 expected = (65, self.tree.find_position(65).value()) self.assertEqual(expected, self.tree.find_ge(45)) def test_find_ge_first_pos_tried_less_than_k(self): # Searching for ge 31 should land on 32, via 32's parent 17 expected = (32, self.tree.find_position(32).value()) self.assertEqual(expected, self.tree.find_ge(31)) def test_find_ge_target_would_become_last(self): """Does the method return None when there's no existing key in the tree greater than or equal to the search target?""" self.assertIsNone(self.tree.find_ge(98)) def test_find_ge_empty(self): """Does the method return None when called on an empty tree?""" empty_tree = TreeMap() self.assertIsNone(empty_tree.find_ge(44)) ### TreeMap.find_range def test_find_range_full_tree(self): """Does the method iterate over all key-value pairs in the tree when both start and stop are None?""" count = 0 for node in self.tree.find_range(): self.assertIsInstance(node, tuple) # Just a rando thing to do to each, point # here is to confirm they can all be iterated # over, IMU no need to do anything fancy on # successfully touching each. count += 1 self.assertEqual(len(self.tree), count) # Confirm actually touched all def test_find_range_root_is_start(self): # If iteration starts at root with key=44, then it should iterate over # a total of 4 nodes given the setup of the hardcoded test tree. # That is, keys 44, 65, 88, and 97 count = 0 expected_keys = [44, 65, 88, 97] actual_keys = [] for node in self.tree.find_range(start=44): actual_keys.append(node[0]) count += 1 self.assertEqual(expected_keys, actual_keys) self.assertEqual(4, count) def test_find_range_root_is_stop(self): # If iteration stops at root of this hardcoded test tree, then it # should iterate over a total of 3 elements. Keys 8, 17 and 32. # It won't reach the "stop" value, same as builtin Python range. count = 0 expected_keys = [8, 17, 32] actual_keys = [] for node in self.tree.find_range(stop=44): actual_keys.append(node[0]) count += 1 self.assertEqual(expected_keys, actual_keys) self.assertEqual(3, count) def test_find_range_start_not_exact_match(self): """Does the method behave as intended when the start value isn't equal to any actual key in the tree?""" # In the hardcoded test tree, start value of 40 should yield same elements # as starting at 44. start = 40 count = 0 expected_keys = [44, 65, 88, 97] actual_keys = [] for node in self.tree.find_range(start): actual_keys.append(node[0]) count += 1 self.assertEqual(expected_keys, actual_keys) self.assertEqual(4, count) ### def test_iter(self): """Does __iter__ method yield the keys in order?""" expected_keys = [8, 17, 32, 44, 65, 88, 97] actual_keys = [] for key in self.tree: actual_keys.append(key) self.assertEqual(expected_keys, actual_keys) ### def test_delete(self): # If 44 is deleted, 32 should become the new root del self.tree[44] self.assertEqual(32, self.tree.root().key()) def test_delete_raises_key_error(self): """Does delete method raise KeyError when called with a nonexistent key?""" with self.assertRaises(KeyError): del self.tree[9001]
def test_init(self): """Can an instance of a TreeMap object be initialized?""" test_tree = TreeMap() self.assertIsInstance(test_tree, TreeMap)
def test_init(self): ht = TreeMap() assert ht.size == 0
def test_set_twice_and_get(self): ht = TreeMap() ht.set('I', 1) ht.set('V', 4) ht.set('X', 9) assert ht.size == 3 ht.set('V', 5) # Update value ht.set('X', 10) # Update value assert ht.get('I') == 1 assert ht.get('V') == 5 assert ht.get('X') == 10 assert ht.size == 3 # Check size is not overcounting
def test_items(self): ht = TreeMap() assert ht.items() == [] ht.set('I', 1) assert ht.items() == [('I', 1)] ht.set('V', 5) self.assertCountEqual(ht.items(), [('I', 1), ('V', 5)]) ht.set('X', 10) self.assertCountEqual(ht.items(), [('I', 1), ('V', 5), ('X', 10)])
def test_values(self): ht = TreeMap() assert ht.values() == [] ht.set('I', 1) assert ht.values() == [1] ht.set('V', 5) self.assertCountEqual(ht.values(), [1, 5]) # Ignore item order ht.set('X', 10) self.assertCountEqual(ht.values(), [1, 5, 10]) # Ignore item order
def test_keys(self): ht = TreeMap() assert ht.keys() == [] ht.set('I', 1) assert ht.keys() == ['I'] ht.set('V', 5) self.assertCountEqual(ht.keys(), ['I', 'V']) # Ignore item order ht.set('X', 10) self.assertCountEqual(ht.keys(), ['I', 'V', 'X']) # Ignore item order
if p._node._height == old._height: p = None else: p = self.parent(p) def _rebalance_insert(self, p): self._rebalance(p) def _rabalance_delete(self, p): self._rebalance(p) def _rebalance_access(self, p): self._rebalance(p) if __name__ == "__main__": rand = random.choices(range(20), k=10) d = TreeMap() for n in rand: d[n] = n * n for key, value in d.items(): print(key, value) print(f"min: {d.find_min()}") print(f"greater than or equal to 10: {d.find_ge(10)}") listed = d.list_by_depth() for depth in listed: for item in depth: print(item._key, item._value, end=" ") print("") for key, value in d.find_range(1, 10): print(key, value)