Skip to content

Commit 2f50d6f

Browse files
adding Test
1 parent c8e5b76 commit 2f50d6f

File tree

4 files changed

+176
-44
lines changed

4 files changed

+176
-44
lines changed

src/main/java/dev/toonformat/jtoon/normalizer/JsonNormalizer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dev.toonformat.jtoon.normalizer;
22

33
import dev.toonformat.jtoon.util.ObjectMapperSingleton;
4+
import tools.jackson.core.JacksonException;
45
import tools.jackson.databind.JsonNode;
56
import tools.jackson.databind.ObjectMapper;
67
import tools.jackson.databind.node.ArrayNode;
@@ -281,7 +282,7 @@ private static ObjectNode normalizeMap(Map<?, ?> map) {
281282
private static JsonNode tryNormalizePojo(Object value) {
282283
try {
283284
return MAPPER.valueToTree(value);
284-
} catch (IllegalArgumentException e) {
285+
} catch (Exception e) {
285286
return NullNode.getInstance();
286287
}
287288
}

src/test/java/dev/toonformat/jtoon/decoder/PrimitiveDecoderTest.java

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package dev.toonformat.jtoon.decoder;
22

3+
import dev.toonformat.jtoon.encoder.PrimitiveEncoder;
34
import org.junit.jupiter.api.DisplayName;
45
import org.junit.jupiter.api.Tag;
56
import org.junit.jupiter.api.Test;
67

78
import java.lang.reflect.Constructor;
89
import java.lang.reflect.InvocationTargetException;
10+
import java.lang.reflect.Method;
911

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

@@ -19,7 +21,7 @@ class PrimitiveDecoderTest {
1921
@Test
2022
@DisplayName("throws unsupported Operation Exception for calling the constructor")
2123
void throwsOnConstructor() throws NoSuchMethodException {
22-
final Constructor<PrimitiveDecoder> constructor = PrimitiveDecoder.class.getDeclaredConstructor();
24+
final Constructor<PrimitiveEncoder> constructor = PrimitiveEncoder.class.getDeclaredConstructor();
2325
constructor.setAccessible(true);
2426

2527
final InvocationTargetException thrown =
@@ -258,7 +260,7 @@ void givenMaxLongNumber_whenParse_thenReturnsLong() {
258260
@Test
259261
void givenSmallerMinLongNumber_whenParse_thenReturnsLong() {
260262
// Given
261-
String input = String.valueOf(Long.MIN_VALUE -1);
263+
String input = String.valueOf(Long.MIN_VALUE - 1);
262264

263265
// When
264266
Object result = PrimitiveDecoder.parse(input);
@@ -271,7 +273,7 @@ void givenSmallerMinLongNumber_whenParse_thenReturnsLong() {
271273
@Test
272274
void givenBiggerMaxLongNumber_whenParse_thenReturnsLong() {
273275
// Given
274-
String input = String.valueOf(Long.MAX_VALUE +1);
276+
String input = String.valueOf(Long.MAX_VALUE + 1);
275277

276278
// When
277279
Object result = PrimitiveDecoder.parse(input);
@@ -293,4 +295,37 @@ void givenInvalidNumber_whenParse_thenReturnsOriginalString() {
293295
// Then
294296
assertEquals("123abc", result);
295297
}
298+
299+
@Test
300+
void testing_SkipTrailingZeros() throws Exception {
301+
// Given
302+
String input = "10.000";
303+
304+
// When
305+
String result = (String) invokePrivateStatic("stripTrailingZeros", new Class[]{String.class}, input);
306+
307+
// Then
308+
assertEquals("10", result);
309+
}
310+
311+
@Test
312+
void testing_SkipTrailingZeros_WithSmallNUmber() throws Exception {
313+
// Given
314+
String input = "1.0";
315+
316+
// When
317+
String result = (String) invokePrivateStatic("stripTrailingZeros", new Class[]{String.class}, input);
318+
319+
// Then
320+
assertEquals("1", result);
321+
}
322+
323+
324+
325+
// Reflection helpers for invoking private static methods
326+
private static Object invokePrivateStatic(String methodName, Class<?>[] paramTypes, Object... args) throws Exception {
327+
Method declaredMethod = PrimitiveEncoder.class.getDeclaredMethod(methodName, paramTypes);
328+
declaredMethod.setAccessible(true);
329+
return declaredMethod.invoke(null, args);
330+
}
296331
}

src/test/java/dev/toonformat/jtoon/normalizer/JsonNormalizerTest.java

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -905,9 +905,9 @@ void throwsOnConstructor() throws NoSuchMethodException {
905905

906906
// Reflection helpers for invoking private static methods
907907
private static Object invokePrivateStatic(String methodName, Class<?>[] paramTypes, Object... args) throws Exception {
908-
Method m = JsonNormalizer.class.getDeclaredMethod(methodName, paramTypes);
909-
m.setAccessible(true);
910-
return m.invoke(null, args);
908+
Method declaredMethod = JsonNormalizer.class.getDeclaredMethod(methodName, paramTypes);
909+
declaredMethod.setAccessible(true);
910+
return declaredMethod.invoke(null, args);
911911
}
912912

913913

@@ -1332,7 +1332,7 @@ void testLongMaxValueReturnsOptional_whenTryConvertToLong() throws Exception {
13321332
@DisplayName("Given Long Min Value, When tryConvertToLong is called, Then Optional is returned")
13331333
void testLongMinValueReturnsOptional_whenTryConvertToLong() throws Exception {
13341334
// Given
1335-
Double input = (double) Long.MIN_VALUE -1;
1335+
Double input = (double) Long.MIN_VALUE - 1;
13361336

13371337
// When
13381338
Object result = invokePrivateStatic("tryConvertToLong", new Class[]{Double.class}, input);
@@ -1346,7 +1346,7 @@ void testLongMinValueReturnsOptional_whenTryConvertToLong() throws Exception {
13461346
@DisplayName("Given Long Min Value, When tryConvertToLong is called, Then Optional is returned")
13471347
void testLongNormalizeBigInteger() throws Exception {
13481348
// Given
1349-
BigInteger input = BigInteger.valueOf(Long.MIN_VALUE -1);
1349+
BigInteger input = BigInteger.valueOf(Long.MIN_VALUE - 1);
13501350

13511351
// When
13521352
Object result = invokePrivateStatic("normalizeBigInteger", new Class[]{BigInteger.class}, input);
@@ -1483,7 +1483,7 @@ class NormalizeArray {
14831483

14841484
@Test
14851485
@DisplayName("Given Object, When normalizeArray is called, Then ArrayNode get return")
1486-
void givenException_whenTryNormalizePojo_thenNullNode() throws Exception {
1486+
void NormalizeArray_thenNullNode() throws Exception {
14871487
// Given
14881488
Object input = new Object();
14891489

@@ -1492,9 +1492,74 @@ void givenException_whenTryNormalizePojo_thenNullNode() throws Exception {
14921492

14931493
// Then
14941494
assertInstanceOf(ArrayNode.class, result);
1495+
}
1496+
}
1497+
1498+
@Nested
1499+
@DisplayName("NormalizePojo")
1500+
class NormalizePojo {
1501+
class ExplodingPojo {
1502+
public String getValue() {
1503+
throw new RuntimeException("Boom");
1504+
}
1505+
}
14951506

1507+
@Test
1508+
@DisplayName("Given Object, When tryNormalizePojo is called, Then ArrayNode get return")
1509+
void tryNormalizePojo_thenNullNode() throws Exception {
1510+
// Given
1511+
Object input = new Object();
1512+
1513+
// When
1514+
Object result = invokePrivateStatic("tryNormalizePojo", new Class[]{Object.class}, input);
14961515

1516+
// Then
1517+
assertInstanceOf(ObjectNode.class, result);
1518+
}
1519+
1520+
@Test
1521+
void returnsNullNodeWhenJacksonExceptionOccurs() throws Exception {
1522+
// Given
1523+
Object input = new ExplodingPojo();
1524+
//
1525+
Object result = invokePrivateStatic("tryNormalizePojo", new Class[]{Object.class}, input);
1526+
1527+
assertInstanceOf(NullNode.class, result);
14971528
}
14981529
}
1530+
1531+
@Nested
1532+
@DisplayName("parse")
1533+
class parse {
1534+
@Test
1535+
void parseNullAsString() {
1536+
// Given
1537+
String input = null;
1538+
1539+
// When
1540+
final IllegalArgumentException thrown =
1541+
assertThrows(IllegalArgumentException.class, () -> JsonNormalizer.parse(input));
1542+
1543+
1544+
// Then
1545+
assertEquals("Invalid JSON", thrown.getMessage());
1546+
}
1547+
1548+
1549+
@Test
1550+
void parseEmptyString() {
1551+
// Given
1552+
String input = " ";
1553+
1554+
// When
1555+
final IllegalArgumentException thrown =
1556+
assertThrows(IllegalArgumentException.class, () -> JsonNormalizer.parse(input));
1557+
1558+
1559+
// Then
1560+
assertEquals("Invalid JSON", thrown.getMessage());
1561+
}
1562+
1563+
}
14991564
}
15001565

src/test/java/dev/toonformat/jtoon/util/StringEscaperTest.java

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ class BasicEscaping {
2828

2929
static Stream<Arguments> basicEscapingCases() {
3030
return Stream.of(
31-
Arguments.of("backslashes", "path\\to\\file", "path\\\\to\\\\file"),
32-
Arguments.of("double quotes", "He said \"hello\"", "He said \\\"hello\\\""),
33-
Arguments.of("newlines", "line1\nline2", "line1\\nline2"),
34-
Arguments.of("carriage returns", "line1\rline2", "line1\\rline2"),
35-
Arguments.of("tabs", "col1\tcol2", "col1\\tcol2"));
31+
Arguments.of("backslashes", "path\\to\\file", "path\\\\to\\\\file"),
32+
Arguments.of("double quotes", "He said \"hello\"", "He said \\\"hello\\\""),
33+
Arguments.of("newlines", "line1\nline2", "line1\\nline2"),
34+
Arguments.of("carriage returns", "line1\rline2", "line1\\rline2"),
35+
Arguments.of("tabs", "col1\tcol2", "col1\\tcol2"));
3636
}
3737

3838
@ParameterizedTest(name = "should escape {0}")
@@ -49,10 +49,10 @@ class CombinedEscaping {
4949

5050
static Stream<Arguments> combinedEscapingCases() {
5151
return Stream.of(
52-
Arguments.of("multiple special characters", "He said \"test\\path\"\nNext line",
53-
"He said \\\"test\\\\path\\\"\\nNext line"),
54-
Arguments.of("all control characters together", "text\n\r\t", "text\\n\\r\\t"),
55-
Arguments.of("backslash before quote", "\\\"", "\\\\\\\""));
52+
Arguments.of("multiple special characters", "He said \"test\\path\"\nNext line",
53+
"He said \\\"test\\\\path\\\"\\nNext line"),
54+
Arguments.of("all control characters together", "text\n\r\t", "text\\n\\r\\t"),
55+
Arguments.of("backslash before quote", "\\\"", "\\\\\\\""));
5656
}
5757

5858
@ParameterizedTest(name = "should escape {0}")
@@ -76,9 +76,9 @@ void testEmptyString() {
7676
@ParameterizedTest
7777
@DisplayName("should not modify strings without special characters")
7878
@ValueSource(strings = {
79-
"hello world",
80-
"Hello World 123 @#$%^&*()_+-=[]{}|;:',.<>?/",
81-
"Hello 世界 🌍"
79+
"hello world",
80+
"Hello World 123 @#$%^&*()_+-=[]{}|;:',.<>?/",
81+
"Hello 世界 🌍"
8282
})
8383
void testStringsWithoutSpecialCharacters(String input) {
8484
assertEquals(input, StringEscaper.escape(input));
@@ -99,13 +99,13 @@ class RealWorldScenarios {
9999

100100
static Stream<Arguments> realWorldScenarios() {
101101
return Stream.of(
102-
Arguments.of("JSON string", "{\"key\": \"value\"}", "{\\\"key\\\": \\\"value\\\"}"),
103-
Arguments.of("Windows file path", "C:\\Users\\Documents\\file.txt",
104-
"C:\\\\Users\\\\Documents\\\\file.txt"),
105-
Arguments.of("multi-line text", "Line 1\nLine 2\nLine 3", "Line 1\\nLine 2\\nLine 3"),
106-
Arguments.of("SQL query", "SELECT * FROM users WHERE name = \"John\"",
107-
"SELECT * FROM users WHERE name = \\\"John\\\""),
108-
Arguments.of("regex pattern", "\\d+\\.\\d+", "\\\\d+\\\\.\\\\d+"));
102+
Arguments.of("JSON string", "{\"key\": \"value\"}", "{\\\"key\\\": \\\"value\\\"}"),
103+
Arguments.of("Windows file path", "C:\\Users\\Documents\\file.txt",
104+
"C:\\\\Users\\\\Documents\\\\file.txt"),
105+
Arguments.of("multi-line text", "Line 1\nLine 2\nLine 3", "Line 1\\nLine 2\\nLine 3"),
106+
Arguments.of("SQL query", "SELECT * FROM users WHERE name = \"John\"",
107+
"SELECT * FROM users WHERE name = \\\"John\\\""),
108+
Arguments.of("regex pattern", "\\d+\\.\\d+", "\\\\d+\\\\.\\\\d+"));
109109
}
110110

111111
@ParameterizedTest(name = "should escape {0}")
@@ -122,11 +122,11 @@ class BasicUnescaping {
122122

123123
static Stream<Arguments> basicUnescapingCases() {
124124
return Stream.of(
125-
Arguments.of("backslashes", "path\\\\to\\\\file", "path\\to\\file"),
126-
Arguments.of("double quotes", "He said \\\"hello\\\"", "He said \"hello\""),
127-
Arguments.of("newlines", "line1\\nline2", "line1\nline2"),
128-
Arguments.of("carriage returns", "line1\\rline2", "line1\rline2"),
129-
Arguments.of("tabs", "col1\\tcol2", "col1\tcol2"));
125+
Arguments.of("backslashes", "path\\\\to\\\\file", "path\\to\\file"),
126+
Arguments.of("double quotes", "He said \\\"hello\\\"", "He said \"hello\""),
127+
Arguments.of("newlines", "line1\\nline2", "line1\nline2"),
128+
Arguments.of("carriage returns", "line1\\rline2", "line1\rline2"),
129+
Arguments.of("tabs", "col1\\tcol2", "col1\tcol2"));
130130
}
131131

132132
@ParameterizedTest(name = "should unescape {0}")
@@ -172,13 +172,13 @@ class RoundTripEscaping {
172172

173173
static Stream<String> roundTripCases() {
174174
return Stream.of(
175-
"simple text",
176-
"path\\to\\file",
177-
"He said \"hello\"",
178-
"line1\nline2\nline3",
179-
"col1\tcol2\tcol3",
180-
"C:\\Users\\Documents",
181-
"text\n\r\t\"\\"
175+
"simple text",
176+
"path\\to\\file",
177+
"He said \"hello\"",
178+
"line1\nline2\nline3",
179+
"col1\tcol2\tcol3",
180+
"C:\\Users\\Documents",
181+
"text\n\r\t\"\\"
182182
);
183183
}
184184

@@ -230,6 +230,7 @@ void testUnknownEscapeSequences() {
230230
void unquotesValueWhenStartsAndEndsWithQuote() {
231231
assertEquals("abc", StringEscaper.unescape("\"abc\""));
232232
}
233+
233234
@Test
234235
void unescapesBackslashSequences() {
235236
assertEquals("a\"b", StringEscaper.unescape("a\\\"b"));
@@ -259,7 +260,7 @@ void throwsOnConstructor() throws NoSuchMethodException {
259260
constructor.setAccessible(true);
260261

261262
final InvocationTargetException thrown =
262-
assertThrows(InvocationTargetException.class, constructor::newInstance);
263+
assertThrows(InvocationTargetException.class, constructor::newInstance);
263264

264265
final Throwable cause = thrown.getCause();
265266
assertInstanceOf(UnsupportedOperationException.class, cause);
@@ -275,6 +276,7 @@ void testingValidateString_WithNull() {
275276
// Then
276277

277278
}
279+
278280
@Test
279281
void testingValidateString_WithEmptyString() {
280282
// Given
@@ -284,14 +286,43 @@ void testingValidateString_WithEmptyString() {
284286
// Then
285287

286288
}
289+
287290
@Test
288291
void testingValidateString_WithWildStringToThrowsException() {
289292
// Given
290293
String input = "\"te\\st\"";
291294
// When // Then
292-
assertThrows(IllegalArgumentException.class,
293-
()->{
295+
final IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
296+
() -> {
297+
StringEscaper.validateString(input);
298+
});
299+
300+
assertEquals("Invalid escape sequence: \\s", thrown.getMessage());
301+
}
302+
303+
@Test
304+
void testingValidateString_WithWildStringOnlyAtTheStartToThrowsException() {
305+
// Given
306+
String input = "\"te\\st";
307+
// When // Then
308+
final IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
309+
() -> {
310+
StringEscaper.validateString(input);
311+
});
312+
313+
assertEquals("Unterminated string", thrown.getMessage());
314+
}
315+
316+
@Test
317+
void testingValidateString_WithWildStringOnlyAtTheStartAndEndToThrowsException() {
318+
// Given
319+
String input = "\"abc\\\"";
320+
// When // Then
321+
final IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
322+
() -> {
294323
StringEscaper.validateString(input);
295324
});
325+
326+
assertEquals("Invalid escape sequence: trailing backslash", thrown.getMessage());
296327
}
297328
}

0 commit comments

Comments
 (0)