Skip to content

Commit 3ae40c7

Browse files
committed
Add unit tests for VelocityJSONFile functionality
1 parent d778190 commit 3ae40c7

File tree

1 file changed

+140
-0
lines changed

1 file changed

+140
-0
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package com.bencodez.simpleapi.tests;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
6+
import static org.junit.jupiter.api.Assertions.assertNotNull;
7+
import static org.junit.jupiter.api.Assertions.assertTrue;
8+
9+
import java.nio.file.Files;
10+
import java.nio.file.Path;
11+
import java.util.Comparator;
12+
import java.util.List;
13+
import java.util.concurrent.Executors;
14+
15+
import org.junit.jupiter.api.DisplayName;
16+
import org.junit.jupiter.api.Test;
17+
import org.junit.jupiter.api.io.TempDir;
18+
19+
import com.bencodez.simpleapi.file.velocity.VelocityJSONFile;
20+
21+
import lombok.var;
22+
23+
class VelocityJSONFileTest {
24+
25+
@TempDir
26+
Path tmpRoot;
27+
28+
@Test
29+
@DisplayName("Constructor creates empty config and file")
30+
void fileCreationCreatesEmptyConfigAndFileExists() throws Exception {
31+
Path file = tmpRoot.resolve("config.json");
32+
Files.deleteIfExists(file);
33+
34+
VelocityJSONFile v = new VelocityJSONFile(file);
35+
36+
assertNotNull(v.getData());
37+
assertTrue(Files.exists(file));
38+
}
39+
40+
@Test
41+
@DisplayName("save() then reload persists values")
42+
void saveAndReloadPersistsValues() throws Exception {
43+
Path file = tmpRoot.resolve("config.json");
44+
VelocityJSONFile writer = new VelocityJSONFile(file);
45+
46+
writer.set(new Object[] { "some", "nested", "key" }, "myValue");
47+
writer.save();
48+
49+
VelocityJSONFile reader = new VelocityJSONFile(file);
50+
String value = reader.getString(reader.getNode("some", "nested", "key"), null);
51+
assertEquals("myValue", value);
52+
}
53+
54+
@Test
55+
@DisplayName("set/remove affects contains and getNode")
56+
void setAndRemoveAffectsContainsAndGetNode() throws Exception {
57+
Path file = tmpRoot.resolve("config.json");
58+
VelocityJSONFile v = new VelocityJSONFile(file);
59+
60+
assertFalse(v.contains("will", "exist"));
61+
v.set(new Object[] { "will", "exist" }, 123);
62+
assertTrue(v.contains("will", "exist"));
63+
assertEquals(123, v.getInt(v.getNode("will", "exist"), 0));
64+
65+
v.remove("will", "exist");
66+
assertFalse(v.contains("will", "exist"));
67+
}
68+
69+
@Test
70+
@DisplayName("getKeys returns all child keys")
71+
void getKeysReturnsAllChildKeys() throws Exception {
72+
Path file = tmpRoot.resolve("config.json");
73+
VelocityJSONFile v = new VelocityJSONFile(file);
74+
75+
v.set(new Object[] { "alpha" }, "1");
76+
v.set(new Object[] { "beta" }, "2");
77+
v.set(new Object[] { "gamma" }, "3");
78+
79+
List<String> keys = v.getKeys(v.getData());
80+
assertTrue(keys.contains("alpha"));
81+
assertTrue(keys.contains("beta"));
82+
assertTrue(keys.contains("gamma"));
83+
}
84+
85+
@Test
86+
@DisplayName("save() creates parent directories if missing")
87+
void createsParentDirectoriesOnSave() throws Exception {
88+
Path file = tmpRoot.resolve("plugins/votingplugin/nonvotedplayerscache.json");
89+
// Ensure parents don't exist
90+
if (Files.exists(file.getParent())) {
91+
Files.walk(file.getParent()).sorted(Comparator.reverseOrder()).forEach(p -> {
92+
try { Files.deleteIfExists(p); } catch (Exception ignored) {}
93+
});
94+
}
95+
96+
VelocityJSONFile v = new VelocityJSONFile(file);
97+
v.set(new Object[] { "ok" }, true);
98+
v.save();
99+
100+
assertTrue(Files.exists(file.getParent()));
101+
assertTrue(Files.size(file) > 0);
102+
}
103+
104+
@Test
105+
@DisplayName("No .tmp artifacts are left after save()")
106+
void noTmpFileLeftBehind() throws Exception {
107+
Path file = tmpRoot.resolve("x/y/z/thing.json");
108+
VelocityJSONFile v = new VelocityJSONFile(file);
109+
v.set(new Object[] { "k" }, "v");
110+
v.save();
111+
112+
Path tmp = file.resolveSibling(file.getFileName() + ".tmp");
113+
assertFalse(Files.exists(tmp));
114+
}
115+
116+
@Test
117+
@DisplayName("Concurrent saves do not throw and file remains readable")
118+
void concurrentSavesAreSafeEnough() throws Exception {
119+
Path file = tmpRoot.resolve("conc/config.json");
120+
VelocityJSONFile v = new VelocityJSONFile(file);
121+
122+
var pool = Executors.newFixedThreadPool(4);
123+
try {
124+
for (int i = 0; i < 20; i++) {
125+
final int n = i;
126+
pool.submit(() -> {
127+
v.set(new Object[] { "counter" }, n);
128+
v.save();
129+
});
130+
}
131+
} finally {
132+
pool.shutdown();
133+
Thread.sleep(200); // small settle time
134+
}
135+
136+
VelocityJSONFile re = new VelocityJSONFile(file);
137+
int last = re.getNode("counter").getInt(Integer.MIN_VALUE);
138+
assertNotEquals(Integer.MIN_VALUE, last);
139+
}
140+
}

0 commit comments

Comments
 (0)