Newer
Older
noctua / src / test / java / com / cube / index / CubicIndexTest.java
@agalyaramadoss agalyaramadoss on 13 Feb 9 KB first commit
package com.cube.index;

import org.junit.jupiter.api.*;
import java.util.*;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Tests for Cubic Index System
 */
public class CubicIndexTest {
    
    @Test
    public void testCubicIndexCalculation() {
        // Test cubic index formula: N³ × 6
        assertEquals(6, CubicIndexNode.calculateCubicIndex(1));      // 1³×6 = 6
        assertEquals(48, CubicIndexNode.calculateCubicIndex(2));     // 2³×6 = 48
        assertEquals(162, CubicIndexNode.calculateCubicIndex(3));    // 3³×6 = 162
        assertEquals(384, CubicIndexNode.calculateCubicIndex(4));    // 4³×6 = 384
        assertEquals(750, CubicIndexNode.calculateCubicIndex(5));    // 5³×6 = 750
        assertEquals(1296, CubicIndexNode.calculateCubicIndex(6));   // 6³×6 = 1296
    }
    
    @Test
    public void testLevelCalculation() {
        // Test calculating level from index value
        assertEquals(1, CubicIndexNode.calculateLevel(6));
        assertEquals(2, CubicIndexNode.calculateLevel(48));
        assertEquals(3, CubicIndexNode.calculateLevel(162));
        assertEquals(4, CubicIndexNode.calculateLevel(384));
        assertEquals(5, CubicIndexNode.calculateLevel(750));
    }
    
    @Test
    public void testSideDetermination() {
        // Test that keys are consistently mapped to sides
        String key1 = "test-key-1";
        CubicIndexNode.Side side1 = CubicIndexNode.determineSide(key1);
        
        assertNotNull(side1);
        
        // Same key should always map to same side
        assertEquals(side1, CubicIndexNode.determineSide(key1));
        
        // Test all possible sides
        Set<CubicIndexNode.Side> seenSides = new HashSet<>();
        for (int i = 0; i < 100; i++) {
            CubicIndexNode.Side side = CubicIndexNode.determineSide("key-" + i);
            seenSides.add(side);
        }
        
        // With 100 keys, we should see multiple sides
        assertTrue(seenSides.size() > 1, "Keys should distribute across multiple sides");
    }
    
    @Test
    public void testCubicNodeCreation() {
        CubicIndexNode node = new CubicIndexNode(3);
        
        assertEquals(3, node.getLevel());
        assertEquals(162, node.getIndexValue());
        assertEquals(0, node.getTotalSize());
    }
    
    @Test
    public void testCubicNodePutAndGet() {
        CubicIndexNode node = new CubicIndexNode(2);
        
        // Put data
        node.put("key1", "value1".getBytes());
        node.put("key2", "value2".getBytes());
        node.put("key3", "value3".getBytes());
        
        // Get data
        assertArrayEquals("value1".getBytes(), node.get("key1"));
        assertArrayEquals("value2".getBytes(), node.get("key2"));
        assertArrayEquals("value3".getBytes(), node.get("key3"));
        
        // Total size
        assertEquals(3, node.getTotalSize());
    }
    
    @Test
    public void testCubicNodeSideDistribution() {
        CubicIndexNode node = new CubicIndexNode(3);
        
        // Add many keys
        for (int i = 0; i < 60; i++) {
            node.put("key-" + i, ("value-" + i).getBytes());
        }
        
        assertEquals(60, node.getTotalSize());
        
        // Check that keys are distributed across sides
        Map<String, Object> stats = node.getStats();
        @SuppressWarnings("unchecked")
        Map<String, Integer> sideDistribution = (Map<String, Integer>) stats.get("sideDistribution");
        
        assertNotNull(sideDistribution);
        assertEquals(6, sideDistribution.size());
        
        // At least some sides should have keys
        long nonEmptySides = sideDistribution.values().stream().filter(count -> count > 0).count();
        assertTrue(nonEmptySides > 1, "Keys should be distributed across multiple sides");
    }
    
    @Test
    public void testCubicIndexTree() {
        CubicIndexTree tree = new CubicIndexTree(3, 10, true);
        
        // Put data
        tree.put("user:1", "Alice".getBytes());
        tree.put("user:2", "Bob".getBytes());
        tree.put("user:3", "Charlie".getBytes());
        tree.put("product:1", "Laptop".getBytes());
        tree.put("product:2", "Mouse".getBytes());
        
        // Get data
        assertArrayEquals("Alice".getBytes(), tree.get("user:1"));
        assertArrayEquals("Bob".getBytes(), tree.get("user:2"));
        assertArrayEquals("Laptop".getBytes(), tree.get("product:1"));
        
        // Total size
        assertEquals(5, tree.getTotalSize());
    }
    
