diff options
13 files changed, 600 insertions, 48 deletions
diff --git a/vespajlib/src/main/java/com/yahoo/slime/ArrayInserter.java b/vespajlib/src/main/java/com/yahoo/slime/ArrayInserter.java index d6c31b39b5b..84e42d83de8 100644 --- a/vespajlib/src/main/java/com/yahoo/slime/ArrayInserter.java +++ b/vespajlib/src/main/java/com/yahoo/slime/ArrayInserter.java @@ -5,12 +5,16 @@ package com.yahoo.slime; * Helper class for inserting values into an ArrayValue. * For justification read Inserter documentation. **/ -final class ArrayInserter implements Inserter { +public final class ArrayInserter implements Inserter { private Cursor target; + + public ArrayInserter(Cursor c) { target = c; } + public final ArrayInserter adjust(Cursor c) { target = c; return this; } + public final Cursor insertNIX() { return target.addNix(); } public final Cursor insertBOOL(boolean value) { return target.addBool(value); } public final Cursor insertLONG(long value) { return target.addLong(value); } diff --git a/vespajlib/src/main/java/com/yahoo/slime/BinaryDecoder.java b/vespajlib/src/main/java/com/yahoo/slime/BinaryDecoder.java index 3fe35ef2098..ecee5e9504e 100644 --- a/vespajlib/src/main/java/com/yahoo/slime/BinaryDecoder.java +++ b/vespajlib/src/main/java/com/yahoo/slime/BinaryDecoder.java @@ -6,9 +6,9 @@ import static com.yahoo.slime.BinaryFormat.*; final class BinaryDecoder { BufferedInput in; - private final SlimeInserter slimeInserter = new SlimeInserter(); - private final ArrayInserter arrayInserter = new ArrayInserter(); - private final ObjectInserter objectInserter = new ObjectInserter(); + private final SlimeInserter slimeInserter = new SlimeInserter(null); + private final ArrayInserter arrayInserter = new ArrayInserter(null); + private final ObjectSymbolInserter objectInserter = new ObjectSymbolInserter(null, 0); public BinaryDecoder() {} diff --git a/vespajlib/src/main/java/com/yahoo/slime/Injector.java b/vespajlib/src/main/java/com/yahoo/slime/Injector.java new file mode 100644 index 00000000000..f21cf621d3c --- /dev/null +++ b/vespajlib/src/main/java/com/yahoo/slime/Injector.java @@ -0,0 +1,80 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.slime; + +/** + * @author hakonhall + */ +public class Injector { + /** + * Inject a slime sub-structure described by an Inspector into a slime + * structure where the insertion point is described by an + * Inserter. This will copy all the values represented by the + * Inspector into the position described by the Inserter. Note that + * this can be used to either copy data from one Slime structure to + * another, or to copy data internally within a single slime + * structure. If the Inspector contains the insertion point it will + * only be expanded once to avoid infinite recursion. + * + * @param inspector what to inject + * @param inserter where to inject + **/ + public void inject(Inspector inspector, Inserter inserter) { + if (inspector.valid()) { + injectValue(inserter, inspector, null); + } + } + + private void injectValue(Inserter inserter, Inspector inspector, Inspector guard) { + inspector.accept(new Visitor() { + @Override public void visitInvalid() { } + @Override public void visitNix() { inserter.insertNIX(); } + @Override public void visitBool(boolean bit) { inserter.insertBOOL(bit); } + @Override public void visitLong(long l) { inserter.insertLONG(l); } + @Override public void visitDouble(double d) { inserter.insertDOUBLE(d); } + @Override public void visitString(String str) { inserter.insertSTRING(str); } + @Override public void visitString(byte[] utf8) { inserter.insertSTRING(utf8); } + @Override public void visitData(byte[] data) { inserter.insertDATA(data); } + + @Override + public void visitArray(Inspector arr) { + Cursor cursor = inserter.insertARRAY(); + ArrayTraverser arrayTraverser = new NestedInjector(cursor, guard != null ? guard : cursor); + arr.traverse(arrayTraverser); + } + @Override + public void visitObject(Inspector obj) { + Cursor cursor = inserter.insertOBJECT(); + ObjectTraverser objectTraverser = new NestedInjector(cursor, guard != null ? guard : cursor); + obj.traverse(objectTraverser); + } + }); + } + + private class NestedInjector implements ArrayTraverser, ObjectTraverser { + private final Cursor cursor; + private final Inspector guard; + + public NestedInjector(Cursor cursor, Inspector guard) { + this.cursor = cursor; + this.guard = guard; + } + + @Override + public void entry(int idx, Inspector inspector) { + if (inspector == guard) { + return; + } + + injectValue(new ArrayInserter(cursor), inspector, guard); + } + + @Override + public void field(String name, Inspector inspector) { + if (inspector == guard) { + return; + } + + injectValue(new ObjectInserter(cursor, name), inspector, guard); + } + } +} diff --git a/vespajlib/src/main/java/com/yahoo/slime/Inserter.java b/vespajlib/src/main/java/com/yahoo/slime/Inserter.java index b3ccd5e3e6c..21f641914d8 100644 --- a/vespajlib/src/main/java/com/yahoo/slime/Inserter.java +++ b/vespajlib/src/main/java/com/yahoo/slime/Inserter.java @@ -7,7 +7,7 @@ package com.yahoo.slime; * deserializers where you can use it to decouple the actual value * decoding from the container where the value should be inserted. **/ -interface Inserter { +public interface Inserter { Cursor insertNIX(); Cursor insertBOOL(boolean value); Cursor insertLONG(long value); diff --git a/vespajlib/src/main/java/com/yahoo/slime/Inspector.java b/vespajlib/src/main/java/com/yahoo/slime/Inspector.java index 99489faca47..7af7accaf49 100644 --- a/vespajlib/src/main/java/com/yahoo/slime/Inspector.java +++ b/vespajlib/src/main/java/com/yahoo/slime/Inspector.java @@ -131,4 +131,13 @@ public interface Inspector { */ Inspector field(String name); + /** + * Tests whether this is equal to Inspector. + * + * Since equality of two Inspectors is subtle, {@link Object#equals(Object)} is not used. + * + * @param that inspector. + * @return true if they are equal. + */ + boolean equalTo(Inspector that); } diff --git a/vespajlib/src/main/java/com/yahoo/slime/JsonDecoder.java b/vespajlib/src/main/java/com/yahoo/slime/JsonDecoder.java index 71eaa7f8b25..a761c91f64f 100644 --- a/vespajlib/src/main/java/com/yahoo/slime/JsonDecoder.java +++ b/vespajlib/src/main/java/com/yahoo/slime/JsonDecoder.java @@ -4,9 +4,6 @@ package com.yahoo.slime; import com.yahoo.text.Utf8; import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; /** * A port of the C++ json decoder intended to be fast. @@ -18,9 +15,9 @@ public class JsonDecoder { private BufferedInput in; private byte c; - private final SlimeInserter slimeInserter = new SlimeInserter(); - private final ArrayInserter arrayInserter = new ArrayInserter(); - private final JsonObjectInserter objectInserter = new JsonObjectInserter(); + private final SlimeInserter slimeInserter = new SlimeInserter(null); + private final ArrayInserter arrayInserter = new ArrayInserter(null); + private final ObjectInserter objectInserter = new ObjectInserter(null, null); private final ByteArrayOutputStream buf = new ByteArrayOutputStream(); private static final byte[] TRUE = {'t', 'r', 'u', 'e'}; @@ -284,23 +281,4 @@ public class JsonDecoder { } } - private static final class JsonObjectInserter implements Inserter { - private Cursor target; - private String key; - public final JsonObjectInserter adjust(Cursor c, String key) { - target = c; - this.key = key; - return this; - } - public final Cursor insertNIX() { return target.setNix(key); } - public final Cursor insertBOOL(boolean value) { return target.setBool(key, value); } - public final Cursor insertLONG(long value) { return target.setLong(key, value); } - public final Cursor insertDOUBLE(double value) { return target.setDouble(key, value); } - public final Cursor insertSTRING(String value) { return target.setString(key, value); } - public final Cursor insertSTRING(byte[] utf8) { return target.setString(key, utf8); } - public final Cursor insertDATA(byte[] value) { return target.setData(key, value); } - public final Cursor insertARRAY() { return target.setArray(key); } - public final Cursor insertOBJECT() { return target.setObject(key); } - } - } diff --git a/vespajlib/src/main/java/com/yahoo/slime/ObjectInserter.java b/vespajlib/src/main/java/com/yahoo/slime/ObjectInserter.java index 3e0073beccd..3da39fd753a 100644 --- a/vespajlib/src/main/java/com/yahoo/slime/ObjectInserter.java +++ b/vespajlib/src/main/java/com/yahoo/slime/ObjectInserter.java @@ -1,25 +1,31 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.slime; /** - * Helper class for inserting values into an ObjectValue. - * For justification read Inserter documentation. - **/ -final class ObjectInserter implements Inserter { + * @author hakonhall + */ +public final class ObjectInserter implements Inserter { private Cursor target; - private int symbol; - public final ObjectInserter adjust(Cursor c, int sym) { + private String key; + + public ObjectInserter(Cursor c, String key) { target = c; - symbol = sym; + this.key = key; + } + + public final ObjectInserter adjust(Cursor c, String key) { + target = c; + this.key = key; return this; } - public final Cursor insertNIX() { return target.setNix(symbol); } - public final Cursor insertBOOL(boolean value) { return target.setBool(symbol, value); } - public final Cursor insertLONG(long value) { return target.setLong(symbol, value); } - public final Cursor insertDOUBLE(double value) { return target.setDouble(symbol, value); } - public final Cursor insertSTRING(String value) { return target.setString(symbol, value); } - public final Cursor insertSTRING(byte[] utf8) { return target.setString(symbol, utf8); } - public final Cursor insertDATA(byte[] value) { return target.setData(symbol, value); } - public final Cursor insertARRAY() { return target.setArray(symbol); } - public final Cursor insertOBJECT() { return target.setObject(symbol); } + + public final Cursor insertNIX() { return target.setNix(key); } + public final Cursor insertBOOL(boolean value) { return target.setBool(key, value); } + public final Cursor insertLONG(long value) { return target.setLong(key, value); } + public final Cursor insertDOUBLE(double value) { return target.setDouble(key, value); } + public final Cursor insertSTRING(String value) { return target.setString(key, value); } + public final Cursor insertSTRING(byte[] utf8) { return target.setString(key, utf8); } + public final Cursor insertDATA(byte[] value) { return target.setData(key, value); } + public final Cursor insertARRAY() { return target.setArray(key); } + public final Cursor insertOBJECT() { return target.setObject(key); } } diff --git a/vespajlib/src/main/java/com/yahoo/slime/ObjectSymbolInserter.java b/vespajlib/src/main/java/com/yahoo/slime/ObjectSymbolInserter.java new file mode 100644 index 00000000000..0fa66245643 --- /dev/null +++ b/vespajlib/src/main/java/com/yahoo/slime/ObjectSymbolInserter.java @@ -0,0 +1,32 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.slime; + +/** + * Helper class for inserting values into an ObjectValue. + * For justification read Inserter documentation. + **/ +public final class ObjectSymbolInserter implements Inserter { + private Cursor target; + private int symbol; + + public ObjectSymbolInserter(Cursor cursor, int sym) { + target = cursor; + symbol = sym; + } + + public final ObjectSymbolInserter adjust(Cursor c, int sym) { + target = c; + symbol = sym; + return this; + } + + public final Cursor insertNIX() { return target.setNix(symbol); } + public final Cursor insertBOOL(boolean value) { return target.setBool(symbol, value); } + public final Cursor insertLONG(long value) { return target.setLong(symbol, value); } + public final Cursor insertDOUBLE(double value) { return target.setDouble(symbol, value); } + public final Cursor insertSTRING(String value) { return target.setString(symbol, value); } + public final Cursor insertSTRING(byte[] utf8) { return target.setString(symbol, utf8); } + public final Cursor insertDATA(byte[] value) { return target.setData(symbol, value); } + public final Cursor insertARRAY() { return target.setArray(symbol); } + public final Cursor insertOBJECT() { return target.setObject(symbol); } +} diff --git a/vespajlib/src/main/java/com/yahoo/slime/Slime.java b/vespajlib/src/main/java/com/yahoo/slime/Slime.java index 84f193caa4d..8357e3035c0 100644 --- a/vespajlib/src/main/java/com/yahoo/slime/Slime.java +++ b/vespajlib/src/main/java/com/yahoo/slime/Slime.java @@ -158,4 +158,20 @@ public final class Slime { return wrap(names.insert(name)); } + /** + * Tests whether this is equal to Inspector. + * + * Since equality of two Inspectors is subtle, {@link Object#equals(Object)} is not used. + * + * @param that inspector. + * @return true if they are equal. + */ + public boolean equalTo(Slime that) { + return get().equalTo(that.get()); + } + + @Override + public String toString() { + return get().toString(); + } } diff --git a/vespajlib/src/main/java/com/yahoo/slime/SlimeInserter.java b/vespajlib/src/main/java/com/yahoo/slime/SlimeInserter.java index 2607f762f66..2b048c42f73 100644 --- a/vespajlib/src/main/java/com/yahoo/slime/SlimeInserter.java +++ b/vespajlib/src/main/java/com/yahoo/slime/SlimeInserter.java @@ -5,12 +5,18 @@ package com.yahoo.slime; * Helper class for inserting values into a Slime object. * For justification read Inserter documentation. **/ -final class SlimeInserter implements Inserter { +public final class SlimeInserter implements Inserter { private Slime target; + + public SlimeInserter(Slime target) { + this.target = target; + } + public final SlimeInserter adjust(Slime slime) { target = slime; return this; } + public final Cursor insertNIX() { return target.setNix(); } public final Cursor insertBOOL(boolean value) { return target.setBool(value); } public final Cursor insertLONG(long value) { return target.setLong(value); } diff --git a/vespajlib/src/main/java/com/yahoo/slime/Value.java b/vespajlib/src/main/java/com/yahoo/slime/Value.java index 51a8262333b..9d325fc7fb6 100644 --- a/vespajlib/src/main/java/com/yahoo/slime/Value.java +++ b/vespajlib/src/main/java/com/yahoo/slime/Value.java @@ -3,6 +3,7 @@ package com.yahoo.slime; import java.io.ByteArrayOutputStream; +import java.util.Arrays; /** * Common implementation for all value types. @@ -84,4 +85,83 @@ abstract class Value implements Cursor { return "null"; } } + + private static class Equal { + protected final Inspector rhsInspector; + + protected boolean equal = true; + + public Equal(Inspector rhsInspector) { this.rhsInspector = rhsInspector; } + + public boolean isEqual() { return equal; } + } + + private static class EqualArray extends Equal implements ArrayTraverser { + public EqualArray(Inspector rhsInspector) { super(rhsInspector); } + + @Override + public void entry(int idx, Inspector inspector) { + if (equal) { + equal = inspector.equalTo(rhsInspector.entry(idx)); + } + } + } + + private static class EqualObject extends Equal implements ObjectTraverser { + public EqualObject(Inspector rhsInspector) { super(rhsInspector); } + + @Override + public void field(String name, Inspector inspector) { + if (equal) { + equal = inspector.equalTo(rhsInspector.field(name)); + } + } + } + + @Override + public boolean equalTo(Inspector that) { + boolean equal = type() == that.type(); + + if (equal) { + switch (type()) { + case NIX: + equal = valid() == that.valid(); + break; + case BOOL: + equal = asBool() == that.asBool(); + break; + case LONG: + equal = asLong() == that.asLong(); + break; + case DOUBLE: + equal = Double.compare(asDouble(), that.asDouble()) == 0; + break; + case STRING: + equal = asString().equals(that.asString()); + break; + case DATA: + equal = Arrays.equals(asData(), that.asData()); + break; + case ARRAY: + { + var traverser = new EqualArray(that); + traverse(traverser); + equal = traverser.isEqual() && (entries() == that.entries()); + } + break; + case OBJECT: + { + var traverser = new EqualObject(that); + traverse(traverser); + equal = traverser.isEqual() && (fields() == that.fields()); + } + break; + default: + assert(false); + break; + } + } + + return equal; + } } diff --git a/vespajlib/src/test/java/com/yahoo/slime/InjectorTest.java b/vespajlib/src/test/java/com/yahoo/slime/InjectorTest.java new file mode 100644 index 00000000000..a11d3ad220f --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/slime/InjectorTest.java @@ -0,0 +1,210 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.slime; + +import org.junit.Test; + +import java.nio.charset.StandardCharsets; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author hakonhall + */ +public class InjectorTest { + private static class SourceFixture { + public final Slime empty = new Slime(); + public final Slime nixValue = new Slime(); + public final Slime boolValue = new Slime(); + public final Slime longValue = new Slime(); + public final Slime doubleValue = new Slime(); + public final Slime stringValue = new Slime(); + public final Slime dataValue = new Slime(); + public final Slime arrayValue = new Slime(); + public final Slime objectValue = new Slime(); + + SourceFixture() { + nixValue.setNix(); + boolValue.setBool(true); + longValue.setLong(10); + doubleValue.setDouble(20.0); + stringValue.setString("string"); + dataValue.setData("data".getBytes(StandardCharsets.UTF_8)); + Cursor arr = arrayValue.setArray(); + arr.addLong(1); + arr.addLong(2); + arr.addLong(3); + Cursor obj = objectValue.setObject(); + obj.setLong("a", 1); + obj.setLong("b", 2); + obj.setLong("c", 3); + } + } + + private static class DestinationFixture { + public final Slime slime1 = new Slime(); + public final Slime slime2 = new Slime(); + public final Slime slime3 = new Slime(); + public final Slime slime4 = new Slime(); + public final Slime slime5 = new Slime(); + public final Slime slime6 = new Slime(); + public final Slime slime7 = new Slime(); + public final Slime slime8 = new Slime(); + public final Slime slime9 = new Slime(); + } + + private final SourceFixture f1 = new SourceFixture(); + private final DestinationFixture f2 = new DestinationFixture(); + + private final Injector injector = new Injector(); + + private void inject(Inspector inspector, Inserter inserter) { + injector.inject(inspector, inserter); + } + + private void assertEqualTo(Slime left, Slime right) { + assertTrue("'" + left + "' not equal to '" + right + "'", left.equalTo(right)); + } + + private void assertEqualTo(Inspector left, Inspector right) { + assertTrue("'" + left + "' not equal to '" + right + "'", left.equalTo(right)); + } + + @Test + public void injectIntoSlime() { + assertTrue(f1.empty.get().valid()); // explicit nix + + inject(f1.empty.get(), new SlimeInserter(f2.slime1)); + inject(f1.nixValue.get(), new SlimeInserter(f2.slime2)); + inject(f1.boolValue.get(), new SlimeInserter(f2.slime3)); + inject(f1.longValue.get(), new SlimeInserter(f2.slime4)); + inject(f1.doubleValue.get(), new SlimeInserter(f2.slime5)); + inject(f1.stringValue.get(), new SlimeInserter(f2.slime6)); + inject(f1.dataValue.get(), new SlimeInserter(f2.slime7)); + inject(f1.arrayValue.get(), new SlimeInserter(f2.slime8)); + inject(f1.objectValue.get(), new SlimeInserter(f2.slime9)); + + assertEquals(f1.empty.get().toString(), f2.slime1.get().toString()); + assertEquals(f1.nixValue.get().toString(), f2.slime2.get().toString()); + assertEquals(f1.boolValue.get().toString(), f2.slime3.get().toString()); + assertEquals(f1.longValue.get().toString(), f2.slime4.get().toString()); + assertEquals(f1.doubleValue.get().toString(), f2.slime5.get().toString()); + assertEquals(f1.stringValue.get().toString(), f2.slime6.get().toString()); + assertEquals(f1.dataValue.get().toString(), f2.slime7.get().toString()); + assertEquals(f1.arrayValue.get().toString(), f2.slime8.get().toString()); + assertEqualTo(f1.objectValue.get(), f2.slime9.get()); + + } + + @Test + public void injectIntoArray() { + f2.slime1.setArray(); + inject(f1.empty.get(), new ArrayInserter(f2.slime1.get())); + inject(f1.nixValue.get(), new ArrayInserter(f2.slime1.get())); + inject(f1.boolValue.get(), new ArrayInserter(f2.slime1.get())); + inject(f1.longValue.get(), new ArrayInserter(f2.slime1.get())); + inject(f1.doubleValue.get(), new ArrayInserter(f2.slime1.get())); + inject(f1.stringValue.get(), new ArrayInserter(f2.slime1.get())); + inject(f1.dataValue.get(), new ArrayInserter(f2.slime1.get())); + inject(f1.arrayValue.get(), new ArrayInserter(f2.slime1.get())); + inject(f1.objectValue.get(), new ArrayInserter(f2.slime1.get())); + + assertEquals(f1.empty.get().toString(), f2.slime1.get().entry(0).toString()); + assertEquals(f1.nixValue.get().toString(), f2.slime1.get().entry(1).toString()); + assertEquals(f1.boolValue.get().toString(), f2.slime1.get().entry(2).toString()); + assertEquals(f1.longValue.get().toString(), f2.slime1.get().entry(3).toString()); + assertEquals(f1.doubleValue.get().toString(), f2.slime1.get().entry(4).toString()); + assertEquals(f1.stringValue.get().toString(), f2.slime1.get().entry(5).toString()); + assertEquals(f1.dataValue.get().toString(), f2.slime1.get().entry(6).toString()); + assertEquals(f1.arrayValue.get().toString(), f2.slime1.get().entry(7).toString()); + assertEqualTo(f1.objectValue.get(), f2.slime1.get().entry(8)); + } + + @Test + public void injectIntoObject() { + f2.slime1.setObject(); + inject(f1.empty.get(), new ObjectInserter(f2.slime1.get(), "a")); + inject(f1.nixValue.get(), new ObjectInserter(f2.slime1.get(), "b")); + inject(f1.boolValue.get(), new ObjectInserter(f2.slime1.get(), "c")); + inject(f1.longValue.get(), new ObjectInserter(f2.slime1.get(), "d")); + inject(f1.doubleValue.get(), new ObjectInserter(f2.slime1.get(), "e")); + inject(f1.stringValue.get(), new ObjectInserter(f2.slime1.get(), "f")); + inject(f1.dataValue.get(), new ObjectInserter(f2.slime1.get(), "g")); + inject(f1.arrayValue.get(), new ObjectInserter(f2.slime1.get(), "h")); + inject(f1.objectValue.get(), new ObjectInserter(f2.slime1.get(), "i")); + + assertEquals(f1.empty.get().toString(), f2.slime1.get().field("a").toString()); + assertEquals(f1.nixValue.get().toString(), f2.slime1.get().field("b").toString()); + assertEquals(f1.boolValue.get().toString(), f2.slime1.get().field("c").toString()); + assertEquals(f1.longValue.get().toString(), f2.slime1.get().field("d").toString()); + assertEquals(f1.doubleValue.get().toString(), f2.slime1.get().field("e").toString()); + assertEquals(f1.stringValue.get().toString(), f2.slime1.get().field("f").toString()); + assertEquals(f1.dataValue.get().toString(), f2.slime1.get().field("g").toString()); + assertEquals(f1.arrayValue.get().toString(), f2.slime1.get().field("h").toString()); + assertEqualTo(f1.objectValue.get(), f2.slime1.get().field("i")); + } + + @Test + public void invalidInjectionIsIgnored() { + inject(f1.arrayValue.get(), new SlimeInserter(f2.slime1)); + assertEquals(3, f2.slime1.get().entries()); + inject(f1.longValue.get(), new ArrayInserter(f2.slime1.get())); + assertEquals(4, f2.slime1.get().entries()); + inject(f1.doubleValue.get(), new ArrayInserter(f2.slime1.get())); + assertEquals(5, f2.slime1.get().entries()); + inject(f1.nixValue.get().field("bogus"), new ArrayInserter(f2.slime1.get())); + assertEquals(5, f2.slime1.get().entries()); + } + + @Test + public void recursiveArrayInject() { + Slime expect = new Slime(); + { + Cursor arr = expect.setArray(); + arr.addLong(1); + arr.addLong(2); + arr.addLong(3); + { + Cursor arrCpy = arr.addArray(); + arrCpy.addLong(1); + arrCpy.addLong(2); + arrCpy.addLong(3); + } + } + Slime data = new Slime(); + { + Cursor arr = data.setArray(); + arr.addLong(1); + arr.addLong(2); + arr.addLong(3); + } + inject(data.get(), new ArrayInserter(data.get())); + assertEquals(expect.toString(), data.toString()); + } + + @Test + public void recursiveObjectInject() { + Slime expect = new Slime(); + { + Cursor obj = expect.setObject(); + obj.setLong("a", 1); + obj.setLong("b", 2); + obj.setLong("c", 3); + { + Cursor obj_cpy = obj.setObject("d"); + obj_cpy.setLong("a", 1); + obj_cpy.setLong("b", 2); + obj_cpy.setLong("c", 3); + } + } + Slime data = new Slime(); + { + Cursor obj = data.setObject(); + obj.setLong("a", 1); + obj.setLong("b", 2); + obj.setLong("c", 3); + } + inject(data.get(), new ObjectInserter(data.get(), "d")); + assertEqualTo(expect, data); + } +}
\ No newline at end of file diff --git a/vespajlib/src/test/java/com/yahoo/slime/ValueTest.java b/vespajlib/src/test/java/com/yahoo/slime/ValueTest.java new file mode 100644 index 00000000000..50d2e900720 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/slime/ValueTest.java @@ -0,0 +1,131 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.slime; + +import org.junit.Test; + +import java.nio.charset.StandardCharsets; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author hakonhall + */ +public class ValueTest { + @Test + public void verifyObjectEquality() { + Slime slimeLeft = new Slime(); + Cursor left = slimeLeft.setObject(); + left.setString("a", "A"); + left.setString("b", "B"); + + Slime slimeRight = new Slime(); + Cursor right = slimeRight.setObject(); + right.setString("b", "B"); + right.setString("a", "A"); + + assertTrue(left.equalTo(right)); + assertTrue(right.equalTo(left)); + assertTrue(left.equalTo(left)); + + right.setString("c", "C"); + assertFalse(left.equalTo(right)); + assertFalse(right.equalTo(left)); + } + + @Test + public void verifyArrayEquality() { + Slime slimeLeft = new Slime(); + Cursor left = slimeLeft.setArray(); + left.addArray().addString("a"); + left.addArray().addString("b"); + + Slime slimeRight = new Slime(); + Cursor right = slimeRight.setArray(); + right.addArray().addString("a"); + right.addArray().addString("b"); + + assertTrue(left.equalTo(right)); + assertTrue(right.equalTo(left)); + assertTrue(left.equalTo(left)); + + right.addArray().addString("c"); + assertFalse(left.equalTo(right)); + assertFalse(right.equalTo(left)); + + // Order matters + Slime slimeRight2 = new Slime(); + Cursor right2 = slimeRight2.setObject(); + right2.addArray().addString("b"); + right2.addArray().addString("a"); + assertFalse(left.equalTo(right2)); + assertFalse(right2.equalTo(left)); + } + + @Test + public void verifyPrimitiveEquality() { + Slime left = new Slime(); + Cursor leftObject = left.setObject(); + populateWithPrimitives(leftObject, true); + + Slime right = new Slime(); + Cursor rightObject = right.setObject(); + populateWithPrimitives(rightObject, true); + + assertEqualTo(left.get().field("bool"), right.get().field("bool")); + assertEqualTo(left.get().field("nix"), right.get().field("nix")); + assertEqualTo(left.get().field("long"), right.get().field("long")); + assertEqualTo(left.get().field("string"), right.get().field("string")); + assertEqualTo(left.get().field("data"), right.get().field("data")); + assertEqualTo(left.get(), right.get()); + + assertNotEqualTo(left.get().field("bool"), right.get().field("nix")); + assertNotEqualTo(left.get().field("nix"), right.get().field("string")); + assertNotEqualTo(left.get().field("string"), right.get().field("data")); + assertNotEqualTo(left.get().field("bool"), right.get().field("data")); + assertNotEqualTo(left.get().field("bool"), right.get().field("long")); + } + + @Test + public void verifyPrimitiveNotEquality() { + Slime left = new Slime(); + Cursor leftObject = left.setObject(); + populateWithPrimitives(leftObject, true); + + Slime right = new Slime(); + Cursor rightObject = right.setObject(); + populateWithPrimitives(rightObject, false); + + assertNotEqualTo(left.get().field("bool"), right.get().field("bool")); + assertEqualTo(left.get().field("nix"), right.get().field("nix")); + assertNotEqualTo(left.get().field("long"), right.get().field("long")); + assertNotEqualTo(left.get().field("string"), right.get().field("string")); + assertNotEqualTo(left.get().field("data"), right.get().field("data")); + assertNotEqualTo(left.get(), right.get()); + } + + @Test + public void testNixEquality() { + assertEqualTo(NixValue.invalid(), NixValue.invalid()); + assertEqualTo(NixValue.instance(), NixValue.instance()); + assertNotEqualTo(NixValue.instance(), NixValue.invalid()); + assertNotEqualTo(NixValue.invalid(), NixValue.instance()); + } + + private void populateWithPrimitives(Cursor cursor, boolean enabled) { + cursor.setBool("bool", enabled ? true : false); + cursor.setNix("nix"); + cursor.setLong("long", enabled ? 1 : 0); + cursor.setString("string", enabled ? "enabled" : "disabled"); + cursor.setDouble("double", enabled ? 1.5 : 0.5); + cursor.setData("data", (enabled ? "edata" : "ddata").getBytes(StandardCharsets.UTF_8)); + } + + private void assertEqualTo(Inspector left, Inspector right) { + assertTrue("'" + left + "' is not equal to '" + right + "'", left.equalTo(right)); + } + + private void assertNotEqualTo(Inspector left, Inspector right) { + assertTrue("'" + left + "' is equal to '" + right + "'", !left.equalTo(right)); + } +}
\ No newline at end of file |