summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHÃ¥kon Hallingstad <hakon@oath.com>2019-01-30 16:43:19 +0100
committerGitHub <noreply@github.com>2019-01-30 16:43:19 +0100
commit2f05c797b69f0a261a347d769301a856a117170b (patch)
treebb1888e7fc718ac8500212878cb795a548f525c9
parente10f613bd06a8a15417d305bf1f3e80913f5547c (diff)
parenta364f2eece7d194e40c519d6246dcab522d1f06e (diff)
Merge pull request #8285 from vespa-engine/hakonhall/port-slime-injection-to-java
Port Slime injection to Java.
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/ArrayInserter.java6
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/BinaryDecoder.java6
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/Injector.java80
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/Inserter.java2
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/Inspector.java9
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/JsonDecoder.java28
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/ObjectInserter.java40
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/ObjectSymbolInserter.java32
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/Slime.java16
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/SlimeInserter.java8
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/Value.java80
-rw-r--r--vespajlib/src/test/java/com/yahoo/slime/InjectorTest.java210
-rw-r--r--vespajlib/src/test/java/com/yahoo/slime/ValueTest.java131
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