|
1 | | -package com.thealgorithms.datastructures.tries; |
2 | | - |
3 | | -import static org.junit.jupiter.api.Assertions.*; |
4 | | - |
5 | | -import org.junit.jupiter.api.Test; |
6 | | - |
7 | | -class PatriciaTrieTest { |
8 | | - |
9 | | - @Test |
10 | | - void insertAndGet_basic() { |
11 | | - var t = new PatriciaTrie<Integer>(); |
12 | | - t.put("ant", 1); |
13 | | - t.put("ante", 2); |
14 | | - t.put("anti", 3); |
15 | | - assertEquals(3, t.size()); |
16 | | - assertEquals(1, t.get("ant")); |
17 | | - assertEquals(2, t.get("ante")); |
18 | | - assertEquals(3, t.get("anti")); |
19 | | - assertNull(t.get("aunt")); |
20 | | - } |
21 | | - |
22 | | - @Test |
23 | | - void overwriteValue_doesNotChangeSize() { |
24 | | - var t = new PatriciaTrie<String>(); |
25 | | - t.put("car", "A"); |
26 | | - assertEquals(1, t.size()); |
27 | | - t.put("car", "B"); |
28 | | - assertEquals(1, t.size()); |
29 | | - assertEquals("B", t.get("car")); |
30 | | - } |
31 | | - |
32 | | - @Test |
33 | | - void startsWith_variousPrefixes() { |
34 | | - var t = new PatriciaTrie<Integer>(); |
35 | | - t.put("an", 1); t.put("ant", 2); t.put("anthem", 3); t.put("banana", 4); |
36 | | - assertTrue(t.startsWith("an")); |
37 | | - assertTrue(t.startsWith("ant")); |
38 | | - assertTrue(t.startsWith("anthem")); |
39 | | - assertFalse(t.startsWith("ante")); |
40 | | - assertTrue(t.startsWith("b")); |
41 | | - assertFalse(t.startsWith("c")); |
42 | | - assertTrue(t.startsWith("")); // non-empty trie => true |
43 | | - } |
44 | | - |
45 | | - @Test |
46 | | - void unicodeKeys_supported() { |
47 | | - var t = new PatriciaTrie<String>(); |
48 | | - t.put("mañana", "sun"); |
49 | | - t.put("манго", "mango-cyrillic"); |
50 | | - assertTrue(t.contains("mañana")); |
51 | | - assertTrue(t.contains("манго")); |
52 | | - assertEquals("sun", t.get("mañana")); |
53 | | - assertTrue(t.startsWith("ма")); // prefix in Cyrillic |
54 | | - } |
55 | | - |
56 | | - @Test |
57 | | - void remove_leafKey() { |
| 1 | +@Test |
| 2 | + void insert_splitCausesNewBranch_incrementsSize() { |
58 | 3 | var t = new PatriciaTrie<Integer>(); |
59 | | - t.put("cat", 1); |
60 | | - t.put("car", 2); |
61 | | - assertTrue(t.remove("car")); |
62 | | - assertFalse(t.contains("car")); |
63 | | - assertTrue(t.contains("cat")); |
| 4 | + t.put("romane", 1); // An initial key |
64 | 5 | assertEquals(1, t.size()); |
65 | | - } |
66 | | - |
67 | | - @Test |
68 | | - void remove_internalCausesMerge() { |
69 | | - var t = new PatriciaTrie<Integer>(); |
70 | | - t.put("card", 1); |
71 | | - t.put("care", 2); |
72 | | - t.put("car", 3); |
73 | | - // remove "car" which sits on the path to "card" and "care" |
74 | | - assertTrue(t.remove("car")); |
75 | | - assertFalse(t.contains("car")); |
76 | | - assertTrue(t.contains("card")); |
77 | | - assertTrue(t.contains("care")); |
78 | | - // structure should remain accessible after merge |
79 | | - assertEquals(2, t.size()); |
80 | | - assertEquals(1, t.get("card")); |
81 | | - assertEquals(2, t.get("care")); |
82 | | - } |
83 | 6 |
|
84 | | - @Test |
85 | | - void remove_absentKey_noop() { |
86 | | - var t = new PatriciaTrie<Integer>(); |
87 | | - t.put("alpha", 1); |
88 | | - assertFalse(t.remove("alphabet")); |
89 | | - assertEquals(1, t.size()); |
90 | | - assertTrue(t.contains("alpha")); |
91 | | - } |
| 7 | + // This insertion will split the "romane" edge at "roman" |
| 8 | + // and create a new branch for "us". This is where the bug occurred. |
| 9 | + t.put("romanus", 2); |
92 | 10 |
|
93 | | - @Test |
94 | | - void emptyKey_supported() { |
95 | | - var t = new PatriciaTrie<String>(); |
96 | | - t.put("", "root"); |
97 | | - assertTrue(t.contains("")); |
98 | | - assertEquals("root", t.get("")); |
99 | | - assertTrue(t.remove("")); |
100 | | - assertFalse(t.contains("")); |
101 | | - assertEquals(0, t.size()); |
102 | | - } |
103 | | - |
104 | | - @Test |
105 | | - void nullContracts() { |
106 | | - var t = new PatriciaTrie<Integer>(); |
107 | | - assertThrows(IllegalArgumentException.class, () -> t.put(null, 1)); |
108 | | - assertThrows(IllegalArgumentException.class, () -> t.put("a", null)); |
109 | | - assertThrows(IllegalArgumentException.class, () -> t.get(null)); |
110 | | - assertThrows(IllegalArgumentException.class, () -> t.contains(null)); |
111 | | - assertThrows(IllegalArgumentException.class, () -> t.remove(null)); |
112 | | - assertThrows(IllegalArgumentException.class, () -> t.startsWith(null)); |
113 | | - } |
114 | | - |
115 | | - @Test |
116 | | - void isEmptyAndSize() { |
117 | | - var t = new PatriciaTrie<Integer>(); |
118 | | - assertTrue(t.isEmpty()); |
119 | | - t.put("x", 10); |
120 | | - assertFalse(t.isEmpty()); |
121 | | - assertEquals(1, t.size()); |
122 | | - t.remove("x"); |
123 | | - assertTrue(t.isEmpty()); |
124 | | - assertEquals(0, t.size()); |
| 11 | + assertEquals(2, t.size(), "Size should increment when a split creates a new key branch"); |
| 12 | + assertTrue(t.contains("romane")); |
| 13 | + assertTrue(t.contains("romanus")); |
| 14 | + assertEquals(1, t.get("romane")); |
| 15 | + assertEquals(2, t.get("romanus")); |
125 | 16 | } |
126 | | -} |
0 commit comments