    @Test
    public void testPrefixSearch() {
        CubicIndexTree tree = new CubicIndexTree(3, 10, true);
        
        // Add data
        tree.put("user:1:name", "Alice".getBytes());
        tree.put("user:1:email", "alice@example.com".getBytes());
        tree.put("user:2:name", "Bob".getBytes());
        tree.put("user:2:email", "bob@example.com".getBytes());
        tree.put("product:1", "Laptop".getBytes());
        
        // Search by prefix
        List<String> userKeys = tree.searchPrefix("user:");
        assertEquals(4, userKeys.size());
        assertTrue(userKeys.contains("user:1:name"));
        assertTrue(userKeys.contains("user:1:email"));
        
        List<String> user1Keys = tree.searchPrefix("user:1");
        assertEquals(2, user1Keys.size());
        
        List<String> productKeys = tree.searchPrefix("product:");
        assertEquals(1, productKeys.size());
    }
    
    @Test
    public void testRangeSearch() {
        CubicIndexTree tree = new CubicIndexTree(3, 10, true);
        
        // Add sequential keys
        for (int i = 0; i < 20; i++) {
            tree.put(String.format("key-%03d", i), ("value-" + i).getBytes());
        }
        
        // Range search
        List<String> range = tree.searchRange("key-005", "key-010");
        
        assertTrue(range.size() >= 6); // At least 005-010
        assertTrue(range.contains("key-005"));
        assertTrue(range.contains("key-010"));
    }
    
    @Test
    public void testAutoExpansion() {
        CubicIndexTree tree = new CubicIndexTree(2, 10, true);
        
        assertEquals(2, tree.getLevelCount());
        
        // Add enough data to potentially trigger expansion
        for (int i = 0; i < 100; i++) {
            tree.put("key-" + i, ("value-" + i).getBytes());
        }
        
        // Tree should maintain or expand levels
        assertTrue(tree.getLevelCount() >= 2);
    }
    
    @Test
    public void testRebalance() {
        CubicIndexTree tree = new CubicIndexTree(3, 10, true);
        
        // Add data
        for (int i = 0; i < 50; i++) {
            tree.put("key-" + i, ("value-" + i).getBytes());
        }
        
        int beforeSize = tree.getTotalSize();
        
        // Rebalance
        tree.rebalance();
        
        // Size should remain the same
        assertEquals(beforeSize, tree.getTotalSize());
        
        // Data should still be accessible
        assertArrayEquals("value-0".getBytes(), tree.get("key-0"));
        assertArrayEquals("value-25".getBytes(), tree.get("key-25"));
    }
    
    @Test
    public void testRemove() {
        CubicIndexTree tree = new CubicIndexTree(3, 10, true);
        
        tree.put("key1", "value1".getBytes());
        tree.put("key2", "value2".getBytes());
        
        assertEquals(2, tree.getTotalSize());
        
        // Remove
        assertTrue(tree.remove("key1"));
        
        assertEquals(1, tree.getTotalSize());
        assertNull(tree.get("key1"));
        assertArrayEquals("value2".getBytes(), tree.get("key2"));
        
        // Remove non-existent key
        assertFalse(tree.remove("nonexistent"));
    }
    
    @Test
    public void testGetAllKeys() {
        CubicIndexTree tree = new CubicIndexTree(3, 10, true);
        
        tree.put("key1", "value1".getBytes());
        tree.put("key2", "value2".getBytes());
        tree.put("key3", "value3".getBytes());
        
        Set<String> allKeys = tree.getAllKeys();
        
        assertEquals(3, allKeys.size());
        assertTrue(allKeys.contains("key1"));
        assertTrue(allKeys.contains("key2"));
        assertTrue(allKeys.contains("key3"));
    }
    
    @Test
    public void testCubicIndexStatistics() {
        CubicIndexTree tree = new CubicIndexTree(5, 20, true);
        
        // Add data
        for (int i = 0; i < 100; i++) {
            tree.put("key-" + i, ("value-" + i).getBytes());
        }
        
        Map<String, Object> stats = tree.getStats();
        
        assertNotNull(stats);
        assertTrue((Integer) stats.get("totalKeys") > 0);
        assertTrue((Integer) stats.get("totalLevels") > 0);
        assertNotNull(stats.get("sideDistribution"));
        assertNotNull(stats.get("levels"));
    }
    
    @Test
    public void testSideEnumeration() {
        // Test all 6 sides exist
        CubicIndexNode.Side[] sides = CubicIndexNode.Side.values();
        assertEquals(6, sides.length);
        
        // Test side names
        assertEquals("FRONT", CubicIndexNode.Side.FRONT.name());
        assertEquals("BACK", CubicIndexNode.Side.BACK.name());
        assertEquals("LEFT", CubicIndexNode.Side.LEFT.name());
        assertEquals("RIGHT", CubicIndexNode.Side.RIGHT.name());
        assertEquals("TOP", CubicIndexNode.Side.TOP.name());
        assertEquals("BOTTOM", CubicIndexNode.Side.BOTTOM.name());
        
        // Test side indices
        assertEquals(0, CubicIndexNode.Side.FRONT.getIndex());
        assertEquals(5, CubicIndexNode.Side.BOTTOM.getIndex());
    }
}