package com.ctriposs.baiji.generic;
import com.ctriposs.baiji.io.BinaryDecoder;
import com.ctriposs.baiji.io.BinaryEncoder;
import com.ctriposs.baiji.io.Decoder;
import com.ctriposs.baiji.io.Encoder;
import com.ctriposs.baiji.schema.EnumSchema;
import com.ctriposs.baiji.schema.RecordSchema;
import com.ctriposs.baiji.schema.Schema;
import org.junit.Assert;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
public abstract class GenericTestBase {
protected static <T> void test(String schema, T value) throws IOException {
Schema s = Schema.parse(schema);
byte[] data = serialize(s, value);
T output = deserialize(data, s);
checkEquals(value, output);
}
protected <T, S> void testResolution(String schema, T actual, S expected) throws IOException {
Schema s = Schema.parse(schema);
byte[] data = serialize(s, actual);
S output = deserialize(data, s);
checkEquals(expected, output);
}
protected static GenericRecord makeRecord(Object[] kv, RecordSchema s) {
GenericRecord input = new GenericRecord(s);
for (int i = 0; i < kv.length; i += 2) {
String fieldName = (String) kv[i];
Object fieldValue = kv[i + 1];
Schema inner = s.getField(fieldName).getSchema();
if (inner instanceof EnumSchema) {
GenericEnum ge = new GenericEnum((EnumSchema) inner, (String) fieldValue);
fieldValue = ge;
}
input.add(fieldName, fieldValue);
}
return input;
}
protected static Map<String, Object> makeMap(Object[] vv) {
Map<String, Object> d = new HashMap<String, Object>();
for (int j = 0; j < vv.length; j += 2) {
d.put((String) vv[j], vv[j + 1]);
}
return d;
}
protected static Object makeEnum(String enumSchema, String value) {
return new GenericEnum((EnumSchema) Schema.parse(enumSchema), value);
}
protected static <S> S deserialize(byte[] data, Schema s) throws IOException {
ByteArrayInputStream is = new ByteArrayInputStream(data);
GenericDatumReader<S> r = new GenericDatumReader<S>(s);
Decoder d = new BinaryDecoder(is);
List<S> items = new ArrayList<S>();
// validate reading twice to make sure there isn't some state that isn't reset between reads.
items.add(read(r, d));
items.add(read(r, d));
assertEquals(0, is.available()); // Ensure we have read everything.
checkAlternateDeserializers(items, data, s);
return items.get(0);
}
protected static <S> S read(DatumReader<S> reader, Decoder d) throws IOException {
return reader.read(null, d);
}
protected static <S> void checkAlternateDeserializers(List<S> expectations, byte[] data,
Schema s) throws IOException {
ByteArrayInputStream is = new ByteArrayInputStream(data);
GenericDatumReader<S> r = new GenericDatumReader<S>(s);
Decoder d = new BinaryDecoder(is);
for (Object expected : expectations) {
S read = read(r, d);
checkEquals(expected, read);
}
assertEquals(0, is.available()); // Ensure we have read everything.
}
protected static <T> byte[] serialize(Schema schema, T actual) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
Encoder e = new BinaryEncoder(os);
GenericDatumWriter<T> w = new GenericDatumWriter<T>(schema);
// write twice so we can validate reading twice
w.write(actual, e);
w.write(actual, e);
byte[] data = os.toByteArray();
checkAlternateSerializers(data, actual, schema);
return data;
}
protected static <T> void checkAlternateSerializers(byte[] expected, T value, Schema schema)
throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
Encoder e = new BinaryEncoder(os);
GenericDatumWriter<T> w = new GenericDatumWriter<T>(schema);
w.write(value, e);
w.write(value, e);
byte[] output = os.toByteArray();
assertArrayEquals(expected, output);
}
private static void checkEquals(Object expected, Object actual) {
if (expected == actual) {
return;
}
if (expected instanceof Object[]) {
Object[] expectedArray = (Object[]) expected;
Object[] actualArray = (Object[]) actual;
Assert.assertEquals(expectedArray.length, actualArray.length);
for (int i = 0; i < expectedArray.length; ++i) {
checkEquals(expectedArray[i], actualArray[i]);
}
} else if (expected instanceof byte[]) {
Assert.assertArrayEquals((byte[]) expected, (byte[]) actual);
} else {
Assert.assertEquals(expected, actual);
}
}
}