package com.juliasoft.beedeedee.factories; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import java.util.Arrays; import org.junit.Before; import org.junit.Test; public class ResizingAndGarbageCollectedUniqueTableTest { private ResizingAndGarbageCollectedUniqueTable ut; private Factory factoryMock; @Before public void setUp() { factoryMock = mock(Factory.class); ut = new ResizingAndGarbageCollectedUniqueTable(10, 10, factoryMock); } @Test public void testCompactTable1() { // terminals ut.get(Integer.MAX_VALUE - 1, -1, -1); ut.get(Integer.MAX_VALUE, -1, -1); assertEquals(2, ut.get(3, 0, 1)); assertEquals(3, ut.get(4, 0, 1)); // let's kill node 2 boolean[] aliveNodes = new boolean[] { true, true, false, true }; // so compactTable collects it assertEquals(1, ut.compactTable(aliveNodes)); Arrays.fill(ut.H, -1); ut.updateHashTable(); // x4 should have been shifted back by one assertEquals(2, ut.get(4, 0, 1)); assertEquals(3, ut.nextPos); } @Test public void testCompactTable2() { // terminals ut.get(Integer.MAX_VALUE - 1, -1, -1); ut.get(Integer.MAX_VALUE, -1, -1); assertEquals(2, ut.get(31, 0, 1)); assertEquals(3, ut.get(4, 0, 1)); assertEquals(4, ut.get(25, 3, 1)); // let's kill node 2 boolean[] aliveNodes = new boolean[] { true, true, false, true, true }; // so compactTable collects it assertEquals(1, ut.compactTable(aliveNodes)); Arrays.fill(ut.H, -1); ut.updateHashTable(); // x4 should have been shifted back by one assertEquals(2, ut.get(4, 0, 1)); // reference in other node changed as well assertEquals(4, ut.nextPos); assertEquals(3, ut.get(25, 2, 1)); // was 25, 3, 1 } @Test public void testUpdateHashTable1() { ut.get(3, 0, 1); ut.get(4, 10, 1); ut.get(5, 100, 0); int[] H = ut.H; Arrays.fill(H, -1); ut.updateHashTable(); // H contains node position, given its hash assertEquals(0, H[ut.hash(3, 0, 1)]); assertEquals(1, H[ut.hash(4, 10, 1)]); assertEquals(2, H[ut.hash(5, 100, 0)]); } @Test public void testUpdateHashTable2() { redefineHashInTestDouble(10); ut.get(3, 0, 1); // hash(...) considers only low and high, so these should have the same hash (same chain) ut.get(4, 10, 1); ut.get(5, 10, 1); assertEquals(2, ut.next(1)); // reset next for node 1 ut.setNext(1, -1); Arrays.fill(ut.H, -1); ut.updateHashTable(); // should be restored by updateHashTable assertEquals(2, ut.next(1)); } /** * Redefine hash to use only low and high. */ private void redefineHashInTestDouble(int size) { ut = new ResizingAndGarbageCollectedUniqueTable(size, 10, factoryMock) { @Override protected int hash(int var, int low, int high, int size) { int num = low; while (low > 0) { low >>>= 1; high <<= 1; } return (num |= high) >= 0 ? num % size : (-num) % size; } }; } @Test public void testExpandTable() { int pos = ut.hash(13, 20, 41); int createdNode = ut.expandTable(13, 20, 41, null, pos ); // node is actually created by expandTable assertEquals(createdNode, ut.H[pos]); assertEquals(13, ut.var(createdNode)); assertEquals(20, ut.low(createdNode)); assertEquals(41, ut.high(createdNode)); } @Test public void testExpandTableTwoNodesSameHash() { int pos = ut.hash(13, 20, 41); int node1 = ut.expandTable(13, 20, 41, null, pos); int node2 = ut.expandTable(1024, 20, 41, null, pos); assertEquals(node2, ut.next(node1)); } @Test public void testExpandTableDebugging() { redefineHashInTestDouble(2); ut.get(1, 2, 3); ut.get(2, 2, 3); // this triggers resizing, hash changes in the middle of operation int pos1 = ut.get(3, 3, 2); int pos2 = ut.get(3, 3, 2); assertEquals(pos1, pos2); } }