Skip to content

Commit

Permalink
Implemented test for JsonParser
Browse files Browse the repository at this point in the history
  • Loading branch information
JanHolger committed Mar 10, 2024
1 parent fc8db8b commit 64444aa
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 12 deletions.
25 changes: 13 additions & 12 deletions src/main/java/org/javawebstack/abstractdata/json/JsonParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
import org.javawebstack.abstractdata.*;

import java.text.ParseException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.*;

public class JsonParser {

Expand All @@ -19,7 +16,7 @@ public AbstractElement parse(String json) throws ParseException {
AbstractElement parsed;
try {
parsed = parse(stack);
} catch (NullPointerException ex) {
} catch (NoSuchElementException | NullPointerException ex) {
throw new ParseException("Unexpected character <EOF>", primChars.length);
}
if (parsed == null) {
Expand All @@ -28,11 +25,11 @@ public AbstractElement parse(String json) throws ParseException {
for (int i = 0; i < primChars.length - stack.size(); i++) {
if (primChars[i] == '\n') {
line++;
pos = 1;
pos = 0;
}
pos++;
}
throw new ParseException("Unexpected character '" + stack.pop() + "' at line " + line + " pos " + pos, primChars.length - stack.size());
throw new ParseException("Unexpected character '" + stack.pop() + "' at line " + line + " pos " + pos, primChars.length - stack.size() - 1);
}
return parsed;
}
Expand Down Expand Up @@ -114,7 +111,7 @@ private void popWhitespace(Deque<Character> stack) {

private AbstractPrimitive parseNumber(Deque<Character> stack) {
StringBuilder sb = new StringBuilder();
while (Character.isDigit(stack.peek()) || stack.peek() == '.' || stack.peek() == '-' || stack.peek() == 'E' || stack.peek() == 'e')
while (stack.peek() != null && (Character.isDigit(stack.peek()) || stack.peek() == '.' || stack.peek() == '+' || stack.peek() == '-' || stack.peek() == 'E' || stack.peek() == 'e'))
sb.append(stack.pop());
String s = sb.toString();
if (s.contains(".")) {
Expand Down Expand Up @@ -181,8 +178,6 @@ private AbstractObject parseObject(Deque<Character> stack) {
break;
}
AbstractPrimitive key = parseString(stack);
if (key == null)
return null;
popWhitespace(stack);
if (stack.peek() != ':')
return null;
Expand All @@ -193,8 +188,11 @@ private AbstractObject parseObject(Deque<Character> stack) {
return null;
object.set(key.string(), value);
popWhitespace(stack);
if (stack.peek() == ',')
if (stack.peek() == ',') {
stack.pop();
} else if(stack.peek() != '}') {
return null;
}
}
return object;
}
Expand All @@ -213,8 +211,11 @@ private AbstractArray parseArray(Deque<Character> stack) {
return null;
array.add(value);
popWhitespace(stack);
if (stack.peek() == ',')
if (stack.peek() == ',') {
stack.pop();
} else if(stack.peek() != ']') {
return null;
}
}
return array;
}
Expand Down
169 changes: 169 additions & 0 deletions src/test/java/org/javawebstack/abstractdata/json/JsonParserTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package org.javawebstack.abstractdata.json;

import org.javawebstack.abstractdata.AbstractElement;
import org.javawebstack.abstractdata.AbstractPrimitive;
import org.junit.jupiter.api.Test;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

public class JsonParserTest {

@Test
public void testParseEmptyString() {
ParseException e = assertThrows(ParseException.class, () -> new JsonParser().parse(""));
assertEquals("Unexpected character <EOF>", e.getMessage());
}

@Test
public void testParseUnexpectedEOF() {
ParseException e = assertThrows(ParseException.class, () -> new JsonParser().parse("{"));
assertEquals("Unexpected character <EOF>", e.getMessage());
e = assertThrows(ParseException.class, () -> new JsonParser().parse("["));
assertEquals("Unexpected character <EOF>", e.getMessage());
e = assertThrows(ParseException.class, () -> new JsonParser().parse("\""));
assertEquals("Unexpected character <EOF>", e.getMessage());
e = assertThrows(ParseException.class, () -> new JsonParser().parse("t"));
assertEquals("Unexpected character <EOF>", e.getMessage());
}

@Test
public void testParseUnexpectedCharacter() {
ParseException e = assertThrows(ParseException.class, () -> new JsonParser().parse("{\n \"abc\":x\n}"));
assertEquals("Unexpected character 'x' at line 2 pos 11", e.getMessage());
assertEquals(12, e.getErrorOffset());
}

@Test
public void testParseBooleanTrue() {
AbstractElement trueElement = assertDoesNotThrow(() -> new JsonParser().parse("true"));
assertTrue(trueElement.isBoolean());
assertTrue(trueElement.bool());
assertThrows(ParseException.class, () -> new JsonParser().parse("trux"));
assertThrows(ParseException.class, () -> new JsonParser().parse("trxx"));
assertThrows(ParseException.class, () -> new JsonParser().parse("txxx"));
}

@Test
public void testParseBooleanFalse() {
AbstractElement falseElement = assertDoesNotThrow(() -> new JsonParser().parse("false"));
assertTrue(falseElement.isBoolean());
assertFalse(falseElement.bool());
assertThrows(ParseException.class, () -> new JsonParser().parse("falsx"));
assertThrows(ParseException.class, () -> new JsonParser().parse("falxx"));
assertThrows(ParseException.class, () -> new JsonParser().parse("faxxx"));
assertThrows(ParseException.class, () -> new JsonParser().parse("fxxxx"));
}

@Test
public void testParseBooleanNull() {
AbstractElement nullElement = assertDoesNotThrow(() -> new JsonParser().parse("null"));
assertTrue(nullElement.isNull());
assertThrows(ParseException.class, () -> new JsonParser().parse("nulx"));
assertThrows(ParseException.class, () -> new JsonParser().parse("nuxx"));
assertThrows(ParseException.class, () -> new JsonParser().parse("nxxx"));
}

@Test
public void testParseInteger() {
AbstractElement e = assertDoesNotThrow(() -> new JsonParser().parse("123"));
assertTrue(e.isNumber());
assertEquals(123, e.number());
}

@Test
public void testParseLong() {
long expected = 1L + Integer.MAX_VALUE;
AbstractElement e = assertDoesNotThrow(() -> new JsonParser().parse(String.valueOf(expected)));
assertTrue(e.isNumber());
assertEquals(expected, e.number());
}

@Test
public void testParseDouble() {
AbstractElement e = assertDoesNotThrow(() -> new JsonParser().parse("123.456"));
assertTrue(e.isNumber());
assertEquals(123.456, e.number());
}

@Test
public void testParseStringEscapeSeq() {
Map<String, String> escapes = new HashMap<>();
escapes.put("\\\"", "\"");
escapes.put("\\\\", "\\");
escapes.put("\\b", "\b");
escapes.put("\\f", "\f");
escapes.put("\\n", "\n");
escapes.put("\\r", "\r");
escapes.put("\\t", "\t");
escapes.put("\\0", "\0");
escapes.put("\\/", "/");
for(String c : escapes.keySet()) {
AbstractElement e = assertDoesNotThrow(() -> new JsonParser().parse("\"" + c + "\""));
assertTrue(e.isString());
assertEquals(escapes.get(c), e.string());
}
}

@Test
public void testParseStringUnicode() {
AbstractElement e = assertDoesNotThrow(() -> new JsonParser().parse("\"\\u001F\""));
assertTrue(e.isString());
assertEquals("\u001F", e.string());
}

@Test
public void testParseValidObject() {
AbstractElement e = assertDoesNotThrow(() -> new JsonParser().parse("{\"a\":1,\"b\":2}"));
assertTrue(e.isObject());
assertEquals(2, e.object().size());
List<String> keys = new ArrayList<>(e.object().keys());
assertEquals("a", keys.get(0));
assertEquals("b", keys.get(1));
AbstractElement aElement = e.object().get("a");
assertTrue(aElement.isNumber());
assertEquals(1, aElement.number());
AbstractElement bElement = e.object().get("b");
assertTrue(bElement.isNumber());
assertEquals(2, bElement.number());
}

@Test
public void testParseInvalidObjectWithMissingColon() {
assertThrows(ParseException.class, () -> new JsonParser().parse("{\"a\"1}"));
}

@Test
public void testParseInvalidObjectWithMissingComma() {
assertThrows(ParseException.class, () -> new JsonParser().parse("{\"a\":1\"b\":2}"));
}

@Test
public void testParseValidArray() {
AbstractElement e = assertDoesNotThrow(() -> new JsonParser().parse("[1,2]"));
assertTrue(e.isArray());
assertEquals(2, e.array().size());
AbstractElement firstElement = e.array().get(0);
assertTrue(firstElement.isNumber());
assertEquals(1, firstElement.number());
AbstractElement secondElement = e.array().get(1);
assertTrue(secondElement.isNumber());
assertEquals(2, secondElement.number());
}

@Test
public void testParseInvalidArrayWithInvalidValue() {
assertThrows(ParseException.class, () -> new JsonParser().parse("[talse]"));
}

@Test
public void testParseInvalidArrayWithMissingComma() {
assertThrows(ParseException.class, () -> new JsonParser().parse("[\"a\"\"b\"]"));
}

}

0 comments on commit 64444aa

Please sign in to comment.