Skip to content

Commit 64444aa

Browse files
committed
Implemented test for JsonParser
1 parent fc8db8b commit 64444aa

File tree

2 files changed

+182
-12
lines changed

2 files changed

+182
-12
lines changed

src/main/java/org/javawebstack/abstractdata/json/JsonParser.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@
33
import org.javawebstack.abstractdata.*;
44

55
import java.text.ParseException;
6-
import java.util.ArrayDeque;
7-
import java.util.ArrayList;
8-
import java.util.Deque;
9-
import java.util.List;
6+
import java.util.*;
107

118
public class JsonParser {
129

@@ -19,7 +16,7 @@ public AbstractElement parse(String json) throws ParseException {
1916
AbstractElement parsed;
2017
try {
2118
parsed = parse(stack);
22-
} catch (NullPointerException ex) {
19+
} catch (NoSuchElementException | NullPointerException ex) {
2320
throw new ParseException("Unexpected character <EOF>", primChars.length);
2421
}
2522
if (parsed == null) {
@@ -28,11 +25,11 @@ public AbstractElement parse(String json) throws ParseException {
2825
for (int i = 0; i < primChars.length - stack.size(); i++) {
2926
if (primChars[i] == '\n') {
3027
line++;
31-
pos = 1;
28+
pos = 0;
3229
}
3330
pos++;
3431
}
35-
throw new ParseException("Unexpected character '" + stack.pop() + "' at line " + line + " pos " + pos, primChars.length - stack.size());
32+
throw new ParseException("Unexpected character '" + stack.pop() + "' at line " + line + " pos " + pos, primChars.length - stack.size() - 1);
3633
}
3734
return parsed;
3835
}
@@ -114,7 +111,7 @@ private void popWhitespace(Deque<Character> stack) {
114111

115112
private AbstractPrimitive parseNumber(Deque<Character> stack) {
116113
StringBuilder sb = new StringBuilder();
117-
while (Character.isDigit(stack.peek()) || stack.peek() == '.' || stack.peek() == '-' || stack.peek() == 'E' || stack.peek() == 'e')
114+
while (stack.peek() != null && (Character.isDigit(stack.peek()) || stack.peek() == '.' || stack.peek() == '+' || stack.peek() == '-' || stack.peek() == 'E' || stack.peek() == 'e'))
118115
sb.append(stack.pop());
119116
String s = sb.toString();
120117
if (s.contains(".")) {
@@ -181,8 +178,6 @@ private AbstractObject parseObject(Deque<Character> stack) {
181178
break;
182179
}
183180
AbstractPrimitive key = parseString(stack);
184-
if (key == null)
185-
return null;
186181
popWhitespace(stack);
187182
if (stack.peek() != ':')
188183
return null;
@@ -193,8 +188,11 @@ private AbstractObject parseObject(Deque<Character> stack) {
193188
return null;
194189
object.set(key.string(), value);
195190
popWhitespace(stack);
196-
if (stack.peek() == ',')
191+
if (stack.peek() == ',') {
197192
stack.pop();
193+
} else if(stack.peek() != '}') {
194+
return null;
195+
}
198196
}
199197
return object;
200198
}
@@ -213,8 +211,11 @@ private AbstractArray parseArray(Deque<Character> stack) {
213211
return null;
214212
array.add(value);
215213
popWhitespace(stack);
216-
if (stack.peek() == ',')
214+
if (stack.peek() == ',') {
217215
stack.pop();
216+
} else if(stack.peek() != ']') {
217+
return null;
218+
}
218219
}
219220
return array;
220221
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package org.javawebstack.abstractdata.json;
2+
3+
import org.javawebstack.abstractdata.AbstractElement;
4+
import org.javawebstack.abstractdata.AbstractPrimitive;
5+
import org.junit.jupiter.api.Test;
6+
7+
import java.text.ParseException;
8+
import java.util.ArrayList;
9+
import java.util.HashMap;
10+
import java.util.List;
11+
import java.util.Map;
12+
13+
import static org.junit.jupiter.api.Assertions.*;
14+
15+
public class JsonParserTest {
16+
17+
@Test
18+
public void testParseEmptyString() {
19+
ParseException e = assertThrows(ParseException.class, () -> new JsonParser().parse(""));
20+
assertEquals("Unexpected character <EOF>", e.getMessage());
21+
}
22+
23+
@Test
24+
public void testParseUnexpectedEOF() {
25+
ParseException e = assertThrows(ParseException.class, () -> new JsonParser().parse("{"));
26+
assertEquals("Unexpected character <EOF>", e.getMessage());
27+
e = assertThrows(ParseException.class, () -> new JsonParser().parse("["));
28+
assertEquals("Unexpected character <EOF>", e.getMessage());
29+
e = assertThrows(ParseException.class, () -> new JsonParser().parse("\""));
30+
assertEquals("Unexpected character <EOF>", e.getMessage());
31+
e = assertThrows(ParseException.class, () -> new JsonParser().parse("t"));
32+
assertEquals("Unexpected character <EOF>", e.getMessage());
33+
}
34+
35+
@Test
36+
public void testParseUnexpectedCharacter() {
37+
ParseException e = assertThrows(ParseException.class, () -> new JsonParser().parse("{\n \"abc\":x\n}"));
38+
assertEquals("Unexpected character 'x' at line 2 pos 11", e.getMessage());
39+
assertEquals(12, e.getErrorOffset());
40+
}
41+
42+
@Test
43+
public void testParseBooleanTrue() {
44+
AbstractElement trueElement = assertDoesNotThrow(() -> new JsonParser().parse("true"));
45+
assertTrue(trueElement.isBoolean());
46+
assertTrue(trueElement.bool());
47+
assertThrows(ParseException.class, () -> new JsonParser().parse("trux"));
48+
assertThrows(ParseException.class, () -> new JsonParser().parse("trxx"));
49+
assertThrows(ParseException.class, () -> new JsonParser().parse("txxx"));
50+
}
51+
52+
@Test
53+
public void testParseBooleanFalse() {
54+
AbstractElement falseElement = assertDoesNotThrow(() -> new JsonParser().parse("false"));
55+
assertTrue(falseElement.isBoolean());
56+
assertFalse(falseElement.bool());
57+
assertThrows(ParseException.class, () -> new JsonParser().parse("falsx"));
58+
assertThrows(ParseException.class, () -> new JsonParser().parse("falxx"));
59+
assertThrows(ParseException.class, () -> new JsonParser().parse("faxxx"));
60+
assertThrows(ParseException.class, () -> new JsonParser().parse("fxxxx"));
61+
}
62+
63+
@Test
64+
public void testParseBooleanNull() {
65+
AbstractElement nullElement = assertDoesNotThrow(() -> new JsonParser().parse("null"));
66+
assertTrue(nullElement.isNull());
67+
assertThrows(ParseException.class, () -> new JsonParser().parse("nulx"));
68+
assertThrows(ParseException.class, () -> new JsonParser().parse("nuxx"));
69+
assertThrows(ParseException.class, () -> new JsonParser().parse("nxxx"));
70+
}
71+
72+
@Test
73+
public void testParseInteger() {
74+
AbstractElement e = assertDoesNotThrow(() -> new JsonParser().parse("123"));
75+
assertTrue(e.isNumber());
76+
assertEquals(123, e.number());
77+
}
78+
79+
@Test
80+
public void testParseLong() {
81+
long expected = 1L + Integer.MAX_VALUE;
82+
AbstractElement e = assertDoesNotThrow(() -> new JsonParser().parse(String.valueOf(expected)));
83+
assertTrue(e.isNumber());
84+
assertEquals(expected, e.number());
85+
}
86+
87+
@Test
88+
public void testParseDouble() {
89+
AbstractElement e = assertDoesNotThrow(() -> new JsonParser().parse("123.456"));
90+
assertTrue(e.isNumber());
91+
assertEquals(123.456, e.number());
92+
}
93+
94+
@Test
95+
public void testParseStringEscapeSeq() {
96+
Map<String, String> escapes = new HashMap<>();
97+
escapes.put("\\\"", "\"");
98+
escapes.put("\\\\", "\\");
99+
escapes.put("\\b", "\b");
100+
escapes.put("\\f", "\f");
101+
escapes.put("\\n", "\n");
102+
escapes.put("\\r", "\r");
103+
escapes.put("\\t", "\t");
104+
escapes.put("\\0", "\0");
105+
escapes.put("\\/", "/");
106+
for(String c : escapes.keySet()) {
107+
AbstractElement e = assertDoesNotThrow(() -> new JsonParser().parse("\"" + c + "\""));
108+
assertTrue(e.isString());
109+
assertEquals(escapes.get(c), e.string());
110+
}
111+
}
112+
113+
@Test
114+
public void testParseStringUnicode() {
115+
AbstractElement e = assertDoesNotThrow(() -> new JsonParser().parse("\"\\u001F\""));
116+
assertTrue(e.isString());
117+
assertEquals("\u001F", e.string());
118+
}
119+
120+
@Test
121+
public void testParseValidObject() {
122+
AbstractElement e = assertDoesNotThrow(() -> new JsonParser().parse("{\"a\":1,\"b\":2}"));
123+
assertTrue(e.isObject());
124+
assertEquals(2, e.object().size());
125+
List<String> keys = new ArrayList<>(e.object().keys());
126+
assertEquals("a", keys.get(0));
127+
assertEquals("b", keys.get(1));
128+
AbstractElement aElement = e.object().get("a");
129+
assertTrue(aElement.isNumber());
130+
assertEquals(1, aElement.number());
131+
AbstractElement bElement = e.object().get("b");
132+
assertTrue(bElement.isNumber());
133+
assertEquals(2, bElement.number());
134+
}
135+
136+
@Test
137+
public void testParseInvalidObjectWithMissingColon() {
138+
assertThrows(ParseException.class, () -> new JsonParser().parse("{\"a\"1}"));
139+
}
140+
141+
@Test
142+
public void testParseInvalidObjectWithMissingComma() {
143+
assertThrows(ParseException.class, () -> new JsonParser().parse("{\"a\":1\"b\":2}"));
144+
}
145+
146+
@Test
147+
public void testParseValidArray() {
148+
AbstractElement e = assertDoesNotThrow(() -> new JsonParser().parse("[1,2]"));
149+
assertTrue(e.isArray());
150+
assertEquals(2, e.array().size());
151+
AbstractElement firstElement = e.array().get(0);
152+
assertTrue(firstElement.isNumber());
153+
assertEquals(1, firstElement.number());
154+
AbstractElement secondElement = e.array().get(1);
155+
assertTrue(secondElement.isNumber());
156+
assertEquals(2, secondElement.number());
157+
}
158+
159+
@Test
160+
public void testParseInvalidArrayWithInvalidValue() {
161+
assertThrows(ParseException.class, () -> new JsonParser().parse("[talse]"));
162+
}
163+
164+
@Test
165+
public void testParseInvalidArrayWithMissingComma() {
166+
assertThrows(ParseException.class, () -> new JsonParser().parse("[\"a\"\"b\"]"));
167+
}
168+
169+
}

0 commit comments

Comments
 (0)