JSON object builder, pointable and unit tests.
diff --git a/vxquery-core/src/main/java/org/apache/vxquery/datamodel/accessors/SequencePointable.java b/vxquery-core/src/main/java/org/apache/vxquery/datamodel/accessors/SequencePointable.java
index 0aa66f7..9ccac0b 100644
--- a/vxquery-core/src/main/java/org/apache/vxquery/datamodel/accessors/SequencePointable.java
+++ b/vxquery-core/src/main/java/org/apache/vxquery/datamodel/accessors/SequencePointable.java
@@ -24,8 +24,8 @@
import org.apache.hyracks.data.std.primitive.VoidPointable;
public class SequencePointable extends AbstractPointable {
- private static final int ENTRY_COUNT_SIZE = 4;
- private static final int SLOT_SIZE = 4;
+ private static final int ENTRY_COUNT_SIZE = IntegerPointable.TYPE_TRAITS.getFixedLength();
+ private static final int SLOT_SIZE = IntegerPointable.TYPE_TRAITS.getFixedLength();
public static final IPointableFactory FACTORY = new IPointableFactory() {
private static final long serialVersionUID = 1L;
@@ -77,4 +77,4 @@
private static int getDataAreaOffset(byte[] bytes, int start) {
return getSlotArrayOffset(start) + getEntryCount(bytes, start) * SLOT_SIZE;
}
-}
+}
\ No newline at end of file
diff --git a/vxquery-core/src/main/java/org/apache/vxquery/datamodel/accessors/jsonItem/ObjectPointable.java b/vxquery-core/src/main/java/org/apache/vxquery/datamodel/accessors/jsonItem/ObjectPointable.java
new file mode 100644
index 0000000..953a8fa
--- /dev/null
+++ b/vxquery-core/src/main/java/org/apache/vxquery/datamodel/accessors/jsonItem/ObjectPointable.java
@@ -0,0 +1,124 @@
+/*
+ * 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.vxquery.datamodel.accessors.jsonItem;
+
+import java.io.IOException;
+
+import org.apache.hyracks.api.dataflow.value.ITypeTraits;
+import org.apache.hyracks.data.std.api.AbstractPointable;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.data.std.api.IPointableFactory;
+import org.apache.hyracks.data.std.primitive.IntegerPointable;
+import org.apache.hyracks.data.std.primitive.UTF8StringPointable;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
+import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+import org.apache.vxquery.datamodel.builders.sequence.SequenceBuilder;
+import org.apache.vxquery.datamodel.values.ValueTag;
+import org.apache.vxquery.runtime.functions.util.FunctionHelper;
+
+/**
+ * The datamodel of the JSON object is represented in this class:
+ * Byte 1: Value tag of object (109)
+ * Byte 2 to 5: number of key-value pairs in the object
+ * Next few bytes: Offsets for each key-value pair in the object in the order appearing in the json data
+ * Next bytes: The keys in the object each followed by the value of the key. Each key is a StringPointable and the value
+ * of the key will be the respective pointable starting with its valuetag.
+ */
+public class ObjectPointable extends AbstractPointable {
+ public static final IPointableFactory FACTORY = new IPointableFactory() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public ITypeTraits getTypeTraits() {
+ return VoidPointable.TYPE_TRAITS;
+ }
+
+ @Override
+ public IPointable createPointable() {
+ return new ObjectPointable();
+ }
+ };
+ private static final int ENTRY_COUNT_SIZE = IntegerPointable.TYPE_TRAITS.getFixedLength();
+ private static final int SLOT_SIZE = IntegerPointable.TYPE_TRAITS.getFixedLength();
+ private final ArrayBackedValueStorage abvs = new ArrayBackedValueStorage();
+ private final SequenceBuilder sb = new SequenceBuilder();
+ private final UTF8StringPointable key1 = (UTF8StringPointable) UTF8StringPointable.FACTORY.createPointable();
+
+ private static int getSlotValue(byte[] bytes, int start, int idx) {
+ return IntegerPointable.getInteger(bytes, getSlotArrayOffset(start) + idx * SLOT_SIZE);
+ }
+
+ private static int getEntryCount(byte[] bytes, int start) {
+ return IntegerPointable.getInteger(bytes, start);
+ }
+
+ private static int getKeyLength(byte[] b, int s) {
+ return UTF8StringPointable.getUTFLength(b, s) + 2;
+ }
+
+ private static int getSlotArrayOffset(int start) {
+ return start + ENTRY_COUNT_SIZE;
+ }
+
+ private static int getDataAreaOffset(byte[] bytes, int start) {
+ return getSlotArrayOffset(start) + getEntryCount(bytes, start) * SLOT_SIZE;
+ }
+
+ public void getKeys(IPointable result) throws IOException {
+ abvs.reset();
+ sb.reset(abvs);
+ int dataAreaOffset = getDataAreaOffset(bytes, start);
+ int entryCount = getEntryCount();
+ int s;
+ for (int i = 0; i < entryCount; i++) {
+ s = dataAreaOffset + getRelativeEntryStartOffset(i);
+ key1.set(bytes, s, getKeyLength(bytes, s));
+ sb.addItem(ValueTag.XS_STRING_TAG, key1);
+ }
+ sb.finish();
+ result.set(abvs);
+ }
+
+ public boolean getValue(UTF8StringPointable key, IPointable result) {
+ int dataAreaOffset = getDataAreaOffset(bytes, start);
+ int entryCount = getEntryCount();
+ int start, length, i;
+ for (i = 0; i < entryCount; i++) {
+ start = dataAreaOffset + getRelativeEntryStartOffset(i);
+ length = getKeyLength(bytes, start);
+ if (FunctionHelper.arraysEqual(bytes, start, length, key.getByteArray(), key.getStartOffset(),
+ key.getLength())) {
+ result.set(bytes, start + length, getEntryLength(i) - length);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private int getRelativeEntryStartOffset(int idx) {
+ return idx == 0 ? 0 : getSlotValue(bytes, start, idx - 1);
+ }
+
+ private int getEntryLength(int idx) {
+ return getSlotValue(bytes, start, idx) - getRelativeEntryStartOffset(idx);
+ }
+
+ public int getEntryCount() {
+ return getEntryCount(bytes, start);
+ }
+
+}
diff --git a/vxquery-core/src/main/java/org/apache/vxquery/datamodel/builders/jsonItem/ObjectBuilder.java b/vxquery-core/src/main/java/org/apache/vxquery/datamodel/builders/jsonItem/ObjectBuilder.java
new file mode 100644
index 0000000..f4b7649
--- /dev/null
+++ b/vxquery-core/src/main/java/org/apache/vxquery/datamodel/builders/jsonItem/ObjectBuilder.java
@@ -0,0 +1,66 @@
+/*
+ * 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.vxquery.datamodel.builders.jsonItem;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.hyracks.data.std.api.IMutableValueStorage;
+import org.apache.hyracks.data.std.api.IValueReference;
+import org.apache.hyracks.data.std.primitive.UTF8StringPointable;
+import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+import org.apache.vxquery.datamodel.builders.base.AbstractBuilder;
+import org.apache.vxquery.datamodel.builders.base.IBuilder;
+import org.apache.vxquery.datamodel.values.ValueTag;
+import org.apache.vxquery.util.GrowableIntArray;
+
+public class ObjectBuilder extends AbstractBuilder implements IBuilder {
+ private final GrowableIntArray slots = new GrowableIntArray();
+ private final ArrayBackedValueStorage dataArea = new ArrayBackedValueStorage();
+ private IMutableValueStorage mvs;
+
+ public void reset(IMutableValueStorage mvs) {
+ this.mvs = mvs;
+ slots.clear();
+ dataArea.reset();
+ }
+
+ @Override
+ public int getValueTag() {
+ return ValueTag.OBJECT_TAG;
+ }
+
+ public void addItem(UTF8StringPointable key, IValueReference value) throws IOException {
+ dataArea.getDataOutput().write(key.getByteArray(), key.getStartOffset(), key.getLength());
+ dataArea.getDataOutput().write(value.getByteArray(), value.getStartOffset(), value.getLength());
+ slots.append(dataArea.getLength());
+ }
+
+ public void finish() throws IOException {
+ DataOutput out = mvs.getDataOutput();
+ out.write(ValueTag.OBJECT_TAG);
+ int size = slots.getSize();
+ out.writeInt(size);
+ if (size > 0) {
+ int[] slotArray = slots.getArray();
+ for (int i = 0; i < size; ++i) {
+ out.writeInt(slotArray[i]);
+ }
+ out.write(dataArea.getByteArray(), dataArea.getStartOffset(), dataArea.getLength());
+ }
+ }
+}
diff --git a/vxquery-core/src/main/java/org/apache/vxquery/datamodel/builders/sequence/SequenceBuilder.java b/vxquery-core/src/main/java/org/apache/vxquery/datamodel/builders/sequence/SequenceBuilder.java
index 5cd31b1..e347818 100644
--- a/vxquery-core/src/main/java/org/apache/vxquery/datamodel/builders/sequence/SequenceBuilder.java
+++ b/vxquery-core/src/main/java/org/apache/vxquery/datamodel/builders/sequence/SequenceBuilder.java
@@ -42,6 +42,12 @@
slots.append(dataArea.getLength());
}
+ public void addItem(int tagValue, IValueReference p) throws IOException {
+ dataArea.getDataOutput().write(tagValue);
+ dataArea.getDataOutput().write(p.getByteArray(), p.getStartOffset(), p.getLength());
+ slots.append(dataArea.getLength());
+ }
+
public void finish() throws IOException {
if (slots.getSize() != 1) {
out.write(ValueTag.SEQUENCE_TAG);
diff --git a/vxquery-core/src/main/java/org/apache/vxquery/datamodel/values/ValueTag.java b/vxquery-core/src/main/java/org/apache/vxquery/datamodel/values/ValueTag.java
index d2c8a9b..2e4d5c7 100644
--- a/vxquery-core/src/main/java/org/apache/vxquery/datamodel/values/ValueTag.java
+++ b/vxquery-core/src/main/java/org/apache/vxquery/datamodel/values/ValueTag.java
@@ -74,6 +74,8 @@
public static final int XS_NMTOKENS_TAG = BuiltinTypeConstants.XS_NMTOKENS_TYPE_ID;
public static final int XS_ENTITIES_TAG = BuiltinTypeConstants.XS_ENTITIES_TYPE_ID;
+ public static final int JS_NULL_TAG = BuiltinTypeConstants.JS_NULL_TYPE_ID;
+
public static final int SEQUENCE_TAG = 100;
public static final int DOCUMENT_NODE_TAG = 101;
public static final int ELEMENT_NODE_TAG = 102;
@@ -83,6 +85,7 @@
public static final int PI_NODE_TAG = 106;
public static final int NODE_TREE_TAG = 107;
public static final int ARRAY_TAG = 108;
+ public static final int OBJECT_TAG = 109;
public static boolean isAtomic(int tag) {
return tag < 100;
diff --git a/vxquery-core/src/main/java/org/apache/vxquery/datamodel/values/XDMConstants.java b/vxquery-core/src/main/java/org/apache/vxquery/datamodel/values/XDMConstants.java
index bc058c7..3dc7e9e 100644
--- a/vxquery-core/src/main/java/org/apache/vxquery/datamodel/values/XDMConstants.java
+++ b/vxquery-core/src/main/java/org/apache/vxquery/datamodel/values/XDMConstants.java
@@ -19,11 +19,10 @@
import java.io.IOException;
import java.util.Arrays;
-import org.apache.vxquery.datamodel.builders.sequence.SequenceBuilder;
-
import org.apache.hyracks.data.std.api.IPointable;
import org.apache.hyracks.data.std.primitive.BooleanPointable;
import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+import org.apache.vxquery.datamodel.builders.sequence.SequenceBuilder;
public class XDMConstants {
private static final byte[] BOOLEAN_TRUE_CONSTANT;
@@ -34,6 +33,8 @@
private static final byte[] EMPTY_STRING;
+ private static final byte[] JS_NULL_CONSTANT;
+
static {
BOOLEAN_TRUE_CONSTANT = new byte[2];
BOOLEAN_TRUE_CONSTANT[0] = ValueTag.XS_BOOLEAN_TAG;
@@ -52,11 +53,17 @@
throw new RuntimeException(e);
}
EMPTY_SEQUENCE = Arrays.copyOf(abvs.getByteArray(), abvs.getLength());
-
+
EMPTY_STRING = new byte[3];
EMPTY_STRING[0] = ValueTag.XS_STRING_TAG;
EMPTY_STRING[1] = 0;
EMPTY_STRING[2] = 0;
+
+ JS_NULL_CONSTANT = new byte[1];
+ JS_NULL_CONSTANT[0] = ValueTag.JS_NULL_TAG;
+ }
+
+ private XDMConstants() {
}
public static void setTrue(IPointable p) {
@@ -75,10 +82,11 @@
set(p, EMPTY_STRING);
}
- private static void set(IPointable p, byte[] array) {
- p.set(array, 0, array.length);
+ public static void setJsNull(IPointable p) {
+ set(p, JS_NULL_CONSTANT);
}
- private XDMConstants() {
+ private static void set(IPointable p, byte[] array) {
+ p.set(array, 0, array.length);
}
}
diff --git a/vxquery-core/src/main/java/org/apache/vxquery/types/BuiltinTypeConstants.java b/vxquery-core/src/main/java/org/apache/vxquery/types/BuiltinTypeConstants.java
index eefebcc..5ac51ec 100644
--- a/vxquery-core/src/main/java/org/apache/vxquery/types/BuiltinTypeConstants.java
+++ b/vxquery-core/src/main/java/org/apache/vxquery/types/BuiltinTypeConstants.java
@@ -72,5 +72,7 @@
public static final int XS_NMTOKENS_TYPE_ID = 50;
public static final int XS_ENTITIES_TYPE_ID = 51;
- public static final int BUILTIN_TYPE_COUNT = 52;
+ public static final int JS_NULL_TYPE_ID = 52;
+
+ public static final int BUILTIN_TYPE_COUNT = 53;
}
diff --git a/vxquery-core/src/test/java/org/apache/vxquery/datamodel/AbstractPointableTest.java b/vxquery-core/src/test/java/org/apache/vxquery/datamodel/AbstractPointableTest.java
index fa4e831..d3de095 100644
--- a/vxquery-core/src/test/java/org/apache/vxquery/datamodel/AbstractPointableTest.java
+++ b/vxquery-core/src/test/java/org/apache/vxquery/datamodel/AbstractPointableTest.java
@@ -25,6 +25,7 @@
public class AbstractPointableTest {
private final ArrayBackedValueStorage abvsInput = new ArrayBackedValueStorage();
private final StringValueBuilder svb = new StringValueBuilder();
+ private boolean includeTag = true;
protected void getTaggedValuePointable(Object value, IPointable result) throws IOException {
int start = abvsInput.getLength();
@@ -42,23 +43,36 @@
result.set(abvsInput.getByteArray(), start, abvsInput.getLength() - start);
}
+ protected void getTaggedValuePointable(Object value, boolean includeTag, IPointable result) throws IOException {
+ this.includeTag = includeTag;
+ getTaggedValuePointable(value, result);
+ }
+
protected void writeInteger(Integer value, DataOutput dOut) throws IOException {
- dOut.write(ValueTag.XS_INT_TAG);
+ if (includeTag) {
+ dOut.write(ValueTag.XS_INT_TAG);
+ }
dOut.writeInt(value);
}
protected void writeLong(Long value, DataOutput dOut) throws IOException {
- dOut.write(ValueTag.XS_LONG_TAG);
+ if (includeTag) {
+ dOut.write(ValueTag.XS_LONG_TAG);
+ }
dOut.writeLong(value);
}
protected void writeDouble(Double value, DataOutput dOut) throws IOException {
- dOut.write(ValueTag.XS_DOUBLE_TAG);
+ if (includeTag) {
+ dOut.write(ValueTag.XS_DOUBLE_TAG);
+ }
dOut.writeDouble(value);
}
protected void writeString(String value, DataOutput dOut) throws IOException {
- dOut.write(ValueTag.XS_STRING_TAG);
+ if (includeTag) {
+ dOut.write(ValueTag.XS_STRING_TAG);
+ }
svb.write(value, dOut);
}
diff --git a/vxquery-core/src/test/java/org/apache/vxquery/datamodel/ObjectByteTest.java b/vxquery-core/src/test/java/org/apache/vxquery/datamodel/ObjectByteTest.java
new file mode 100644
index 0000000..4bdb503
--- /dev/null
+++ b/vxquery-core/src/test/java/org/apache/vxquery/datamodel/ObjectByteTest.java
@@ -0,0 +1,264 @@
+/*
+ * 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.vxquery.datamodel;
+
+import java.io.IOException;
+
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.data.std.primitive.UTF8StringPointable;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
+import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+import org.apache.vxquery.datamodel.accessors.SequencePointable;
+import org.apache.vxquery.datamodel.accessors.TaggedValuePointable;
+import org.apache.vxquery.datamodel.accessors.jsonItem.ObjectPointable;
+import org.apache.vxquery.datamodel.builders.jsonItem.ObjectBuilder;
+import org.apache.vxquery.datamodel.values.ValueTag;
+import org.apache.vxquery.runtime.functions.util.FunctionHelper;
+import org.junit.Test;
+
+import junit.framework.Assert;
+
+public class ObjectByteTest extends AbstractPointableTest {
+ private ArrayBackedValueStorage abvsResult = new ArrayBackedValueStorage();
+ private ObjectBuilder ob = new ObjectBuilder();
+ private TaggedValuePointable tvp = (TaggedValuePointable) TaggedValuePointable.FACTORY.createPointable();
+ private UTF8StringPointable tvpKey1 = (UTF8StringPointable) UTF8StringPointable.FACTORY.createPointable();
+ private TaggedValuePointable tvpValue1 = (TaggedValuePointable) TaggedValuePointable.FACTORY.createPointable();
+ private UTF8StringPointable tvpKey2 = (UTF8StringPointable) UTF8StringPointable.FACTORY.createPointable();
+ private TaggedValuePointable tvpValue2 = (TaggedValuePointable) TaggedValuePointable.FACTORY.createPointable();
+ private UTF8StringPointable tvpKey3 = (UTF8StringPointable) UTF8StringPointable.FACTORY.createPointable();
+ private TaggedValuePointable tvpValue3 = (TaggedValuePointable) TaggedValuePointable.FACTORY.createPointable();
+ private SequencePointable sp = (SequencePointable) SequencePointable.FACTORY.createPointable();
+ private ObjectPointable op = (ObjectPointable) ObjectPointable.FACTORY.createPointable();
+ private IPointable vp = VoidPointable.FACTORY.createPointable();
+
+ @Test
+ public void testEmptyObject() {
+ // Build test Object
+ abvsResult.reset();
+ try {
+ ob.reset(abvsResult);
+ ob.finish();
+ } catch (IOException e) {
+ Assert.fail("Test failed to write the Object pointable.");
+ }
+ tvp.set(abvsResult);
+
+ // Check results.
+ if (tvp.getTag() != ValueTag.OBJECT_TAG) {
+ Assert.fail("Type tag is incorrect. Expected: " + ValueTag.OBJECT_TAG + " Got: " + tvp.getTag());
+ }
+ tvp.getValue(op);
+ if (op.getEntryCount() != 0) {
+ Assert.fail("Object size is incorrect. Expected: 0 Got: " + op.getEntryCount());
+ }
+ }
+
+ @Test
+ public void testSingleItemObject() {
+ // Build test Object
+ abvsResult.reset();
+ try {
+ ob.reset(abvsResult);
+ getTaggedValuePointable("id", false, tvpKey1);
+ getTaggedValuePointable(1, tvpValue1);
+ ob.addItem(tvpKey1, tvpValue1);
+ ob.finish();
+ } catch (IOException e) {
+ Assert.fail("Test failed to write the object pointable.");
+ }
+ tvp.set(abvsResult);
+
+ // Check results.
+ if (tvp.getTag() != ValueTag.OBJECT_TAG) {
+ Assert.fail("Type tag is incorrect. Expected: " + ValueTag.OBJECT_TAG + " Got: " + tvp.getTag());
+ }
+
+ tvp.getValue(op);
+ if (op.getEntryCount() != 1) {
+ Assert.fail("Object size is incorrect. Expected: 1 Got: " + op.getEntryCount());
+ }
+ try {
+ op.getKeys(tvp);
+ } catch (IOException e) {
+ Assert.fail("Test failed to write the object pointable.");
+ }
+ if (tvp.getTag() != ValueTag.XS_STRING_TAG) {
+ Assert.fail("Type tag is incorrect. Expected: " + ValueTag.XS_STRING_TAG + " Got: " + tvp.getTag());
+ }
+ if (!compareKeys(tvp, tvpKey1)) {
+ Assert.fail("Key is incorrect. Expected: id");
+ }
+
+ if (!op.getValue(tvpKey1, tvp)) {
+ Assert.fail("Value not found for the given key:id");
+ }
+ if (!FunctionHelper.arraysEqual(tvp, tvpValue1)) {
+ Assert.fail("Value is incorrect for the given key. Expected: 1 with valuetag: " + ValueTag.XS_INT_TAG
+ + " Got valuetag: " + tvp.getTag());
+ }
+ }
+
+ @Test
+ public void testManyItemObject() {
+ // Build test object
+ try {
+ // Add three items
+ ob.reset(abvsResult);
+ getTaggedValuePointable("name", false, tvpKey1);
+ getTaggedValuePointable("A green door", tvpValue1);
+ ob.addItem(tvpKey1, tvpValue1);
+ getTaggedValuePointable("price", false, tvpKey2);
+ getTaggedValuePointable(12.5, tvpValue2);
+ ob.addItem(tvpKey2, tvpValue2);
+ getTaggedValuePointable("properties", false, tvpKey3);
+ getTaggedValuePointable(100L, tvpValue3);
+ ob.addItem(tvpKey3, tvpValue3);
+ ob.finish();
+ } catch (IOException e) {
+ Assert.fail("Test failed to write the object pointable.");
+ }
+ tvp.set(abvsResult);
+
+ // Check results.
+ if (tvp.getTag() != ValueTag.OBJECT_TAG) {
+ Assert.fail("Type tag is incorrect. Expected: " + ValueTag.OBJECT_TAG + " Got: " + tvp.getTag());
+ }
+ tvp.getValue(op);
+ if (op.getEntryCount() != 3) {
+ Assert.fail("Object size is incorrect. Expected: 3 Got: " + op.getEntryCount());
+ }
+
+ //Test keys
+ try {
+ op.getKeys(tvp);
+ } catch (IOException e) {
+ Assert.fail("Test failed to write the object pointable.");
+ }
+
+ if (tvp.getTag() != ValueTag.SEQUENCE_TAG) {
+ Assert.fail("Tag type is incorrect. Expected: " + ValueTag.SEQUENCE_TAG + " Got: " + tvp.getTag());
+ }
+ tvp.getValue(sp);
+ if (sp.getEntryCount() != 3) {
+ Assert.fail("Object size is incorrect. Expected: 3 Got: " + sp.getEntryCount());
+ }
+ sp.getEntry(0, tvp);
+ if (tvp.getTag() != ValueTag.XS_STRING_TAG) {
+ Assert.fail("Type tag is incorrect. Expected: " + ValueTag.XS_STRING_TAG + " Got: " + tvp.getTag());
+ }
+ if (!compareKeys(tvp, tvpKey1)) {
+ Assert.fail("Object key one is incorrect. Expected: name");
+ }
+ sp.getEntry(1, tvp);
+ if (tvp.getTag() != ValueTag.XS_STRING_TAG) {
+ Assert.fail("Type tag is incorrect. Expected: " + ValueTag.XS_STRING_TAG + " Got: " + tvp.getTag());
+ }
+ if (!compareKeys(tvp, tvpKey2)) {
+ Assert.fail("Object key two is incorrect. Expected: price");
+ }
+ sp.getEntry(2, tvp);
+ if (tvp.getTag() != ValueTag.XS_STRING_TAG) {
+ Assert.fail("Type tag is incorrect. Expected: " + ValueTag.XS_STRING_TAG + " Got: " + tvp.getTag());
+ }
+ if (!compareKeys(tvp, tvpKey3)) {
+ Assert.fail("Object key three is incorrect. Expected: properties");
+ }
+
+ //Test values
+ if (!op.getValue(tvpKey1, tvp)) {
+ Assert.fail("Value not found for the given key: name");
+ }
+ if (!FunctionHelper.arraysEqual(tvp, tvpValue1)) {
+ Assert.fail("Value is incorrect for the given key. Expected: A green door with valuetag: "
+ + ValueTag.XS_STRING_TAG + " Got valuetag: " + tvp.getTag());
+ }
+
+ if (!op.getValue(tvpKey2, tvp)) {
+ Assert.fail("Value not found for the given key: price");
+ }
+ if (!FunctionHelper.arraysEqual(tvp, tvpValue2)) {
+ Assert.fail("Value is incorrect for the given key. Expected: 12.5 with valuetag: " + ValueTag.XS_DOUBLE_TAG
+ + " Got valuetag: " + tvp.getTag());
+ }
+
+ if (!op.getValue(tvpKey3, tvp)) {
+ Assert.fail("Value not found for the given key: properties");
+ }
+ if (!FunctionHelper.arraysEqual(tvp, tvpValue3)) {
+ Assert.fail("Value is incorrect for the given key. Expected: 100 with valuetag: " + ValueTag.XS_LONG_TAG
+ + " Got valuetag: " + tvp.getTag());
+ }
+ }
+
+ @Test
+ public void testItemNotExistObject() {
+ // Build empty test Object
+ abvsResult.reset();
+ try {
+ ob.reset(abvsResult);
+ ob.finish();
+ } catch (IOException e) {
+ Assert.fail("Test failed to write the Object pointable.");
+ }
+ tvp.set(abvsResult);
+ tvp.getValue(op);
+ try {
+ getTaggedValuePointable("key", false, tvpKey1);
+ if (op.getValue(tvpKey1, tvp)) {
+ Assert.fail("key not in object. Expected: false Got: true");
+ }
+ } catch (IOException e) {
+ Assert.fail("Test failed to write the object pointable.");
+ }
+
+ // Build test object
+ try {
+ // Add two items
+ abvsResult.reset();
+ ob.reset(abvsResult);
+ getTaggedValuePointable("name", false, tvpKey1);
+ getTaggedValuePointable("A green door", tvpValue1);
+ ob.addItem(tvpKey1, tvpValue1);
+ getTaggedValuePointable("price", false, tvpKey2);
+ getTaggedValuePointable(12.5, tvpValue2);
+ ob.addItem(tvpKey2, tvpValue2);
+ ob.finish();
+ } catch (IOException e) {
+ Assert.fail("Test failed to write the object pointable.");
+ }
+
+ tvp.set(abvsResult);
+ tvp.getValue(op);
+ try {
+ getTaggedValuePointable("key", false, tvpKey3);
+ if (op.getValue(tvpKey3, tvp)) {
+ Assert.fail("key not in object. Expected: false Got: true");
+ }
+
+ if (!op.getValue(tvpKey1, tvp)) {
+ Assert.fail("key in object. Expected: true Got: false");
+ }
+ } catch (IOException e) {
+ Assert.fail("Test failed to write the object pointable.");
+ }
+ }
+
+ private boolean compareKeys(TaggedValuePointable tvp1, IPointable tvp2) {
+ tvp1.getValue(vp);
+ return FunctionHelper.arraysEqual(vp.getByteArray(), vp.getStartOffset(), vp.getLength(), tvp2.getByteArray(),
+ tvp2.getStartOffset(), tvp2.getLength());
+ }
+}