From c1e2fbcc7fdddf21ae2f1c4e13d1ea1dcf886e53 Mon Sep 17 00:00:00 2001 From: Stanislav-Zabramnyi Date: Wed, 3 Aug 2022 14:33:15 +0200 Subject: [PATCH] added tests for size change HashTableTest, added decrement of size when removing element --- .../main/java/com/bobocode/cs/HashTable.java | 6 +- .../java/com/bobocode/cs/HashTableTest.java | 72 +++++++++++++------ 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/2-0-data-structures-and-algorithms/2-2-7-hash-table/src/main/java/com/bobocode/cs/HashTable.java b/2-0-data-structures-and-algorithms/2-2-7-hash-table/src/main/java/com/bobocode/cs/HashTable.java index 0f91e2936..f7f8663ff 100644 --- a/2-0-data-structures-and-algorithms/2-2-7-hash-table/src/main/java/com/bobocode/cs/HashTable.java +++ b/2-0-data-structures-and-algorithms/2-2-7-hash-table/src/main/java/com/bobocode/cs/HashTable.java @@ -1,9 +1,9 @@ package com.bobocode.cs; -import lombok.ToString; - import static java.util.Objects.requireNonNull; +import lombok.ToString; + /** * {@link HashTable} is a simple Hashtable-based implementation of {@link Map} interface with some additional methods. * It is based on the array of {@link Node} objects. Both {@link HashTable} and {@link Node} have two type parameters: @@ -198,12 +198,14 @@ public V remove(K key) { if (current.key.equals(key)) { var value = current.value; table[index] = current.next; + size--; return value; } while (current.next != null) { if (current.next.key.equals(key)) { var value = current.next.value; current.next = current.next.next; + size--; return value; } current = current.next; diff --git a/2-0-data-structures-and-algorithms/2-2-7-hash-table/src/test/java/com/bobocode/cs/HashTableTest.java b/2-0-data-structures-and-algorithms/2-2-7-hash-table/src/test/java/com/bobocode/cs/HashTableTest.java index 8f2d5096b..a952074d3 100644 --- a/2-0-data-structures-and-algorithms/2-2-7-hash-table/src/test/java/com/bobocode/cs/HashTableTest.java +++ b/2-0-data-structures-and-algorithms/2-2-7-hash-table/src/test/java/com/bobocode/cs/HashTableTest.java @@ -1,9 +1,12 @@ package com.bobocode.cs; -import lombok.SneakyThrows; -import org.junit.jupiter.api.ClassOrderer.OrderAnnotation; -import org.junit.jupiter.api.*; -import org.mockito.Mockito; +import static java.lang.reflect.Modifier.isStatic; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.reflect.Field; import java.util.Arrays; @@ -12,12 +15,15 @@ import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static java.lang.reflect.Modifier.isStatic; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +import lombok.SneakyThrows; +import org.junit.jupiter.api.ClassOrderer.OrderAnnotation; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestClassOrder; +import org.junit.jupiter.api.TestMethodOrder; /** * A Reflection-based step by step test for a {@link HashTable} class. PLEASE NOTE that Reflection API should not be used @@ -28,6 +34,7 @@ @TestClassOrder(OrderAnnotation.class) @DisplayName("HashTable Test") class HashTableTest { + private HashTable hashTable = new HashTable<>(); @Nested @@ -126,6 +133,7 @@ void nodeConstructorAcceptKeyValue() { @DisplayName("2. HashTable fields Test") @TestMethodOrder(MethodOrderer.OrderAnnotation.class) class HashTableFieldsTest { + @Test @Order(1) @DisplayName("HastTable has a field 'table' which is an array of nodes") @@ -155,6 +163,7 @@ void sizeFieldExists() { @DisplayName("3. HashTable constructors Test") @TestMethodOrder(MethodOrderer.OrderAnnotation.class) class HashTableConstructorsTest { + @Test @Order(1) @SneakyThrows @@ -198,6 +207,7 @@ void constructorWithTableCapacityWhenArgumentIsNegative() { @DisplayName("4. Hash Function Test") @TestMethodOrder(MethodOrderer.OrderAnnotation.class) class HashFunctionTest { + @Test @Order(1) @DisplayName("calculateIndex returns the same value for the same key") @@ -221,8 +231,8 @@ void calculateIndexReturnDifferentValuesWheKeysAreDifferent() { assertThat(indexSet) .hasSizeGreaterThan(1); - } - + } + @Test @Order(3) @DisplayName("calculateIndex returns values in array bounds") @@ -235,7 +245,7 @@ void calculateIndexReturnIndexInArrayBounds() { var indexes = keys.stream() .map(key -> HashTable.calculateIndex(key, arrayCapacity)) .toList(); - + assertThat(indexes) .isNotEmpty() .allMatch(i -> i >= 0 && i < arrayCapacity); @@ -262,7 +272,7 @@ class HashTableMethodsTest { @Test @SneakyThrows @Order(1) - @DisplayName("put creates new entry and returns null when the table is empty") + @DisplayName("put creates new entry and returns null when the table is empty, should increase the table size") void putWhenTableIsEmpty() { var previousValue = hashTable.put("madmax", 833); @@ -270,11 +280,12 @@ void putWhenTableIsEmpty() { assertNull(previousValue); assertTrue(keyValueExists); + assertEquals(1, getSize()); } @Test @Order(2) - @DisplayName("put elements adds entry to to the same bucket when the hash code is the same") + @DisplayName("put elements adds entry to the same bucket and increases table size when the hash code is the same") @SneakyThrows void putTwoElementsWithTheSameHashCode() { var table = getInternalTable(hashTable); @@ -290,11 +301,13 @@ void putTwoElementsWithTheSameHashCode() { assertTrue(containsKeyValueA); assertTrue(containsKeyValueB); assertThat(bucketIndexA).isEqualTo(bucketIndexB); + assertEquals(2, getSize()); } @Test @Order(3) - @DisplayName("put element updates the value and returns the previous one when key is the same") + @DisplayName( + "put element updates the value and returns the previous one when key is the same, should not increase table size") void putElementWithTheSameKey() { hashTable.put("madmax", 833); System.out.println(hashTable); @@ -305,6 +318,7 @@ void putElementWithTheSameKey() { assertThat(previousValue).isEqualTo(833); assertTrue(containsNewValueByKey); + assertEquals(1, getSize()); } @Test @@ -430,14 +444,15 @@ void isEmptyWhenThereIsNoElements() { @Test @Order(13) - @DisplayName("remove deletes the entry and returns a value") + @DisplayName("remove deletes the entry, decreases table size and returns a value") void remove() { addToTable("madmax", 833); - + setSize(1); var result = hashTable.remove("madmax"); assertThat(result).isEqualTo(833); assertFalse(checkKeyValueExists("madmaxx", 833)); + assertEquals(0, getSize()); } @Test @@ -451,27 +466,32 @@ void removeWhenKeyDoesNotExists() { @Test @Order(15) - @DisplayName("remove deletes the element when it's in the middle of the list") + @DisplayName("remove deletes the element when it's in the middle of the list and decreases the size of table") void removeFromTheMiddleOfTheList() { addToTable("AaAa", 843); addToTable("BBBB", 434); addToTable("AaBB", 587); + var size = 3; + setSize(size); var removedValue = hashTable.remove("BBBB"); assertTrue(checkKeyValueExists("AaAa", 843)); assertFalse(checkKeyExists("BBBB")); assertTrue(checkKeyValueExists("AaBB", 587)); assertThat(removedValue).isEqualTo(434); - } - + assertEquals(size - 1, getSize()); + } + @Test @Order(16) - @DisplayName("remove deletes the element when it's in the end of the list") + @DisplayName("remove deletes the element when it's in the end of the list and decreases the size of table") void removeFromTheEndOfTheList() { addToTable("AaAa", 843); addToTable("BBBB", 434); addToTable("AaBB", 587); + var size = 3; + setSize(size); var removedValue = hashTable.remove("AaBB"); @@ -479,6 +499,7 @@ void removeFromTheEndOfTheList() { assertTrue(checkKeyValueExists("BBBB", 434)); assertFalse(checkKeyExists("AaBB")); assertThat(removedValue).isEqualTo(587); + assertEquals(2, getSize()); } } @@ -585,6 +606,13 @@ private void setSize(int size) { sizeField.set(hashTable, size); } + @SneakyThrows + private int getSize() { + var sizeField = HashTable.class.getDeclaredField("size"); + sizeField.setAccessible(true); + return sizeField.getInt(hashTable); + } + private String tableToString(Object[] table) { StringBuilder result = new StringBuilder(); var n = table.length;