blob: c77807d0f00b1036e5c21a40631f454a4d954f1c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.drill.exec.store.easy.json.parser;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.input.ReaderInputStream;
import org.apache.drill.exec.vector.accessor.UnsupportedConversionError;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonToken;
public class BaseTestJsonParser {
@SuppressWarnings("serial")
protected static class JsonErrorFixture extends RuntimeException {
String errorType;
public JsonErrorFixture(String errorType, String msg, Exception e) {
super(msg, e);
this.errorType = errorType;
}
public JsonErrorFixture(String errorType, String msg) {
super(msg);
this.errorType = errorType;
}
}
/**
* Convert JSON errors to a simple form for use in tests.
* Not all errors are throw in normal operation; some require
* faults in the I/O system or in the Jackson parser.
*/
protected static class ErrorFactoryFixture implements ErrorFactory {
@Override
public RuntimeException parseError(String msg, JsonParseException e) {
throw new JsonErrorFixture("parseError", msg, e);
}
@Override
public RuntimeException ioException(IOException e) {
throw new JsonErrorFixture("ioException", "", e);
}
@Override
public RuntimeException structureError(String msg) {
throw new JsonErrorFixture("structureError", msg);
}
@Override
public RuntimeException syntaxError(JsonParseException e) {
throw new JsonErrorFixture("syntaxError", "", e);
}
@Override
public RuntimeException typeError(UnsupportedConversionError e) {
throw new JsonErrorFixture("typeError", "", e);
}
@Override
public RuntimeException syntaxError(JsonToken token) {
throw new JsonErrorFixture("syntaxError", token.toString());
}
@Override
public RuntimeException unrecoverableError() {
throw new JsonErrorFixture("unrecoverableError", "");
}
}
protected static class ValueListenerFixture implements ValueListener {
final ValueDef valueDef;
int nullCount;
int valueCount;
Object value;
ValueHost host;
ObjectListenerFixture objectValue;
ArrayListenerFixture arrayValue;
public ValueListenerFixture(ValueDef valueDef) {
this.valueDef = valueDef;
}
@Override
public void onNull() {
nullCount++;
}
@Override
public void onBoolean(boolean value) {
this.value = value;
valueCount++;
}
@Override
public void onInt(long value) {
this.value = value;
valueCount++;
}
@Override
public void onFloat(double value) {
this.value = value;
valueCount++;
}
@Override
public void onString(String value) {
this.value = value;
valueCount++;
}
@Override
public void onEmbeddedObject(String value) {
this.value = value;
valueCount++;
}
@Override
public ObjectListener object() {
assertNull(objectValue);
objectValue = new ObjectListenerFixture();
return objectValue;
}
@Override
public ArrayListener array(ValueDef valueDef) {
if (arrayValue == null) {
arrayValue = new ArrayListenerFixture(valueDef);
}
return arrayValue;
}
@Override
public void bind(ValueHost host) {
this.host = host;
}
}
protected static class ArrayListenerFixture implements ArrayListener {
final ValueDef valueDef;
int startCount;
int endCount;
int elementCount;
ValueListenerFixture element;
public ArrayListenerFixture(ValueDef valueDef) {
this.valueDef = valueDef;
}
@Override
public void onStart() {
startCount++;
}
@Override
public void onElementStart() {
elementCount++;
}
@Override
public void onElementEnd() { }
@Override
public void onEnd() {
endCount++;
}
@Override
public ValueListener element(ValueDef valueDef) {
if (element == null) {
element = new ValueListenerFixture(valueDef);
}
return element;
}
}
protected static class ObjectListenerFixture implements ObjectListener {
final Map<String, ValueListenerFixture> fields = new HashMap<>();
Set<String> projectFilter;
FieldType fieldType = FieldType.TYPED;
int startCount;
int endCount;
@Override
public void onStart() {
startCount++;
}
@Override
public void onEnd() {
endCount++;
}
@Override
public FieldType fieldType(String key) {
if (projectFilter != null && !projectFilter.contains(key)) {
return FieldType.IGNORE;
}
return fieldType;
}
@Override
public ValueListener addField(String key, ValueDef valueDef) {
assertFalse(fields.containsKey(key));
ValueListenerFixture field = makeField(key, valueDef);
fields.put(key, field);
return field;
}
public ValueListenerFixture makeField(String key, ValueDef valueDef) {
return new ValueListenerFixture(valueDef);
}
public ValueListenerFixture field(String key) {
ValueListenerFixture field = fields.get(key);
assertNotNull(field);
return field;
}
}
protected static class JsonParserFixture {
JsonStructureOptions options = new JsonStructureOptions();
JsonStructureParser parser;
ObjectListenerFixture rootObject = new ObjectListenerFixture();
ErrorFactory errorFactory = new ErrorFactoryFixture();
public void open(String json) {
InputStream inStream = new
ReaderInputStream(new StringReader(json));
parser = new JsonStructureParser(inStream, options, rootObject,
errorFactory);
}
public boolean next() {
assertNotNull(parser);
return parser.next();
}
public int read() {
int i = 0;
while (next()) {
i++;
}
return i;
}
public ValueListenerFixture field(String key) {
return rootObject.field(key);
}
public void expect(String key, Object[] values) {
ValueListenerFixture valueListener = null;
int expectedNullCount = 0;
for (int i = 0; i < values.length; i++) {
assertTrue(next());
if (valueListener == null) {
valueListener = field(key);
expectedNullCount = valueListener.nullCount;
}
Object value = values[i];
if (value == null) {
expectedNullCount++;
} else {
assertEquals(value, valueListener.value);
}
assertEquals(expectedNullCount, valueListener.nullCount);
}
}
public void close() {
if (parser != null) {
parser.close();
}
}
}
protected static void expectError(String json, String kind) {
JsonParserFixture fixture = new JsonParserFixture();
fixture.open(json);
expectError(fixture, kind);
fixture.close();
}
protected static void expectError(JsonParserFixture fixture, String kind) {
try {
fixture.read();
fail();
} catch (JsonErrorFixture e) {
assertEquals(kind, e.errorType);
}
}
}