package io.nextop;
import com.google.gson.*;
import io.nextop.util.HexBytes;
import junit.framework.TestCase;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class WireValueTest extends TestCase {
public void testStableKeys() {
int n = 8;
int mm = 32;
Random r = new Random();
ByteBuffer bb = ByteBuffer.allocate(32 * 1024);
for (int i = 0; i < n; ++i) {
int m = r.nextInt(2 * mm);
Map<String, Integer> map = new HashMap<String, Integer>(m);
for (int j = 0; j < m; ++j) {
String s = randomString(r, 8);
String key = s;
for (Integer e = j; null != (e = map.put(key, e)); ) {
// double down
key += " " + s;
}
}
Map<WireValue, WireValue> valueMap = new HashMap<WireValue, WireValue>(map.size());
for (Map.Entry<String, Integer> e : map.entrySet()) {
valueMap.put(WireValue.of(e.getKey()), WireValue.of(e.getValue()));
}
assertEquals(map.size(), valueMap.size());
// to bytes, read back,
// now compare equals, compare the json
WireValue in = WireValue.of(valueMap);
bb.clear();
in.toBytes(bb);
bb.flip();
WireValue out = WireValue.valueOf(bb);
assertEquals(in, out);
assertEquals(in.toJson(), out.toJson());
assertEquals(in.toText(), out.toText());
}
}
public void testToString() {
// create random values and call #toString, #toText, #toDebugString
// check that nothing crashes on those calls
int n = 32;
Random r = new Random();
WireValue.Type[] types = WireValue.Type.values();
for (int i = 0; i < n; ++i) {
WireValue.Type type = types[r.nextInt(types.length)];
WireValue value = randomValue(r, type);
System.out.printf("%s\n", value.toString());
System.out.printf("%s\n", value.toText());
System.out.printf("%s\n", value.toDebugString());
}
}
public void testRandomCodec() {
// 1. generate random json
// 2. convert to wire value
// 3. bytes (measure time)
// 4. parse (3) (measure time)
// 5. (4) to json string (measure time)
// 6. parse json (5) (measure time)
// 7. convert json to wire value
// 8. assert (4) == (7)
Random r = new Random();
JsonElement je = randomJson(r, 6);
WireValue v = WireValue.of(je);
ByteBuffer bb = ByteBuffer.allocate(32 * 1024 * 1024);
for (int i = 0; i < 8; ++i) {
bb.clear();
long t = System.nanoTime();
v.toBytes(bb);
System.out.printf("to bytes %.3fms\n", ((System.nanoTime() - t) / 1000) / 1000.f);
bb.flip();
byte[] bytes = new byte[bb.remaining()];
bb.get(bytes);
t = System.nanoTime();
WireValue v2 = WireValue.valueOf(bytes);
System.out.printf("parse bytes %.3fms\n", ((System.nanoTime() - t) / 1000) / 1000.f);
assertEquals(v, v2);
t = System.nanoTime();
String js2 = v2.toJson();
System.out.printf("to json %.3fms\n", ((System.nanoTime() - t) / 1000) / 1000.f);
t = System.nanoTime();
JsonElement je2 = new JsonParser().parse(js2);
System.out.printf("parse json %.3fms\n", ((System.nanoTime() - t) / 1000) / 1000.f);
t = System.nanoTime();
WireValue v3 = WireValue.of(je2);
System.out.printf("value of json %.3fms\n", ((System.nanoTime() - t) / 1000) / 1000.f);
assertEquals(v, v3);
v = v3;
}
}
public void testBasicMessage() {
ByteBuffer bb = ByteBuffer.allocate(1024);
Message a = Message.newBuilder()
.setRoute("GET http://nextop.io")
.build();
bb.clear();
WireValue.of(a).toBytes(bb);
bb.flip();
Message da = WireValue.valueOf(bb).asMessage();
assertEquals(a.hashCode(), da.hashCode());
assertEquals(a, da);
}
public void testImageMessage() {
ByteBuffer bb = ByteBuffer.allocate(8 * 1024);
Message a = Message.newBuilder()
.setRoute("GET http://nextop.io")
.setContent(new EncodedImage(EncodedImage.Format.JPEG, EncodedImage.Orientation.REAR_FACING,
200, 200, new byte[4 * 1024], 0, 2 * 1024))
.build();
bb.clear();
WireValue.of(a).toBytes(bb);
bb.flip();
Message da = WireValue.valueOf(bb).asMessage();
assertEquals(a.hashCode(), da.hashCode());
assertEquals(a, da);
}
public void testEncodedImage() {
ByteBuffer bb = ByteBuffer.allocate(8 * 1024);
EncodedImage a = new EncodedImage(EncodedImage.Format.JPEG, EncodedImage.Orientation.REAR_FACING,
200, 200, new byte[4 * 1024], 0, 2 * 1024);
bb.clear();
WireValue.of(a).toBytes(bb);
bb.flip();
EncodedImage da = WireValue.valueOf(bb).asImage();
assertEquals(a.hashCode(), da.hashCode());
assertEquals(a, da);
}
/** from WireValueTest */
private static JsonElement randomJson(Random r, int d) {
return randomJson(r, d, 0);
}
private static JsonElement randomJson(Random r, int d, int u) {
// list, map, long, double, string, bool
int min, max;
if (0 == u) {
min = 4;
max = 13;
} else if (0 < d) {
min = 0;
max = 14;
} else {
min = 0;
max = 4;
}
switch (min + r.nextInt(max - min)) {
case 0:
return new JsonPrimitive(randomString(r, 16));
case 1:
return new JsonPrimitive(r.nextLong());
case 2:
return new JsonPrimitive(r.nextDouble());
case 3:
return new JsonPrimitive(r.nextBoolean());
case 4:
case 5:
case 6:
case 7:
case 8: {
int n = r.nextInt(16);
JsonArray array = new JsonArray();
for (int i = 0; i < n; ++i) {
array.add(randomJson(r, d - 1, u + 1));
}
return array;
}
case 9:
case 10:
case 11:
case 12:
case 13: {
int n = r.nextInt(16);
JsonObject object = new JsonObject();
for (int i = 0; i < n; ++i) {
int m = r.nextInt(32);
byte[] keyBytes = new byte[m];
r.nextBytes(keyBytes);
String key = HexBytes.toString(keyBytes);
object.add(key, randomJson(r, d - 1, u + 1));
}
return object;
}
default:
throw new IllegalStateException();
}
}
private static String randomString(Random r, int m) {
int n = r.nextInt(m);
byte[] bytes = new byte[n];
r.nextBytes(bytes);
return HexBytes.toString(bytes);
}
private static WireValue randomValue(Random r, WireValue.Type type) {
switch (type) {
case UTF8:
return WireValue.of(randomString(r, 8));
case BLOB:
return WireValue.of(randomBytes(r, 32));
case INT32:
return WireValue.of(r.nextInt());
case INT64:
return WireValue.of(r.nextLong());
case FLOAT32:
return WireValue.of(r.nextFloat());
case FLOAT64:
return WireValue.of(r.nextDouble());
case BOOLEAN:
return WireValue.of(r.nextBoolean());
case MAP:
WireValue mapValue;
do {
mapValue = WireValue.of(randomJson(r, 3));
} while (!WireValue.Type.MAP.equals(mapValue.getType()));
return mapValue;
case LIST:
WireValue listValue;
do {
listValue = WireValue.of(randomJson(r, 3));
} while (!WireValue.Type.LIST.equals(listValue.getType()));
return listValue;
case MESSAGE:
return WireValue.of(randomMessage(r));
case IMAGE:
return WireValue.of(randomImage(r));
case NULL:
return WireValue.of();
default:
throw new IllegalArgumentException("" + type);
}
}
private static byte[] randomBytes(Random r, int m) {
int n = r.nextInt(2 * m);
byte[] bytes = new byte[n];
r.nextBytes(bytes);
return bytes;
}
private static Message randomMessage(Random r) {
// TODO random authority, random method, random path
// TODO random values
return Message.newBuilder().setRoute("GET http://tests.nextop.io").build();
}
private static EncodedImage randomImage(Random r) {
EncodedImage.Format[] formats = EncodedImage.Format.values();
EncodedImage.Orientation[] orientations = EncodedImage.Orientation.values();
EncodedImage.Format format = formats[r.nextInt(formats.length)];
EncodedImage.Orientation orientation = orientations[r.nextInt(orientations.length)];
int width = 1 + r.nextInt(512);
int height = 1 + r.nextInt(512);
byte[] bytes = randomBytes(r, 1024);
return EncodedImage.create(format, orientation, width, height, bytes, 0, bytes.length);
}
}