def test_get(self):
        """Tests the HashMap get method"""
        test_values = [("test_5", 5), ("test_-5", -5), ("test_5_", 5),
                       ("diff_word", 15), ("another_word", 20), ("set", 10),
                       ("anotha_one", -7), ("completely_different", 5),
                       ("getting_there", -1)]

        collision_values = [("completely_different", 5), ("anotha_one", -7),
                            ("set", 10), ("another_word", 20)]
        head_node = collision_values[0]
        tail_node = collision_values[3]
        student_map = HashMap(10, hash_function_1)

        # add all key value pairs to the table
        for key, val in test_values:
            student_map.put(key, val)

        # test get at linked_list head
        self.assertEqual(student_map.get(head_node[0]), head_node[1])

        # test get at linked_list tail
        self.assertEqual(student_map.get(tail_node[0]), tail_node[1])

        # test get at > 2 collision bucket
        for node in collision_values:
            self.assertEqual(student_map.get(node[0]), node[1])

        # test get with no collision
        self.assertEqual(student_map.get("getting_there"), -1)

        # test that all values are in the list
        for node in test_values:
            self.assertEqual(student_map.get(node[0]), node[1])
 def test_init(self):
     """Checks that the hash_table initializes correctly, if __init__ is provided, ignore"""
     student_map = HashMap(10, hash_function_1)
     self.assertEqual(10, student_map.capacity)
     self.assertEqual(0, student_map.size)
     self.assertEqual(hash_function_1, student_map._hash_function)
     for bucket in student_map._buckets:
         self.assertIsNone(bucket.head)
    def test_contains_key(self):
        """Tests the HashMap contains_key method"""
        test_values = [("test_5", 5), ("test_-5", -5), ("test_5_", 5),
                       ("diff_word", 15), ("another_word", 20), ("set", 10),
                       ("anotha_one", -7), ("completely_different", 5),
                       ("getting_there", -1)]

        student_map = HashMap(10, hash_function_1)

        # simple check to test that all values are in the list
        for key, val in test_values:
            student_map.put(key, val)
            found = False
            for bucket in student_map._buckets:
                if bucket.contains(key):
                    found = True
            self.assertEqual(found, student_map.contains_key(key))
    def test_put(self):
        """Tests that HashMap put method"""
        first_node = ("test_val", 5)
        collision_node = ("test_5", 5)
        # these values give a good distribution of collisions and non-collisions
        test_values = [("test_5", 5), ("test_-5", -5), ("test_5_", 5),
                       ("diff_word", 15), ("another_word", 20), ("set", 10),
                       ("anotha_one", -7), ("completely_different", 5),
                       ("getting_there", -1)]
        # Expected distribution with hf1
        #[]
        #[(test_5_, 5) -> (test_ - 5, -5)]
        #[(completely_different, 5) -> (anotha_one, -7) -> (set, 10) -> (another_word, 20)]
        #[]
        #[]
        #[(getting_there, -1)]
        #[(test_5, 5)]
        #[]
        #[(diff_word, 15)]
        #[]

        student_map = HashMap(10, hash_function_1)
        student_map_func2 = HashMap(10, hash_function_2)

        # add a single key/val pair to the table
        self.assertEqual(student_map.size, 0)
        self.assertEqual(student_map.capacity, 10)

        # add the value to both the maps
        student_map.put(first_node[0], first_node[1])
        student_map_func2.put(first_node[0], first_node[1])
        self.assertEqual(student_map.size, 1)

        # hash_function_1 expected location = bucket[6], head
        self.assertEqual(student_map._buckets[6].contains(first_node[0]).key,
                         first_node[0])
        self.assertEqual(student_map._buckets[6].contains(first_node[0]).value,
                         first_node[1])

        # hash_function_2 expected location = bucket[3], head
        self.assertEqual(
            student_map_func2._buckets[3].contains(first_node[0]).key,
            first_node[0])
        self.assertEqual(
            student_map_func2._buckets[3].contains(first_node[0]).value,
            first_node[1])

        # test same key update
        student_map.put(first_node[0], -5)
        self.assertEqual(student_map.size, 1)
        self.assertEqual(student_map._buckets[6].contains(first_node[0]).key,
                         first_node[0])
        self.assertEqual(student_map._buckets[6].contains(first_node[0]).value,
                         -5)

        # test collision add
        student_map.put(collision_node[0], collision_node[1])
        self.assertEqual(student_map._buckets[6].size, 2)
        self.assertEqual(student_map._buckets[6].contains(first_node[0]).key,
                         first_node[0])
        self.assertEqual(
            student_map._buckets[6].contains(collision_node[0]).key,
            collision_node[0])

        # expected location = bucket[6], head
        self.assertIsNotNone(student_map._buckets[6].contains(first_node[0]))

        # add all key value pairs to the table
        for key, val in test_values:
            student_map.put(key, val)

        # check that cap didnt change
        self.assertEqual(student_map.capacity, 10)

        # check that the 10 unique values were added
        self.assertEqual(student_map.size, len(test_values) + 1)
        for key, val in test_values:
            found = False
            for bucket in student_map._buckets:
                if bucket.contains(key):
                    found = True
            self.assertTrue(found)
    def test_resize_table(self):
        """Tests the resize_table method: checks that links are not changed and properties are updated"""
        test_values = [("test_5", 5), ("test_-5", -5), ("test_5_", 5),
                       ("diff_word", 15), ("another_word", 20), ("set", 10),
                       ("anotha_one", -7), ("completely_different", 5),
                       ("getting_there", -1)]
        student_map = HashMap(10, hash_function_1)
        for key, value in test_values:
            student_map.put(key, value)
        self.assertEqual(10, student_map.capacity)

        # get before resize state
        keys_before_resize = get_keys_from_map(student_map)
        size_before_resize = student_map.size

        # Test 1
        # resize the table smaller -> bigger
        student_map.resize_table(50)
        self.assertEqual(50, student_map.capacity)

        # get after resize state
        keys_after_resize = get_keys_from_map(student_map)
        size_after_resize = student_map.size

        # test that no nodes were lost in the resize
        self.assertEqual(len(keys_before_resize), len(keys_after_resize))
        self.assertEqual(size_before_resize, size_after_resize)
        for key in keys_before_resize:
            self.assertTrue(key in keys_after_resize)
        for key in keys_after_resize:
            self.assertTrue(key in keys_before_resize)

        # Test 2
        student_map = HashMap(10, hash_function_1)
        for key, value in test_values:
            student_map.put(key, value)
        self.assertEqual(10, student_map.capacity)

        # get before resize state
        keys_before_resize = get_keys_from_map(student_map)
        size_before_resize = student_map.size

        # resize the table bigger -> smaller
        student_map.resize_table(5)
        self.assertEqual(5, student_map.capacity)

        # get after resize state
        keys_after_resize = get_keys_from_map(student_map)
        size_after_resize = student_map.size

        # test that no nodes were lost in the resize
        self.assertEqual(len(keys_before_resize), len(keys_after_resize))
        self.assertEqual(size_before_resize, size_after_resize)
        for key in keys_before_resize:
            self.assertTrue(key in keys_after_resize)
        for key in keys_after_resize:
            self.assertTrue(key in keys_before_resize)
    def test_empty_buckets(self):
        """Checks the empty_buckets method"""
        test_values = [("test_5", 5), ("test_-5", -5), ("test_5_", 5),
                       ("diff_word", 15), ("another_word", 20), ("set", 10),
                       ("anotha_one", -7), ("completely_different", 5),
                       ("getting_there", -1)]

        empty_buckets = initial_capacity = 10
        student_map = HashMap(initial_capacity, hash_function_1)
        self.assertEqual(empty_buckets, student_map.empty_buckets())

        empty_buckets = initial_capacity = 20
        student_map = HashMap(initial_capacity, hash_function_1)
        self.assertEqual(empty_buckets, student_map.empty_buckets())

        student_map.put("first_value", 5)
        self.assertEqual(empty_buckets - 1, student_map.empty_buckets())

        student_map = HashMap(10, hash_function_1)
        student_map_hf2 = HashMap(10, hash_function_2)
        for key, val in test_values:
            student_map.put(key, val)
            student_map_hf2.put(key, val)
        # should have 5 empty buckets with hash_function_1
        self.assertEqual(5, student_map.empty_buckets())
        # 4 with hash_function_2
        self.assertEqual(4, student_map_hf2.empty_buckets())
    def test_remove(self):
        """Tests the HashMap remove method with both hash functions"""
        test_values = [("test_5", 5), ("test_-5", -5), ("test_5_", 12),
                       ("diff_word", 15), ("another_word", 20), ("set", 10),
                       ("tes", 8), ("anotha_one", -7),
                       ("completely_different", 13), ("getting_there", -1)]
        student_map = HashMap(10, hash_function_1)
        student_map_hf2 = HashMap(10, hash_function_2)

        # get all keys from the map
        sm_values = get_keys_from_map(student_map)
        smhf2_values = get_keys_from_map(student_map_hf2)
        self.assertEqual(len(sm_values), len(smhf2_values))
        self.assertEqual(0, len(sm_values))

        # add test values to the map
        for key, val in test_values:
            student_map.put(key, val)
            student_map_hf2.put(key, val)

        # get all keys from the map
        sm_values = get_keys_from_map(student_map)
        smhf2_values = get_keys_from_map(student_map_hf2)

        # check that all keys that are in test_values are in the map
        self.assertTrue(check_lists_are_equals(test_values, sm_values))
        self.assertTrue(check_lists_are_equals(test_values, smhf2_values))

        # test1 - remove size 1 linked list bucket node (bucket 6)
        value_to_remove = ("test_5", 5)
        # remove the tuple from the control list
        test_values.remove(value_to_remove)
        # Remove the value from the maps
        student_map.remove(value_to_remove[0])
        student_map_hf2.remove(value_to_remove[0])
        # update keys found in the map
        sm_values = get_keys_from_map(student_map)
        smhf2_values = get_keys_from_map(student_map_hf2)
        # check that all keys that are in test_values are in the map
        self.assertTrue(check_lists_are_equals(test_values, sm_values))
        self.assertTrue(check_lists_are_equals(test_values, smhf2_values))

        # test2 - remove size >1 linked list bucket node HEAD POSITION (bucket 2)
        value_to_remove = ("completely_different", 13)
        # remove the tuple from the control list
        test_values.remove(value_to_remove)
        # Remove the value from the maps
        student_map.remove(value_to_remove[0])
        student_map_hf2.remove(value_to_remove[0])
        # update keys found in the map
        sm_values = get_keys_from_map(student_map)
        smhf2_values = get_keys_from_map(student_map_hf2)
        # check that all keys that are in test_values are in the map
        self.assertTrue(check_lists_are_equals(test_values, sm_values))
        self.assertTrue(check_lists_are_equals(test_values, smhf2_values))

        # test3 - remove size >1 linked list bucket node TAIL POSITION (bucket 2)
        value_to_remove = ("another_word", 20)
        # remove the tuple from the control list
        test_values.remove(value_to_remove)
        # Remove the value from the maps
        student_map.remove(value_to_remove[0])
        student_map_hf2.remove(value_to_remove[0])
        # update keys found in the map
        sm_values = get_keys_from_map(student_map)
        smhf2_values = get_keys_from_map(student_map_hf2)
        # check that all keys that are in test_values are in the map
        self.assertTrue(check_lists_are_equals(test_values, sm_values))
        self.assertTrue(check_lists_are_equals(test_values, smhf2_values))

        # test4 - remove size >1 linked list bucket node MID POSITION (bucket 2)
        value_to_remove = ("tes", 8)
        # remove the tuple from the control list
        test_values.remove(value_to_remove)
        # Remove the value from the maps
        student_map.remove(value_to_remove[0])
        student_map_hf2.remove(value_to_remove[0])
        # update keys found in the map
        sm_values = get_keys_from_map(student_map)
        smhf2_values = get_keys_from_map(student_map_hf2)
        # check that all keys that are in test_values are in the map
        self.assertTrue(check_lists_are_equals(test_values, sm_values))
        self.assertTrue(check_lists_are_equals(test_values, smhf2_values))

        # test5 - remove size >1 linked list bucket node
        value_to_remove = ("anotha_one", -7)
        # remove the tuple from the control list
        test_values.remove(value_to_remove)
        # Remove the value from the maps
        student_map.remove(value_to_remove[0])
        student_map_hf2.remove(value_to_remove[0])
        # update keys found in the map
        sm_values = get_keys_from_map(student_map)
        smhf2_values = get_keys_from_map(student_map_hf2)
        # check that all keys that are in test_values are in the map
        self.assertTrue(check_lists_are_equals(test_values, sm_values))
        self.assertTrue(check_lists_are_equals(test_values, smhf2_values))

        # test6 - remove size >1 linked list bucket node
        value_to_remove = ("set", 10)
        # remove the tuple from the control list
        test_values.remove(value_to_remove)
        # Remove the value from the maps
        student_map.remove(value_to_remove[0])
        student_map_hf2.remove(value_to_remove[0])
        # update keys found in the map
        sm_values = get_keys_from_map(student_map)
        smhf2_values = get_keys_from_map(student_map_hf2)
        # check that all keys that are in test_values are in the map
        self.assertTrue(check_lists_are_equals(test_values, sm_values))
        self.assertTrue(check_lists_are_equals(test_values, smhf2_values))

        # test7 - remove value not in map (should do nothing)
        before_size_sm = student_map.size
        before_size_smhf2 = student_map_hf2.size
        student_map.remove("key_not_in_list")
        student_map_hf2.remove("key_not_in_list")
        self.assertEqual(before_size_sm, student_map.size)
        self.assertEqual(before_size_smhf2, student_map_hf2.size)
    def test_table_load(self):
        """Tests HashMap table_load method"""
        test_values = [("test_5", 5), ("test_-5", -5), ("test_5_", 5),
                       ("diff_word", 15), ("another_word", 20)]
        init_capacity = 10
        student_map = HashMap(init_capacity, hash_function_1)
        student_map_d = HashMap(init_capacity * 2, hash_function_1)
        # 0 / 10 = 0, 0 / 20 = 0
        self.assertEqual(student_map.table_load(), student_map_d.table_load())

        for key, val in test_values:
            student_map.put(key, val)
            student_map_d.put(key, val)

        # test known load ( 5 / 10 = 0.5 ),  ( 5 / 20 = 0.25 )
        self.assertEqual((len(test_values) / init_capacity),
                         student_map.table_load())
        self.assertEqual((len(test_values) / (init_capacity * 2)),
                         student_map_d.table_load())

        student_map = HashMap(init_capacity, hash_function_1)
        student_map_d = HashMap(init_capacity * 2, hash_function_1)

        # test high table load
        random_cases = 1000
        # add random key, value pairs to the table
        for i in range(random_cases):
            key, value = create_random_tuple()
            student_map.put(key, value)
            student_map_d.put(key, value)

        self.assertAlmostEqual(student_map.table_load(),
                               student_map_d.table_load() * 2)