Testing JSON Path Tracking Implementation in google/gson
This test suite validates the JSON path tracking functionality in the GSON library’s JsonReader implementation. It ensures accurate path reporting during JSON parsing operations, covering both string-based and object-based reader implementations.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
google/gson
gson/src/test/java/com/google/gson/stream/JsonReaderPathTest.java
/*
* Copyright (C) 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.gson.stream;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assume.assumeTrue;
import com.google.gson.JsonElement;
import com.google.gson.Strictness;
import com.google.gson.internal.Streams;
import com.google.gson.internal.bind.JsonTreeReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@SuppressWarnings("resource")
@RunWith(Parameterized.class)
public class JsonReaderPathTest {
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> parameters() {
return Arrays.asList(
new Object[] {Factory.STRING_READER}, new Object[] {Factory.OBJECT_READER});
}
@Parameterized.Parameter public Factory factory;
@Test
public void path() throws IOException {
JsonReader reader = factory.create("{\"a\":[2,true,false,null,\"b\",{\"c\":\"d\"},[3]]}");
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
reader.beginObject();
assertThat(reader.getPreviousPath()).isEqualTo("$.");
assertThat(reader.getPath()).isEqualTo("$.");
String unused1 = reader.nextName();
assertThat(reader.getPreviousPath()).isEqualTo("$.a");
assertThat(reader.getPath()).isEqualTo("$.a");
reader.beginArray();
assertThat(reader.getPreviousPath()).isEqualTo("$.a[0]");
assertThat(reader.getPath()).isEqualTo("$.a[0]");
int unused2 = reader.nextInt();
assertThat(reader.getPreviousPath()).isEqualTo("$.a[0]");
assertThat(reader.getPath()).isEqualTo("$.a[1]");
boolean unused3 = reader.nextBoolean();
assertThat(reader.getPreviousPath()).isEqualTo("$.a[1]");
assertThat(reader.getPath()).isEqualTo("$.a[2]");
boolean unused4 = reader.nextBoolean();
assertThat(reader.getPreviousPath()).isEqualTo("$.a[2]");
assertThat(reader.getPath()).isEqualTo("$.a[3]");
reader.nextNull();
assertThat(reader.getPreviousPath()).isEqualTo("$.a[3]");
assertThat(reader.getPath()).isEqualTo("$.a[4]");
String unused5 = reader.nextString();
assertThat(reader.getPreviousPath()).isEqualTo("$.a[4]");
assertThat(reader.getPath()).isEqualTo("$.a[5]");
reader.beginObject();
assertThat(reader.getPreviousPath()).isEqualTo("$.a[5].");
assertThat(reader.getPath()).isEqualTo("$.a[5].");
String unused6 = reader.nextName();
assertThat(reader.getPreviousPath()).isEqualTo("$.a[5].c");
assertThat(reader.getPath()).isEqualTo("$.a[5].c");
String unused7 = reader.nextString();
assertThat(reader.getPreviousPath()).isEqualTo("$.a[5].c");
assertThat(reader.getPath()).isEqualTo("$.a[5].c");
reader.endObject();
assertThat(reader.getPreviousPath()).isEqualTo("$.a[5]");
assertThat(reader.getPath()).isEqualTo("$.a[6]");
reader.beginArray();
assertThat(reader.getPreviousPath()).isEqualTo("$.a[6][0]");
assertThat(reader.getPath()).isEqualTo("$.a[6][0]");
int unused8 = reader.nextInt();
assertThat(reader.getPreviousPath()).isEqualTo("$.a[6][0]");
assertThat(reader.getPath()).isEqualTo("$.a[6][1]");
reader.endArray();
assertThat(reader.getPreviousPath()).isEqualTo("$.a[6]");
assertThat(reader.getPath()).isEqualTo("$.a[7]");
reader.endArray();
assertThat(reader.getPreviousPath()).isEqualTo("$.a");
assertThat(reader.getPath()).isEqualTo("$.a");
reader.endObject();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
}
@Test
public void objectPath() throws IOException {
JsonReader reader = factory.create("{\"a\":1,\"b\":2}");
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
JsonToken unused1 = reader.peek();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
reader.beginObject();
assertThat(reader.getPreviousPath()).isEqualTo("$.");
assertThat(reader.getPath()).isEqualTo("$.");
JsonToken unused2 = reader.peek();
assertThat(reader.getPreviousPath()).isEqualTo("$.");
assertThat(reader.getPath()).isEqualTo("$.");
String unused3 = reader.nextName();
assertThat(reader.getPreviousPath()).isEqualTo("$.a");
assertThat(reader.getPath()).isEqualTo("$.a");
JsonToken unused4 = reader.peek();
assertThat(reader.getPreviousPath()).isEqualTo("$.a");
assertThat(reader.getPath()).isEqualTo("$.a");
int unused5 = reader.nextInt();
assertThat(reader.getPreviousPath()).isEqualTo("$.a");
assertThat(reader.getPath()).isEqualTo("$.a");
JsonToken unused6 = reader.peek();
assertThat(reader.getPreviousPath()).isEqualTo("$.a");
assertThat(reader.getPath()).isEqualTo("$.a");
String unused7 = reader.nextName();
assertThat(reader.getPreviousPath()).isEqualTo("$.b");
assertThat(reader.getPath()).isEqualTo("$.b");
JsonToken unused8 = reader.peek();
assertThat(reader.getPreviousPath()).isEqualTo("$.b");
assertThat(reader.getPath()).isEqualTo("$.b");
int unused9 = reader.nextInt();
assertThat(reader.getPreviousPath()).isEqualTo("$.b");
assertThat(reader.getPath()).isEqualTo("$.b");
JsonToken unused10 = reader.peek();
assertThat(reader.getPreviousPath()).isEqualTo("$.b");
assertThat(reader.getPath()).isEqualTo("$.b");
reader.endObject();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
JsonToken unused11 = reader.peek();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
reader.close();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
}
@Test
public void arrayPath() throws IOException {
JsonReader reader = factory.create("[1,2]");
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
JsonToken unused1 = reader.peek();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
reader.beginArray();
assertThat(reader.getPreviousPath()).isEqualTo("$[0]");
assertThat(reader.getPath()).isEqualTo("$[0]");
JsonToken unused2 = reader.peek();
assertThat(reader.getPreviousPath()).isEqualTo("$[0]");
assertThat(reader.getPath()).isEqualTo("$[0]");
int unused3 = reader.nextInt();
assertThat(reader.getPreviousPath()).isEqualTo("$[0]");
assertThat(reader.getPath()).isEqualTo("$[1]");
JsonToken unused4 = reader.peek();
assertThat(reader.getPreviousPath()).isEqualTo("$[0]");
assertThat(reader.getPath()).isEqualTo("$[1]");
int unused5 = reader.nextInt();
assertThat(reader.getPreviousPath()).isEqualTo("$[1]");
assertThat(reader.getPath()).isEqualTo("$[2]");
JsonToken unused6 = reader.peek();
assertThat(reader.getPreviousPath()).isEqualTo("$[1]");
assertThat(reader.getPath()).isEqualTo("$[2]");
reader.endArray();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
JsonToken unused7 = reader.peek();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
reader.close();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
}
@Test
public void multipleTopLevelValuesInOneDocument() throws IOException {
assumeTrue(factory == Factory.STRING_READER);
JsonReader reader = factory.create("[][]");
reader.setStrictness(Strictness.LENIENT);
reader.beginArray();
reader.endArray();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
reader.beginArray();
reader.endArray();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
}
@Test
public void skipArrayElements() throws IOException {
JsonReader reader = factory.create("[1,2,3]");
reader.beginArray();
reader.skipValue();
reader.skipValue();
assertThat(reader.getPreviousPath()).isEqualTo("$[1]");
assertThat(reader.getPath()).isEqualTo("$[2]");
}
@Test
public void skipArrayEnd() throws IOException {
JsonReader reader = factory.create("[[],1]");
reader.beginArray();
reader.beginArray();
assertThat(reader.getPreviousPath()).isEqualTo("$[0][0]");
assertThat(reader.getPath()).isEqualTo("$[0][0]");
reader.skipValue(); // skip end of array
assertThat(reader.getPreviousPath()).isEqualTo("$[0]");
assertThat(reader.getPath()).isEqualTo("$[1]");
}
@Test
public void skipObjectNames() throws IOException {
JsonReader reader = factory.create("{\"a\":[]}");
reader.beginObject();
reader.skipValue();
assertThat(reader.getPreviousPath()).isEqualTo("$.<skipped>");
assertThat(reader.getPath()).isEqualTo("$.<skipped>");
reader.beginArray();
assertThat(reader.getPreviousPath()).isEqualTo("$.<skipped>[0]");
assertThat(reader.getPath()).isEqualTo("$.<skipped>[0]");
}
@Test
public void skipObjectValues() throws IOException {
JsonReader reader = factory.create("{\"a\":1,\"b\":2}");
reader.beginObject();
assertThat(reader.getPreviousPath()).isEqualTo("$.");
assertThat(reader.getPath()).isEqualTo("$.");
String unused1 = reader.nextName();
reader.skipValue();
assertThat(reader.getPreviousPath()).isEqualTo("$.a");
assertThat(reader.getPath()).isEqualTo("$.a");
String unused2 = reader.nextName();
assertThat(reader.getPreviousPath()).isEqualTo("$.b");
assertThat(reader.getPath()).isEqualTo("$.b");
}
@Test
public void skipObjectEnd() throws IOException {
JsonReader reader = factory.create("{\"a\":{},\"b\":2}");
reader.beginObject();
String unused = reader.nextName();
reader.beginObject();
assertThat(reader.getPreviousPath()).isEqualTo("$.a.");
assertThat(reader.getPath()).isEqualTo("$.a.");
reader.skipValue(); // skip end of object
assertThat(reader.getPreviousPath()).isEqualTo("$.a");
assertThat(reader.getPath()).isEqualTo("$.a");
}
@Test
public void skipNestedStructures() throws IOException {
JsonReader reader = factory.create("[[1,2,3],4]");
reader.beginArray();
reader.skipValue();
assertThat(reader.getPreviousPath()).isEqualTo("$[0]");
assertThat(reader.getPath()).isEqualTo("$[1]");
}
@Test
public void skipEndOfDocument() throws IOException {
JsonReader reader = factory.create("[]");
reader.beginArray();
reader.endArray();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
reader.skipValue();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
reader.skipValue();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
}
@Test
public void arrayOfObjects() throws IOException {
JsonReader reader = factory.create("[{},{},{}]");
reader.beginArray();
assertThat(reader.getPreviousPath()).isEqualTo("$[0]");
assertThat(reader.getPath()).isEqualTo("$[0]");
reader.beginObject();
assertThat(reader.getPreviousPath()).isEqualTo("$[0].");
assertThat(reader.getPath()).isEqualTo("$[0].");
reader.endObject();
assertThat(reader.getPreviousPath()).isEqualTo("$[0]");
assertThat(reader.getPath()).isEqualTo("$[1]");
reader.beginObject();
assertThat(reader.getPreviousPath()).isEqualTo("$[1].");
assertThat(reader.getPath()).isEqualTo("$[1].");
reader.endObject();
assertThat(reader.getPreviousPath()).isEqualTo("$[1]");
assertThat(reader.getPath()).isEqualTo("$[2]");
reader.beginObject();
assertThat(reader.getPreviousPath()).isEqualTo("$[2].");
assertThat(reader.getPath()).isEqualTo("$[2].");
reader.endObject();
assertThat(reader.getPreviousPath()).isEqualTo("$[2]");
assertThat(reader.getPath()).isEqualTo("$[3]");
reader.endArray();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
}
@Test
public void arrayOfArrays() throws IOException {
JsonReader reader = factory.create("[[],[],[]]");
reader.beginArray();
assertThat(reader.getPreviousPath()).isEqualTo("$[0]");
assertThat(reader.getPath()).isEqualTo("$[0]");
reader.beginArray();
assertThat(reader.getPreviousPath()).isEqualTo("$[0][0]");
assertThat(reader.getPath()).isEqualTo("$[0][0]");
reader.endArray();
assertThat(reader.getPreviousPath()).isEqualTo("$[0]");
assertThat(reader.getPath()).isEqualTo("$[1]");
reader.beginArray();
assertThat(reader.getPreviousPath()).isEqualTo("$[1][0]");
assertThat(reader.getPath()).isEqualTo("$[1][0]");
reader.endArray();
assertThat(reader.getPreviousPath()).isEqualTo("$[1]");
assertThat(reader.getPath()).isEqualTo("$[2]");
reader.beginArray();
assertThat(reader.getPreviousPath()).isEqualTo("$[2][0]");
assertThat(reader.getPath()).isEqualTo("$[2][0]");
reader.endArray();
assertThat(reader.getPreviousPath()).isEqualTo("$[2]");
assertThat(reader.getPath()).isEqualTo("$[3]");
reader.endArray();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
}
@Test
public void objectOfObjects() throws IOException {
JsonReader reader = factory.create("{\"a\":{\"a1\":1,\"a2\":2},\"b\":{\"b1\":1}}");
reader.beginObject();
assertThat(reader.getPreviousPath()).isEqualTo("$.");
assertThat(reader.getPath()).isEqualTo("$.");
String unused1 = reader.nextName();
assertThat(reader.getPreviousPath()).isEqualTo("$.a");
assertThat(reader.getPath()).isEqualTo("$.a");
reader.beginObject();
assertThat(reader.getPreviousPath()).isEqualTo("$.a.");
assertThat(reader.getPath()).isEqualTo("$.a.");
String unused2 = reader.nextName();
assertThat(reader.getPreviousPath()).isEqualTo("$.a.a1");
assertThat(reader.getPath()).isEqualTo("$.a.a1");
int unused3 = reader.nextInt();
assertThat(reader.getPreviousPath()).isEqualTo("$.a.a1");
assertThat(reader.getPath()).isEqualTo("$.a.a1");
String unused4 = reader.nextName();
assertThat(reader.getPreviousPath()).isEqualTo("$.a.a2");
assertThat(reader.getPath()).isEqualTo("$.a.a2");
int unused5 = reader.nextInt();
assertThat(reader.getPreviousPath()).isEqualTo("$.a.a2");
assertThat(reader.getPath()).isEqualTo("$.a.a2");
reader.endObject();
assertThat(reader.getPreviousPath()).isEqualTo("$.a");
assertThat(reader.getPath()).isEqualTo("$.a");
String unused6 = reader.nextName();
assertThat(reader.getPreviousPath()).isEqualTo("$.b");
assertThat(reader.getPath()).isEqualTo("$.b");
reader.beginObject();
assertThat(reader.getPreviousPath()).isEqualTo("$.b.");
assertThat(reader.getPath()).isEqualTo("$.b.");
String unused7 = reader.nextName();
assertThat(reader.getPreviousPath()).isEqualTo("$.b.b1");
assertThat(reader.getPath()).isEqualTo("$.b.b1");
int unused8 = reader.nextInt();
assertThat(reader.getPreviousPath()).isEqualTo("$.b.b1");
assertThat(reader.getPath()).isEqualTo("$.b.b1");
reader.endObject();
assertThat(reader.getPreviousPath()).isEqualTo("$.b");
assertThat(reader.getPath()).isEqualTo("$.b");
reader.endObject();
assertThat(reader.getPreviousPath()).isEqualTo("$");
assertThat(reader.getPath()).isEqualTo("$");
}
public enum Factory {
STRING_READER {
@Override
public JsonReader create(String data) {
return new JsonReader(new StringReader(data));
}
},
OBJECT_READER {
@Override
public JsonReader create(String data) {
JsonElement element = Streams.parse(new JsonReader(new StringReader(data)));
return new JsonTreeReader(element);
}
};
abstract JsonReader create(String data);
}
}