Skip to content

Commit e5c49e7

Browse files
BarbatosBarbatos
authored andcommitted
test(plugins): add direct unit tests for KeystoreCliUtils
Cover utility methods (stripLineEndings, jsonMap, isValidKeystoreFile, checkFileExists, readPassword, ensureDirectory, printJson, printSecurityTips, atomicMove, generateKeystoreFile, setOwnerOnly) with direct unit tests, including edge cases like BOM, various line endings, empty strings, and both ECDSA/SM2 key paths.
1 parent 309dc23 commit e5c49e7

1 file changed

Lines changed: 350 additions & 0 deletions

File tree

Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
package org.tron.plugins;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertFalse;
5+
import static org.junit.Assert.assertNotNull;
6+
import static org.junit.Assert.assertNull;
7+
import static org.junit.Assert.assertTrue;
8+
9+
import java.io.File;
10+
import java.io.PrintWriter;
11+
import java.io.StringWriter;
12+
import java.nio.charset.StandardCharsets;
13+
import java.nio.file.Files;
14+
import java.security.SecureRandom;
15+
import java.util.Map;
16+
import org.junit.Rule;
17+
import org.junit.Test;
18+
import org.junit.rules.TemporaryFolder;
19+
import org.tron.common.crypto.SignInterface;
20+
import org.tron.common.crypto.SignUtils;
21+
import org.tron.keystore.WalletFile;
22+
23+
public class KeystoreCliUtilsTest {
24+
25+
@Rule
26+
public TemporaryFolder tempFolder = new TemporaryFolder();
27+
28+
@Test
29+
public void testStripLineEndingsNoChange() {
30+
assertEquals("password", KeystoreCliUtils.stripLineEndings("password"));
31+
}
32+
33+
@Test
34+
public void testStripLineEndingsTrailingLf() {
35+
assertEquals("password", KeystoreCliUtils.stripLineEndings("password\n"));
36+
}
37+
38+
@Test
39+
public void testStripLineEndingsTrailingCrLf() {
40+
assertEquals("password", KeystoreCliUtils.stripLineEndings("password\r\n"));
41+
}
42+
43+
@Test
44+
public void testStripLineEndingsTrailingCr() {
45+
assertEquals("password", KeystoreCliUtils.stripLineEndings("password\r"));
46+
}
47+
48+
@Test
49+
public void testStripLineEndingsMultipleTrailing() {
50+
assertEquals("password", KeystoreCliUtils.stripLineEndings("password\r\n\r\n"));
51+
}
52+
53+
@Test
54+
public void testStripLineEndingsBom() {
55+
assertEquals("password", KeystoreCliUtils.stripLineEndings("\uFEFFpassword"));
56+
}
57+
58+
@Test
59+
public void testStripLineEndingsBomAndTrailing() {
60+
assertEquals("password",
61+
KeystoreCliUtils.stripLineEndings("\uFEFFpassword\r\n"));
62+
}
63+
64+
@Test
65+
public void testStripLineEndingsEmpty() {
66+
assertEquals("", KeystoreCliUtils.stripLineEndings(""));
67+
}
68+
69+
@Test
70+
public void testStripLineEndingsOnlyLineEndings() {
71+
assertEquals("", KeystoreCliUtils.stripLineEndings("\r\n\r\n"));
72+
}
73+
74+
@Test
75+
public void testJsonMapEven() {
76+
Map<String, String> m = KeystoreCliUtils.jsonMap("a", "1", "b", "2");
77+
assertEquals(2, m.size());
78+
assertEquals("1", m.get("a"));
79+
assertEquals("2", m.get("b"));
80+
}
81+
82+
@Test
83+
public void testJsonMapPreservesOrder() {
84+
Map<String, String> m = KeystoreCliUtils.jsonMap(
85+
"z", "1", "a", "2", "m", "3");
86+
String[] keys = m.keySet().toArray(new String[0]);
87+
assertEquals("z", keys[0]);
88+
assertEquals("a", keys[1]);
89+
assertEquals("m", keys[2]);
90+
}
91+
92+
@Test
93+
public void testJsonMapEmpty() {
94+
Map<String, String> m = KeystoreCliUtils.jsonMap();
95+
assertTrue(m.isEmpty());
96+
}
97+
98+
@Test
99+
public void testIsValidKeystoreFileValid() {
100+
WalletFile wf = new WalletFile();
101+
wf.setAddress("TAddr");
102+
wf.setVersion(3);
103+
wf.setCrypto(new WalletFile.Crypto());
104+
assertTrue(KeystoreCliUtils.isValidKeystoreFile(wf));
105+
}
106+
107+
@Test
108+
public void testIsValidKeystoreFileNullAddress() {
109+
WalletFile wf = new WalletFile();
110+
wf.setVersion(3);
111+
wf.setCrypto(new WalletFile.Crypto());
112+
assertFalse(KeystoreCliUtils.isValidKeystoreFile(wf));
113+
}
114+
115+
@Test
116+
public void testIsValidKeystoreFileNullCrypto() {
117+
WalletFile wf = new WalletFile();
118+
wf.setAddress("TAddr");
119+
wf.setVersion(3);
120+
assertFalse(KeystoreCliUtils.isValidKeystoreFile(wf));
121+
}
122+
123+
@Test
124+
public void testIsValidKeystoreFileWrongVersion() {
125+
WalletFile wf = new WalletFile();
126+
wf.setAddress("TAddr");
127+
wf.setVersion(2);
128+
wf.setCrypto(new WalletFile.Crypto());
129+
assertFalse(KeystoreCliUtils.isValidKeystoreFile(wf));
130+
}
131+
132+
@Test
133+
public void testCheckFileExistsNull() {
134+
StringWriter err = new StringWriter();
135+
assertTrue(KeystoreCliUtils.checkFileExists(null, "Label",
136+
new PrintWriter(err)));
137+
assertEquals("", err.toString());
138+
}
139+
140+
@Test
141+
public void testCheckFileExistsMissing() {
142+
StringWriter err = new StringWriter();
143+
File missing = new File("/tmp/nonexistent-cli-utils-test-file");
144+
assertFalse(KeystoreCliUtils.checkFileExists(missing, "Key file",
145+
new PrintWriter(err)));
146+
assertTrue(err.toString().contains("Key file not found"));
147+
}
148+
149+
@Test
150+
public void testCheckFileExistsPresent() throws Exception {
151+
StringWriter err = new StringWriter();
152+
File f = tempFolder.newFile("present.txt");
153+
assertTrue(KeystoreCliUtils.checkFileExists(f, "Key file",
154+
new PrintWriter(err)));
155+
}
156+
157+
@Test
158+
public void testReadPasswordFromFile() throws Exception {
159+
File pwFile = tempFolder.newFile("pw.txt");
160+
Files.write(pwFile.toPath(), "goodpassword".getBytes(StandardCharsets.UTF_8));
161+
StringWriter err = new StringWriter();
162+
String pw = KeystoreCliUtils.readPassword(pwFile, new PrintWriter(err));
163+
assertEquals("goodpassword", pw);
164+
}
165+
166+
@Test
167+
public void testReadPasswordFromFileWithLineEndings() throws Exception {
168+
File pwFile = tempFolder.newFile("pw-crlf.txt");
169+
Files.write(pwFile.toPath(), "goodpassword\r\n".getBytes(StandardCharsets.UTF_8));
170+
StringWriter err = new StringWriter();
171+
String pw = KeystoreCliUtils.readPassword(pwFile, new PrintWriter(err));
172+
assertEquals("goodpassword", pw);
173+
}
174+
175+
@Test
176+
public void testReadPasswordFromFileWithBom() throws Exception {
177+
File pwFile = tempFolder.newFile("pw-bom.txt");
178+
Files.write(pwFile.toPath(),
179+
"\uFEFFgoodpassword".getBytes(StandardCharsets.UTF_8));
180+
StringWriter err = new StringWriter();
181+
String pw = KeystoreCliUtils.readPassword(pwFile, new PrintWriter(err));
182+
assertEquals("goodpassword", pw);
183+
}
184+
185+
@Test
186+
public void testReadPasswordFileTooLarge() throws Exception {
187+
File pwFile = tempFolder.newFile("pw-big.txt");
188+
byte[] big = new byte[1025];
189+
java.util.Arrays.fill(big, (byte) 'a');
190+
Files.write(pwFile.toPath(), big);
191+
StringWriter err = new StringWriter();
192+
String pw = KeystoreCliUtils.readPassword(pwFile, new PrintWriter(err));
193+
assertNull(pw);
194+
assertTrue(err.toString().contains("too large"));
195+
}
196+
197+
@Test
198+
public void testReadPasswordFileShort() throws Exception {
199+
File pwFile = tempFolder.newFile("pw-short.txt");
200+
Files.write(pwFile.toPath(), "abc".getBytes(StandardCharsets.UTF_8));
201+
StringWriter err = new StringWriter();
202+
String pw = KeystoreCliUtils.readPassword(pwFile, new PrintWriter(err));
203+
assertNull(pw);
204+
assertTrue(err.toString().contains("at least 6"));
205+
}
206+
207+
@Test
208+
public void testReadPasswordFileNotFound() throws Exception {
209+
StringWriter err = new StringWriter();
210+
String pw = KeystoreCliUtils.readPassword(
211+
new File("/tmp/nonexistent-pw-direct-test.txt"), new PrintWriter(err));
212+
assertNull(pw);
213+
assertTrue(err.toString().contains("Password file not found"));
214+
}
215+
216+
@Test
217+
public void testEnsureDirectoryCreatesNested() throws Exception {
218+
File dir = new File(tempFolder.getRoot(), "a/b/c");
219+
assertFalse(dir.exists());
220+
KeystoreCliUtils.ensureDirectory(dir);
221+
assertTrue(dir.exists());
222+
assertTrue(dir.isDirectory());
223+
}
224+
225+
@Test
226+
public void testEnsureDirectoryExisting() throws Exception {
227+
File dir = tempFolder.newFolder("existing");
228+
KeystoreCliUtils.ensureDirectory(dir);
229+
assertTrue(dir.isDirectory());
230+
}
231+
232+
@Test(expected = java.io.IOException.class)
233+
public void testEnsureDirectoryPathIsFile() throws Exception {
234+
File f = tempFolder.newFile("not-a-dir");
235+
KeystoreCliUtils.ensureDirectory(f);
236+
}
237+
238+
@Test
239+
public void testPrintJsonValidOutput() {
240+
StringWriter out = new StringWriter();
241+
StringWriter err = new StringWriter();
242+
KeystoreCliUtils.printJson(new PrintWriter(out), new PrintWriter(err),
243+
KeystoreCliUtils.jsonMap("address", "TAddr", "file", "file.json"));
244+
String s = out.toString().trim();
245+
assertTrue(s.contains("\"address\":\"TAddr\""));
246+
assertTrue(s.contains("\"file\":\"file.json\""));
247+
}
248+
249+
@Test
250+
public void testPrintSecurityTipsIncludesAddressAndFile() {
251+
StringWriter out = new StringWriter();
252+
KeystoreCliUtils.printSecurityTips(new PrintWriter(out),
253+
"TMyAddress", "/path/to/keystore.json");
254+
String s = out.toString();
255+
assertTrue(s.contains("TMyAddress"));
256+
assertTrue(s.contains("/path/to/keystore.json"));
257+
assertTrue(s.contains("NEVER share"));
258+
assertTrue(s.contains("BACKUP"));
259+
assertTrue(s.contains("REMEMBER"));
260+
}
261+
262+
@Test
263+
public void testAtomicMove() throws Exception {
264+
File src = tempFolder.newFile("src.txt");
265+
Files.write(src.toPath(), "hello".getBytes(StandardCharsets.UTF_8));
266+
File target = new File(tempFolder.getRoot(), "target.txt");
267+
268+
KeystoreCliUtils.atomicMove(src, target);
269+
assertFalse(src.exists());
270+
assertTrue(target.exists());
271+
assertEquals("hello",
272+
new String(Files.readAllBytes(target.toPath()), StandardCharsets.UTF_8));
273+
}
274+
275+
@Test
276+
public void testAtomicMoveReplacesExisting() throws Exception {
277+
File src = tempFolder.newFile("src2.txt");
278+
Files.write(src.toPath(), "new".getBytes(StandardCharsets.UTF_8));
279+
File target = tempFolder.newFile("target2.txt");
280+
Files.write(target.toPath(), "old".getBytes(StandardCharsets.UTF_8));
281+
282+
KeystoreCliUtils.atomicMove(src, target);
283+
assertEquals("new",
284+
new String(Files.readAllBytes(target.toPath()), StandardCharsets.UTF_8));
285+
}
286+
287+
@Test
288+
public void testGenerateKeystoreFileFullScrypt() throws Exception {
289+
File dir = tempFolder.newFolder("gen-full");
290+
SignInterface keyPair = SignUtils.getGeneratedRandomSign(
291+
SecureRandom.getInstance("NativePRNG"), true);
292+
StringWriter err = new StringWriter();
293+
294+
String fileName = KeystoreCliUtils.generateKeystoreFile(
295+
"password123", keyPair, dir, true, new PrintWriter(err));
296+
297+
assertNotNull(fileName);
298+
assertTrue(fileName.endsWith(".json"));
299+
File file = new File(dir, fileName);
300+
assertTrue(file.exists());
301+
}
302+
303+
@Test
304+
public void testGenerateKeystoreFileLightScrypt() throws Exception {
305+
File dir = tempFolder.newFolder("gen-light");
306+
SignInterface keyPair = SignUtils.getGeneratedRandomSign(
307+
SecureRandom.getInstance("NativePRNG"), true);
308+
StringWriter err = new StringWriter();
309+
310+
String fileName = KeystoreCliUtils.generateKeystoreFile(
311+
"password123", keyPair, dir, false, new PrintWriter(err));
312+
313+
assertNotNull(fileName);
314+
File file = new File(dir, fileName);
315+
assertTrue(file.exists());
316+
}
317+
318+
@Test
319+
public void testGenerateKeystoreFileLeavesNoTempFile() throws Exception {
320+
File dir = tempFolder.newFolder("gen-notemp");
321+
SignInterface keyPair = SignUtils.getGeneratedRandomSign(
322+
SecureRandom.getInstance("NativePRNG"), true);
323+
StringWriter err = new StringWriter();
324+
325+
KeystoreCliUtils.generateKeystoreFile(
326+
"password123", keyPair, dir, false, new PrintWriter(err));
327+
328+
File[] tempFiles = dir.listFiles((d, name) -> name.startsWith("keystore-")
329+
&& name.endsWith(".tmp"));
330+
assertNotNull(tempFiles);
331+
assertEquals("No temp files should remain after generation", 0, tempFiles.length);
332+
}
333+
334+
@Test
335+
public void testSetOwnerOnly() throws Exception {
336+
String os = System.getProperty("os.name").toLowerCase();
337+
org.junit.Assume.assumeTrue("POSIX permissions test", !os.contains("win"));
338+
339+
File f = tempFolder.newFile("perm-test.txt");
340+
StringWriter err = new StringWriter();
341+
KeystoreCliUtils.setOwnerOnly(f, new PrintWriter(err));
342+
343+
java.util.Set<java.nio.file.attribute.PosixFilePermission> perms =
344+
Files.getPosixFilePermissions(f.toPath());
345+
assertEquals(java.util.EnumSet.of(
346+
java.nio.file.attribute.PosixFilePermission.OWNER_READ,
347+
java.nio.file.attribute.PosixFilePermission.OWNER_WRITE),
348+
perms);
349+
}
350+
}

0 commit comments

Comments
 (0)