This is an automated email from the ASF dual-hosted git repository.
Cole-Greer pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/master by this push:
new 795594a107 Update GraphBinary/GraphSON model test coverage (#3526)
795594a107 is described below
commit 795594a1070ec35672a4096b81a2ebb589b72efa
Author: Ken Hu <[email protected]>
AuthorDate: Mon Jul 20 10:25:02 2026 -0700
Update GraphBinary/GraphSON model test coverage (#3526)
These changes update the model tests by removing stale tests, adding more
tests for existing types and new tests for newly supported types.
* Fix empty_bulklist typo in test_graphbinaryv4model.py
* Remove stale model test references to removed Traverser type
* Update GraphBinary/GraphSON model round-trip coverage.
Assisted-by: Codex:gpt-5.5
---
docs/src/reference/gremlin-variants.asciidoc | 22 +-
.../io/graphson/PdtGraphSONSerializersV4.java | 14 +-
.../io/graphson/PdtGraphSONSerializersV4Test.java | 27 +-
.../Structure/IO/GraphBinary4/Model.cs | 162 ++++++++++-
.../Structure/IO/GraphBinary4/RoundTripTests.cs | 262 +++++++++++++++++-
.../structure/io/binary/internals/MapSerializer.js | 2 +-
.../test/unit/graphbinary/model-test.js | 157 ++++++++---
.../test/unit/graphbinary/model.js | 140 +++++++++-
.../gremlin_python/structure/io/graphbinaryV4.py | 2 +-
.../main/python/tests/unit/structure/io/model.py | 135 ++++++++-
.../unit/structure/io/test_graphbinaryv4model.py | 192 +++++++++++--
.../GremlinServerSerializationIntegrateTest.java | 7 +-
.../io/graphbinary/empty-label-vertex-v4.gbin | Bin 0 -> 18 bytes
.../structure/io/graphbinary/empty-string-v4.gbin | Bin 0 -> 6 bytes
.../structure/io/graphbinary/empty-tree-v4.gbin | Bin 0 -> 6 bytes
.../io/graphbinary/four-byte-char-v4.gbin | Bin 0 -> 6 bytes
.../structure/io/graphbinary/merge-in-v-v4.gbin | Bin 0 -> 11 bytes
.../io/graphbinary/merge-on-create-v4.gbin | Bin 0 -> 16 bytes
.../io/graphbinary/merge-on-match-v4.gbin | Bin 0 -> 15 bytes
.../structure/io/graphbinary/merge-out-v-v4.gbin | Bin 0 -> 12 bytes
.../io/graphbinary/multi-label-vertex-v4.gbin | Bin 0 -> 44 bytes
.../io/graphbinary/nanos-duration-v4.gbin | Bin 0 -> 14 bytes
.../io/graphbinary/negative-duration-v4.gbin | Bin 0 -> 14 bytes
.../graphbinary/negative-scale-bigdecimal-v4.gbin | Bin 0 -> 12 bytes
.../structure/io/graphbinary/null-int-v4.gbin | 1 +
.../structure/io/graphbinary/null-list-v4.gbin | 1 +
.../structure/io/graphbinary/null-long-v4.gbin | 1 +
.../structure/io/graphbinary/null-map-v4.gbin | 2 +
.../structure/io/graphbinary/null-set-v4.gbin | 1 +
.../structure/io/graphbinary/null-string-v4.gbin | 1 +
.../io/graphbinary/ordered-string-int-map-v4.gbin | Bin 0 -> 111 bytes
.../io/graphbinary/path-multiple-labels-v4.gbin | Bin 0 -> 45 bytes
.../io/graphbinary/path-zero-labels-v4.gbin | Bin 0 -> 31 bytes
.../io/graphbinary/point-composite-pdt-v4.gbin | Bin 0 -> 45 bytes
.../io/graphbinary/positive-duration-v4.gbin | Bin 0 -> 14 bytes
.../io/graphbinary/scale-zero-bigdecimal-v4.gbin | Bin 0 -> 12 bytes
.../sign-boundary-neg-biginteger-v4.gbin | Bin 0 -> 8 bytes
.../sign-boundary-pos-biginteger-v4.gbin | Bin 0 -> 8 bytes
.../graphbinary/small-decimal-bigdecimal-v4.gbin | Bin 0 -> 12 bytes
.../io/graphbinary/three-byte-char-v4.gbin | Bin 0 -> 5 bytes
.../io/graphbinary/tree-deep-nesting-v4.gbin | Bin 0 -> 50 bytes
.../io/graphbinary/tree-mixed-key-types-v4.gbin | Bin 0 -> 30 bytes
.../structure/io/graphbinary/tree-null-key-v4.gbin | Bin 0 -> 12 bytes
...lti-byte-char-v4.gbin => two-byte-char-v4.gbin} | Bin
.../io/graphbinary/uint8-primitive-pdt-v4.gbin | Bin 0 -> 21 bytes
.../io/graphbinary/zero-bigdecimal-v4.gbin | Bin 0 -> 11 bytes
.../io/graphbinary/zero-biginteger-v4.gbin | Bin 0 -> 7 bytes
.../io/graphson/empty-label-vertex-v4.json | 10 +
.../structure/io/graphson/empty-string-v4.json | 1 +
.../structure/io/graphson/merge-in-v-v4.json | 4 +
.../structure/io/graphson/merge-on-create-v4.json | 4 +
.../structure/io/graphson/merge-on-match-v4.json | 4 +
.../structure/io/graphson/merge-out-v-v4.json | 4 +
.../io/graphson/multi-label-vertex-v4.json | 10 +
.../structure/io/graphson/nanos-duration-v4.json | 4 +
.../io/graphson/negative-duration-v4.json | 4 +
.../io/graphson/negative-scale-bigdecimal-v4.json | 4 +
.../io/graphson/ordered-string-int-map-v4.json | 22 ++
.../io/graphson/path-multiple-labels-v4.json | 16 ++
.../structure/io/graphson/path-zero-labels-v4.json | 16 ++
.../io/graphson/point-composite-pdt-v4.json | 16 ++
.../io/graphson/positive-duration-v4.json | 4 +
.../io/graphson/scale-zero-bigdecimal-v4.json | 4 +
.../graphson/sign-boundary-neg-biginteger-v4.json | 4 +
.../graphson/sign-boundary-pos-biginteger-v4.json | 4 +
.../io/graphson/small-decimal-bigdecimal-v4.json | 4 +
...i-byte-char-v4.json => three-byte-char-v4.json} | 2 +-
...lti-byte-char-v4.json => two-byte-char-v4.json} | 0
.../io/graphson/uint8-primitive-pdt-v4.json | 7 +
.../structure/io/graphson/zero-bigdecimal-v4.json | 4 +
.../structure/io/graphson/zero-biginteger-v4.json | 4 +
.../io/AbstractTypedCompatibilityTest.java | 304 ++++++++++++++++++++-
.../tinkerpop/gremlin/structure/io/Model.java | 81 +++++-
.../graphbinary/GraphBinaryCompatibilityTest.java | 104 +++++++
74 files changed, 1650 insertions(+), 124 deletions(-)
diff --git a/docs/src/reference/gremlin-variants.asciidoc
b/docs/src/reference/gremlin-variants.asciidoc
index eab512a14f..885e4866c4 100644
--- a/docs/src/reference/gremlin-variants.asciidoc
+++ b/docs/src/reference/gremlin-variants.asciidoc
@@ -737,6 +737,11 @@ that can be used to fulfill the `gremlingo.Set` interface
if desired.
* Go does not support ordered maps natively as the built-in `map` type does
not guarantee iteration order. Traversal
results which contain maps may not preserve original ordering when
deserialized into Go's native map types.
+* GraphBinary `Char` values are not supported.
+
+* GraphBinary permits map keys of any supported type, including composite
values such as lists. Go's native `map` type
+only supports comparable keys, so GraphBinary maps with non-comparable keys
are not supported.
+
* The `subgraph()`-step returns a detached `*Graph` data container exposing
`Vertices map[interface{}]*Vertex` and `Edges map[interface{}]*Edge`. The
result is not a live `Graph` instance:
mutating the maps has no effect on the source graph, and it cannot be passed
to `traversal().with(...)`. To
@@ -1265,6 +1270,12 @@ The driver streams and deserializes a response
incrementally as it arrives only
is configured, which is the default. Any other `MessageSerializer`, such as a
GraphSON serializer, causes the driver to
buffer the full response body before deserializing it.
+[[gremlin-java-limitations]]
+=== Limitations
+
+* Java `Character` values do not support values outside the Basic Multilingual
Plane, which are mainly 4-byte UTF-8
+characters. Those GraphBinary `Char` values are not supported.
+
[[gremlin-java-gvalue]]
=== GValue Parameterization
@@ -2507,12 +2518,15 @@ unwrap('hello'); // 'hello'
* JavaScript's `Number` type is an IEEE 754 double-precision float. `Float`,
`Byte`, and `Short` values from the server
are deserialized as `Number` and lose their original type information. Use
`preciseNumbers: true` to preserve the
-original types — see <<gremlin-javascript-numeric-types>>.
+original types. See <<gremlin-javascript-numeric-types>>.
* `Long` values outside the safe integer range (|n| > 2^53 - 1) are
deserialized as `BigInt` to preserve precision.
Values within the safe range are deserialized as `Number`. The same server
type may produce different JavaScript types.
* `Number.isInteger(1.0)` is `true` in JavaScript, so the driver cannot
distinguish integer values from whole-number
-doubles. `BigDecimal` is not implemented. Typed wrappers (e.g. `toInt()`,
`toDouble()`) can be used to control the
-exact type sent to the server — see <<gremlin-javascript-numeric-types>>.
+doubles. Typed wrappers (e.g. `toInt()`, `toDouble()`) can be used to control
the exact type sent to the server. See
+<<gremlin-javascript-numeric-types>>.
+* GraphBinary `BigDecimal`, `Char`, and `Duration` values are not implemented.
+* JavaScript `Date` values do not support the extreme values of GraphBinary's
`DateTime` maximum and minimum. Those
+GraphBinary `DateTime` values are not supported.
* The driver applies GremlinLang type suffixes automatically based on value
characteristics: integers within the 32-bit
signed range are unsuffixed (Int), integers beyond that up to
`Number.MAX_SAFE_INTEGER` use the `L` suffix (Long),
non-integer numbers and integers beyond the safe range use the `D` suffix
(Double), and `BigInt` values use the `N`
@@ -3144,6 +3158,8 @@ so offset date-time values at those boundaries will fail
to deserialize.
`Duration.FOREVER`) that exceed `TimeSpan.MaxValue` or `TimeSpan.MinValue`
will fail to deserialize.
* Gremlin's `BigDecimal` supports up to 33 digits of precision while C#'s
`decimal` type is limited to 28-29
significant digits, so high-precision values may lose accuracy or fail to
deserialize.
+* C# `char` values do not support values outside the Basic Multilingual Plane,
which are mainly 4-byte UTF-8
+characters. Those GraphBinary `Char` values are not supported.
* C# `Dictionary` does not allow `null` keys, so `Map` results with `null`
keys (e.g. from `group()` or
`groupCount()` on a missing property) will fail during deserialization.
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4.java
index a4bcd391ad..f9652b2591 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4.java
@@ -57,12 +57,7 @@ final class PdtGraphSONSerializersV4 {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("type", pdt.getName());
jsonGenerator.writeFieldName("fields");
- jsonGenerator.writeStartObject();
- for (final Map.Entry<String, Object> entry :
pdt.getFields().entrySet()) {
- jsonGenerator.writeFieldName(entry.getKey());
- jsonGenerator.writeObject(entry.getValue());
- }
- jsonGenerator.writeEndObject();
+ jsonGenerator.writeObject(pdt.getFields());
jsonGenerator.writeEndObject();
}
}
@@ -92,12 +87,7 @@ final class PdtGraphSONSerializersV4 {
typeName = jsonParser.getText();
} else if ("fields".equals(fieldName)) {
jsonParser.nextToken();
- while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
- final String key = jsonParser.getCurrentName();
- jsonParser.nextToken();
- final Object value =
deserializationContext.readValue(jsonParser, Object.class);
- fields.put(key, value);
- }
+ fields = deserializationContext.readValue(jsonParser,
Map.class);
}
}
diff --git
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4Test.java
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4Test.java
index 6da520d0e0..f153e95ce4 100644
---
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4Test.java
+++
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4Test.java
@@ -70,15 +70,18 @@ public class PdtGraphSONSerializersV4Test extends
AbstractGraphSONTest {
assertEquals("Point", value.get("type").asText());
final JsonNode fields = value.get("fields");
- assertEquals("g:Int32", fields.get("x").get("@type").asText());
- assertEquals(1, fields.get("x").get("@value").asInt());
- assertEquals("g:Int32", fields.get("y").get("@type").asText());
- assertEquals(2, fields.get("y").get("@value").asInt());
+ assertEquals("g:Map", fields.get("@type").asText());
+ final JsonNode x = getMapValue(fields, "x");
+ assertEquals("g:Int32", x.get("@type").asText());
+ assertEquals(1, x.get("@value").asInt());
+ final JsonNode y = getMapValue(fields, "y");
+ assertEquals("g:Int32", y.get("@type").asText());
+ assertEquals(2, y.get("@value").asInt());
}
@Test
public void shouldDeserializeValidJson() throws Exception {
- final String json =
"{\"@type\":\"g:CompositePdt\",\"@value\":{\"type\":\"Point\",\"fields\":{\"x\":{\"@type\":\"g:Int32\",\"@value\":1},\"y\":{\"@type\":\"g:Int32\",\"@value\":2}}}}";
+ final String json =
"{\"@type\":\"g:CompositePdt\",\"@value\":{\"type\":\"Point\",\"fields\":{\"@type\":\"g:Map\",\"@value\":[\"x\",{\"@type\":\"g:Int32\",\"@value\":1},\"y\",{\"@type\":\"g:Int32\",\"@value\":2}]}}}";
final CompositePDT pdt = mapper.readValue(json, CompositePDT.class);
assertEquals("Point", pdt.getName());
@@ -117,7 +120,7 @@ public class PdtGraphSONSerializersV4Test extends
AbstractGraphSONTest {
assertEquals("g:CompositePdt", node.get("@type").asText());
final JsonNode fields = node.get("@value").get("fields");
- final JsonNode locationNode = fields.get("location");
+ final JsonNode locationNode = getMapValue(fields, "location");
assertEquals("g:CompositePdt", locationNode.get("@type").asText());
assertEquals("Point", locationNode.get("@value").get("type").asText());
@@ -318,7 +321,7 @@ public class PdtGraphSONSerializersV4Test extends
AbstractGraphSONTest {
final JsonNode node = plainMapper.readTree(json);
assertEquals("g:CompositePdt", node.get("@type").asText());
- final JsonNode durNode = node.get("@value").get("fields").get("dur");
+ final JsonNode durNode = getMapValue(node.get("@value").get("fields"),
"dur");
assertEquals("g:PrimitivePdt", durNode.get("@type").asText());
assertEquals("Duration", durNode.get("@value").get("type").asText());
assertEquals("PT1H", durNode.get("@value").get("value").asText());
@@ -332,6 +335,16 @@ public class PdtGraphSONSerializersV4Test extends
AbstractGraphSONTest {
assertEquals("PT1H", nestedResult.getValue());
}
+ private JsonNode getMapValue(final JsonNode graphsonMap, final String key)
{
+ final JsonNode values = graphsonMap.get("@value");
+ for (int ix = 0; ix < values.size(); ix = ix + 2) {
+ if (key.equals(values.get(ix).asText()))
+ return values.get(ix + 1);
+ }
+
+ throw new IllegalArgumentException("Could not find key in GraphSON
map: " + key);
+ }
+
// helper types for primitive PDT hydration tests
static class MyDuration {
diff --git
a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary4/Model.cs
b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary4/Model.cs
index bc92428e9d..b161044af2 100644
---
a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary4/Model.cs
+++
b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary4/Model.cs
@@ -23,6 +23,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Numerics;
using Gremlin.Net.Process.Traversal;
using Gremlin.Net.Structure;
@@ -33,12 +34,12 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
/// Defines the supported types for GraphBinary 4.0 IO and provides test
entries for round-trip testing.
///
/// The following models aren't supported:
- /// tinker-graph Graph type not implemented
/// max-offsetdatetime DateTimeOffset.MaxValue exceeds
serialization range
/// min-offsetdatetime DateTimeOffset.MinValue exceeds
serialization range
/// forever-duration TimeSpan cannot represent Duration.FOREVER
/// pos-bigdecimal Java BigDecimal precision (33 digits)
exceeds C# decimal (28-29 digits)
/// neg-bigdecimal Java BigDecimal precision (33 digits)
exceeds C# decimal (28-29 digits)
+ /// four-byte-char C# char cannot represent a supplementary
Unicode code point as a single scalar value
/// var-type-map Dictionary doesn't support null key
/// </summary>
public static class Model
@@ -70,11 +71,50 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
return tree;
}
+ private static Tree BuildNullKeyTree()
+ {
+ var tree = new Tree();
+ tree.GetOrCreateChild(null);
+ return tree;
+ }
+
+ private static Tree BuildMixedKeyTypesTree()
+ {
+ var tree = new Tree();
+ tree.GetOrCreateChild("name");
+ tree.GetOrCreateChild(123);
+ return tree;
+ }
+
+ private static Tree BuildDeepNestingTree()
+ {
+ var tree = new Tree();
+
tree.GetOrCreateChild("root").GetOrCreateChild("branch").GetOrCreateChild("leaf");
+ return tree;
+ }
+
public static Dictionary<string, object?> Entries { get; } = new()
{
+ // BigDecimal
+ ["zero-bigdecimal"] = 0m,
+ ["scale-zero-bigdecimal"] = 1234m,
+ ["negative-scale-bigdecimal"] = 123400m,
+ ["small-decimal-bigdecimal"] = 12.34m,
+
// BigInteger
["pos-biginteger"] =
BigInteger.Parse("123456789987654321123456789987654321"),
["neg-biginteger"] =
BigInteger.Parse("-123456789987654321123456789987654321"),
+ ["zero-biginteger"] = BigInteger.Zero,
+ ["sign-boundary-pos-biginteger"] = new BigInteger(128),
+ ["sign-boundary-neg-biginteger"] = new BigInteger(-129),
+
+ // Provider-defined types
+ ["uint8-primitive-pdt"] = new PrimitivePDT("Uint8", "10"),
+ ["point-composite-pdt"] = new CompositePDT("Point", new
Dictionary<string, object?>
+ {
+ { "x", 1 },
+ { "y", 2 },
+ }),
// Byte (sbyte in C#)
["min-byte"] = sbyte.MinValue, // -128
@@ -108,10 +148,17 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
// Char
["single-byte-char"] = 'a',
- ["multi-byte-char"] = '\u03A9', // Greek capital letter Omega
+ ["two-byte-char"] = '\u03A9', // Greek capital letter Omega
+ ["three-byte-char"] = '\u20AC',
// Null
["unspecified-null"] = null,
+ ["null-int"] = null,
+ ["null-long"] = null,
+ ["null-string"] = null,
+ ["null-list"] = null,
+ ["null-map"] = null,
+ ["null-set"] = null,
// Boolean
["true-boolean"] = true,
@@ -120,6 +167,7 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
// String
["single-byte-string"] = "abc",
["mixed-string"] = "abc\u0391\u0392\u0393", // abc + Greek
letters Alpha, Beta, Gamma
+ ["empty-string"] = "",
// BulkSet (represented as List with duplicates)
["var-bulklist"] = new List<object?> { "marko", "josh", "josh" },
@@ -127,11 +175,15 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
// Duration (TimeSpan)
["zero-duration"] = TimeSpan.Zero,
+ ["positive-duration"] = TimeSpan.FromSeconds(123),
+ ["negative-duration"] = TimeSpan.FromSeconds(-123),
+ ["nanos-duration"] = TimeSpan.FromSeconds(123) +
TimeSpan.FromTicks(4567),
// Edge
["traversal-edge"] = new Edge(13, new Vertex(1, "person"),
"develops", new Vertex(10, "software"),
new dynamic[] { SinceProperty }),
["no-prop-edge"] = new Edge(13, new Vertex(1, "person"),
"develops", new Vertex(10, "software")),
+ ["tinker-graph"] = CrewGraphFactory.Create(),
// Int
["max-int"] = int.MaxValue,
@@ -154,16 +206,34 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
// Note: null key not supported in C# Dictionary
},
["empty-map"] = new Dictionary<object, object?>(),
+ ["ordered-string-int-map"] = new Dictionary<object, object?>
+ {
+ { "delta", 4 },
+ { "alpha", 1 },
+ { "charlie", 3 },
+ { "bravo", 2 },
+ { "echo", 5 },
+ { "foxtrot", 6 },
+ },
// Path
["traversal-path"] = new Path(
new List<ISet<string>> { new HashSet<string>(), new
HashSet<string>(), new HashSet<string>() },
new List<object?> { new Vertex(1, "person"), new Vertex(10,
"software"), new Vertex(11, "software") }),
["empty-path"] = new Path(new List<ISet<string>>(), new
List<object?>()),
+ ["path-zero-labels"] = new Path(
+ new List<ISet<string>> { new HashSet<string>() },
+ new List<object?> { "marko" }),
+ ["path-multiple-labels"] = new Path(
+ new List<ISet<string>> { new HashSet<string> { "a", "b" } },
+ new List<object?> { "marko" }),
// Tree
["traversal-tree"] = BuildTraversalTree(),
["empty-tree"] = new Tree(),
+ ["tree-null-key"] = BuildNullKeyTree(),
+ ["tree-mixed-key-types"] = BuildMixedKeyTypesTree(),
+ ["tree-deep-nesting"] = BuildDeepNestingTree(),
["prop-path"] = new Path(
new List<ISet<string>> { new HashSet<string>(), new
HashSet<string>(), new HashSet<string>() },
@@ -199,6 +269,8 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
// Vertex
["no-prop-vertex"] = new Vertex(1, "person"),
+ ["multi-label-vertex"] = new Vertex(1, "person", labels: new[] {
"person", "employee" }),
+ ["empty-label-vertex"] = new Vertex(1, "", labels:
Array.Empty<string>()),
["traversal-vertex"] = new Vertex(1, "person", new dynamic[]
{
new Property("name", NameMarko, null),
@@ -217,6 +289,92 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
// Direction enum
["out-direction"] = Direction.Out,
+
+ // Merge enum
+ ["merge-on-create"] = Merge.OnCreate,
+ ["merge-on-match"] = Merge.OnMatch,
+ ["merge-out-v"] = Merge.OutV,
+ ["merge-in-v"] = Merge.InV,
};
+
+ private static class CrewGraphFactory
+ {
+ public static Graph Create()
+ {
+ var graph = new Graph();
+ var v1 = AddVertex(graph, 1, "person",
+ Vp(0L, "name", "marko"),
+ Vp(6L, "location", "san diego", new Property("startTime",
1997, null),
+ new Property("endTime", 2001, null)),
+ Vp(7L, "location", "santa cruz", new Property("startTime",
2001, null),
+ new Property("endTime", 2004, null)),
+ Vp(8L, "location", "brussels", new Property("startTime",
2004, null),
+ new Property("endTime", 2005, null)),
+ Vp(9L, "location", "santa fe", new Property("startTime",
2005, null)));
+ var v7 = AddVertex(graph, 7, "person",
+ Vp(1L, "name", "stephen"),
+ Vp(10L, "location", "centreville", new
Property("startTime", 1990, null),
+ new Property("endTime", 2000, null)),
+ Vp(11L, "location", "dulles", new Property("startTime",
2000, null),
+ new Property("endTime", 2006, null)),
+ Vp(12L, "location", "purcellville", new
Property("startTime", 2006, null)));
+ var v8 = AddVertex(graph, 8, "person",
+ Vp(2L, "name", "matthias"),
+ Vp(13L, "location", "bremen", new Property("startTime",
2004, null),
+ new Property("endTime", 2007, null)),
+ Vp(14L, "location", "baltimore", new Property("startTime",
2007, null),
+ new Property("endTime", 2011, null)),
+ Vp(15L, "location", "oakland", new Property("startTime",
2011, null),
+ new Property("endTime", 2014, null)),
+ Vp(16L, "location", "seattle", new Property("startTime",
2014, null)));
+ var v9 = AddVertex(graph, 9, "person",
+ Vp(3L, "name", "daniel"),
+ Vp(17L, "location", "spremberg", new Property("startTime",
1982, null),
+ new Property("endTime", 2005, null)),
+ Vp(18L, "location", "kaiserslautern", new
Property("startTime", 2005, null),
+ new Property("endTime", 2009, null)),
+ Vp(19L, "location", "aachen", new Property("startTime",
2009, null)));
+ var v10 = AddVertex(graph, 10, "software", Vp(4L, "name",
"gremlin"));
+ var v11 = AddVertex(graph, 11, "software", Vp(5L, "name",
"tinkergraph"));
+
+ AddEdge(graph, 13, v1, "develops", v10, new Property("since",
2009, null));
+ AddEdge(graph, 14, v1, "develops", v11, new Property("since",
2010, null));
+ AddEdge(graph, 15, v1, "uses", v10, new Property("skill", 4,
null));
+ AddEdge(graph, 16, v1, "uses", v11, new Property("skill", 5,
null));
+ AddEdge(graph, 17, v7, "develops", v10, new Property("since",
2010, null));
+ AddEdge(graph, 18, v7, "develops", v11, new Property("since",
2011, null));
+ AddEdge(graph, 19, v7, "uses", v10, new Property("skill", 5,
null));
+ AddEdge(graph, 20, v7, "uses", v11, new Property("skill", 4,
null));
+ AddEdge(graph, 21, v8, "develops", v10, new Property("since",
2012, null));
+ AddEdge(graph, 22, v8, "uses", v10, new Property("skill", 3,
null));
+ AddEdge(graph, 23, v8, "uses", v11, new Property("skill", 3,
null));
+ AddEdge(graph, 24, v9, "uses", v10, new Property("skill", 5,
null));
+ AddEdge(graph, 25, v9, "uses", v11, new Property("skill", 3,
null));
+ AddEdge(graph, 26, v10, "traverses", v11);
+
+ return graph;
+ }
+
+ private static VertexProperty Vp(object id, string label, object?
value, params Property[] metaProperties)
+ {
+ return new VertexProperty(id, label, value, null,
metaProperties.Cast<dynamic>().ToArray());
+ }
+
+ private static Vertex AddVertex(Graph graph, object id, string
label,
+ params VertexProperty[] vertexProperties)
+ {
+ var vertex = new Vertex(id, label,
vertexProperties.Cast<dynamic>().ToArray());
+ graph.Vertices[id] = vertex;
+ return vertex;
+ }
+
+ private static Edge AddEdge(Graph graph, object id, Vertex outV,
string label, Vertex inV,
+ params Property[] properties)
+ {
+ var edge = new Edge(id, outV, label, inV,
properties.Cast<dynamic>().ToArray());
+ graph.Edges[id] = edge;
+ return edge;
+ }
+ }
}
}
diff --git
a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary4/RoundTripTests.cs
b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary4/RoundTripTests.cs
index 8622316b49..f1e25c3507 100644
---
a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary4/RoundTripTests.cs
+++
b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary4/RoundTripTests.cs
@@ -22,9 +22,17 @@
#endregion
using System;
+using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Threading.Tasks;
using Gremlin.Net.Structure.IO.GraphBinary4;
+using GremlinEdge = Gremlin.Net.Structure.Edge;
+using GremlinGraph = Gremlin.Net.Structure.Graph;
+using GremlinPath = Gremlin.Net.Structure.Path;
+using GremlinProperty = Gremlin.Net.Structure.Property;
+using GremlinVertex = Gremlin.Net.Structure.Vertex;
+using GremlinVertexProperty = Gremlin.Net.Structure.VertexProperty;
using Xunit;
namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
@@ -159,6 +167,134 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
};
}
+ private static bool OrderedMapComparator(object? x, object? y)
+ {
+ if (x is not IDictionary<object, object?> expected || y is not
IDictionary<object, object?> actual)
+ return false;
+ if (expected.Count != actual.Count)
+ return false;
+
+ return expected.Zip(actual).All(pair =>
+ Equals(pair.First.Key, pair.Second.Key) &&
Equals(pair.First.Value, pair.Second.Value));
+ }
+
+ private static bool PathComparator(object? x, object? y)
+ {
+ if (x is not GremlinPath expected || y is not GremlinPath actual)
+ return false;
+ if (!expected.Objects.SequenceEqual(actual.Objects) ||
expected.Labels.Count != actual.Labels.Count)
+ return false;
+
+ for (var ix = 0; ix < expected.Labels.Count; ix++)
+ {
+ if (!expected.Labels[ix].SetEquals(actual.Labels[ix]))
+ return false;
+ }
+
+ return true;
+ }
+
+ private static bool VertexLabelComparator(object? x, object? y)
+ {
+ if (x is not GremlinVertex expected || y is not GremlinVertex
actual)
+ return false;
+
+ return expected.Equals(actual) &&
+ expected.Labels.Count == actual.Labels.Count &&
+ expected.Labels.All(actual.Labels.Contains);
+ }
+
+ private static bool GraphComparator(object? x, object? y)
+ {
+ if (x is not GremlinGraph expected || y is not GremlinGraph actual)
+ return false;
+ if (expected.Vertices.Count != actual.Vertices.Count ||
expected.Edges.Count != actual.Edges.Count)
+ return false;
+
+ foreach (var pair in expected.Vertices)
+ {
+ if (!actual.Vertices.TryGetValue(pair.Key, out var
actualVertex) ||
+ !VertexComparator(pair.Value, actualVertex))
+ return false;
+ }
+
+ foreach (var pair in expected.Edges)
+ {
+ if (!actual.Edges.TryGetValue(pair.Key, out var actualEdge) ||
!EdgeComparator(pair.Value, actualEdge))
+ return false;
+ }
+
+ return true;
+ }
+
+ private static bool VertexComparator(GremlinVertex expected,
GremlinVertex actual)
+ {
+ return expected.Equals(actual) &&
+ expected.Label == actual.Label &&
+ LabelsEqual(expected.Labels, actual.Labels) &&
+ VertexPropertiesEqual(expected.Properties,
actual.Properties);
+ }
+
+ private static bool EdgeComparator(GremlinEdge expected, GremlinEdge
actual)
+ {
+ return expected.Equals(actual) &&
+ expected.Label == actual.Label &&
+ LabelsEqual(expected.Labels, actual.Labels) &&
+ Equals(expected.OutV.Id, actual.OutV.Id) &&
+ Equals(expected.InV.Id, actual.InV.Id) &&
+ PropertiesEqual(expected.Properties, actual.Properties);
+ }
+
+ private static bool VertexPropertiesEqual(dynamic[] expected,
dynamic[] actual)
+ {
+ if (expected.Length != actual.Length)
+ return false;
+
+ for (var ix = 0; ix < expected.Length; ix++)
+ {
+ if (expected[ix] is not GremlinVertexProperty expectedProperty
||
+ actual[ix] is not GremlinVertexProperty actualProperty ||
+ !VertexPropertyComparator(expectedProperty,
actualProperty))
+ return false;
+ }
+
+ return true;
+ }
+
+ private static bool VertexPropertyComparator(GremlinVertexProperty
expected, GremlinVertexProperty actual)
+ {
+ return expected.Equals(actual) &&
+ expected.Label == actual.Label &&
+ Equals(expected.Value, actual.Value) &&
+ PropertiesEqual(expected.Properties, actual.Properties);
+ }
+
+ private static bool PropertiesEqual(dynamic[] expected, dynamic[]
actual)
+ {
+ if (expected.Length != actual.Length)
+ return false;
+
+ for (var ix = 0; ix < expected.Length; ix++)
+ {
+ if (expected[ix] is not GremlinProperty expectedProperty ||
+ actual[ix] is not GremlinProperty actualProperty ||
+ !PropertyComparator(expectedProperty, actualProperty))
+ return false;
+ }
+
+ return true;
+ }
+
+ private static bool PropertyComparator(GremlinProperty expected,
GremlinProperty actual)
+ {
+ return expected.Key == actual.Key && Equals(expected.Value,
actual.Value);
+ }
+
+ private static bool LabelsEqual(IReadOnlySet<string> expected,
IReadOnlySet<string> actual)
+ {
+ return expected.Count == actual.Count &&
expected.All(actual.Contains);
+ }
+
// BigInteger tests
[Fact]
public Task TestPosBigInteger() => Run("pos-biginteger");
@@ -166,6 +302,36 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
[Fact]
public Task TestNegBigInteger() => Run("neg-biginteger");
+ [Fact]
+ public Task TestZeroBigInteger() => Run("zero-biginteger");
+
+ [Fact]
+ public Task TestSignBoundaryPosBigInteger() =>
Run("sign-boundary-pos-biginteger");
+
+ [Fact]
+ public Task TestSignBoundaryNegBigInteger() =>
Run("sign-boundary-neg-biginteger");
+
+ // BigDecimal tests
+ [Fact]
+ public Task TestZeroBigDecimal() => Run("zero-bigdecimal");
+
+ [Fact]
+ public Task TestScaleZeroBigDecimal() => Run("scale-zero-bigdecimal");
+
+ [Fact]
+ public Task TestNegativeScaleBigDecimal() =>
+ RunWriteRead("negative-scale-bigdecimal"); // decimal doesn't
preserve negative scale for byte-exact writes
+
+ [Fact]
+ public Task TestSmallDecimalBigDecimal() =>
Run("small-decimal-bigdecimal");
+
+ // Provider-defined type tests
+ [Fact]
+ public Task TestUint8PrimitivePdt() => Run("uint8-primitive-pdt");
+
+ [Fact]
+ public Task TestPointCompositePdt() => Run("point-composite-pdt");
+
// Byte tests
[Fact]
public Task TestMinByte() => Run("min-byte");
@@ -235,12 +401,33 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
public Task TestSingleByteChar() => Run("single-byte-char");
[Fact]
- public Task TestMultiByteChar() => Run("multi-byte-char");
+ public Task TestTwoByteChar() => Run("two-byte-char");
+
+ [Fact]
+ public Task TestThreeByteChar() => Run("three-byte-char");
// Null test
[Fact]
public Task TestUnspecifiedNull() => Run("unspecified-null");
+ [Fact]
+ public Task TestNullInt() => RunRead("null-int"); // typed nulls
deserialize to plain null
+
+ [Fact]
+ public Task TestNullLong() => RunRead("null-long"); // typed nulls
deserialize to plain null
+
+ [Fact]
+ public Task TestNullString() => RunRead("null-string"); // typed nulls
deserialize to plain null
+
+ [Fact]
+ public Task TestNullList() => RunRead("null-list"); // typed nulls
deserialize to plain null
+
+ [Fact]
+ public Task TestNullMap() => RunRead("null-map"); // typed nulls
deserialize to plain null
+
+ [Fact]
+ public Task TestNullSet() => RunRead("null-set"); // typed nulls
deserialize to plain null
+
// Boolean tests
[Fact]
public Task TestTrueBoolean() => Run("true-boolean");
@@ -255,17 +442,30 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
[Fact]
public Task TestMixedString() => Run("mixed-string");
+ [Fact]
+ public Task TestEmptyString() => Run("empty-string");
+
// BulkSet tests (read only - BulkSet deserialized as List)
[Fact]
- public Task TestVarBulkList() => RunRead("var-bulklist");
+ public Task TestVarBulkList() => RunRead("var-bulklist"); // BulkList
deserializes as a plain List
[Fact]
- public Task TestEmptyBulkList() => RunRead("empty-bulklist");
+ public Task TestEmptyBulkList() => RunRead("empty-bulklist"); //
BulkList deserializes as a plain List
// Duration tests
[Fact]
public Task TestZeroDuration() => Run("zero-duration");
+ [Fact]
+ public Task TestPositiveDuration() => Run("positive-duration");
+
+ [Fact]
+ public Task TestNegativeDuration() => Run("negative-duration");
+
+ [Fact]
+ public Task TestNanosDuration() =>
+ RunWriteRead("nanos-duration"); // TimeSpan truncates sub-tick
nanoseconds for byte-exact writes
+
// Edge tests
[Fact]
public Task TestTraversalEdge() => RunWriteRead("traversal-edge"); //
properties aren't serialized
@@ -298,6 +498,10 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
[Fact]
public Task TestEmptyMap() => Run("empty-map");
+ [Fact]
+ public Task TestOrderedStringIntMap() =>
+ RunWriteRead("ordered-string-int-map", OrderedMapComparator); //
writer doesn't emit the ordered-map value flag
+
// Path tests
[Fact]
public Task TestTraversalPath() => RunWriteRead("traversal-path"); //
properties written as null not empty list
@@ -305,6 +509,13 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
[Fact]
public Task TestEmptyPath() => Run("empty-path");
+ [Fact]
+ public Task TestPathZeroLabels() => Run("path-zero-labels",
PathComparator);
+
+ [Fact]
+ public Task TestPathMultipleLabels() =>
+ RunWriteRead("path-multiple-labels", PathComparator); // label set
ordering isn't guaranteed
+
[Fact]
public Task TestPropPath() => RunWriteRead("prop-path"); // properties
aren't serialized
@@ -313,19 +524,16 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
public Task TestTraversalTree() => RunWriteRead("traversal-tree"); //
vertex properties aren't serialized
[Fact]
- public Task TestEmptyTree() => TestEmptyTreeRoundTrip();
+ public Task TestEmptyTree() => Run("empty-tree");
- private async Task TestEmptyTreeRoundTrip()
- {
- // no .gbin resource exists for an empty tree, so exercise an
in-memory round trip
- var empty =
(Gremlin.Net.Structure.Tree)Model.Entries["empty-tree"]!;
- using var writeStream = new MemoryStream();
- await Writer.WriteAsync(empty, writeStream);
- using var readStream = new MemoryStream(writeStream.ToArray());
- var roundTripped = await Reader.ReadAsync(readStream);
- Assert.Equal(empty, roundTripped);
- Assert.True(((Gremlin.Net.Structure.Tree)roundTripped!).IsLeaf());
- }
+ [Fact]
+ public Task TestTreeNullKey() => Run("tree-null-key");
+
+ [Fact]
+ public Task TestTreeMixedKeyTypes() => Run("tree-mixed-key-types");
+
+ [Fact]
+ public Task TestTreeDeepNesting() => Run("tree-deep-nesting");
// Property tests
[Fact]
@@ -362,6 +570,17 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
[Fact]
public Task TestTraversalVertex() => RunWriteRead("traversal-vertex");
// properties aren't serialized
+ [Fact]
+ public Task TestTinkerGraph() => Run("tinker-graph", GraphComparator);
+
+ [Fact]
+ public Task TestMultiLabelVertex() =>
+ RunWriteRead("multi-label-vertex", VertexLabelComparator); //
Vertex equality is id-only
+
+ [Fact]
+ public Task TestEmptyLabelVertex() =>
+ RunWriteRead("empty-label-vertex", VertexLabelComparator); //
Vertex equality is id-only
+
// VertexProperty tests
[Fact]
public Task TestTraversalVertexProperty() =>
RunWriteRead("traversal-vertexproperty"); // properties aren't serialized
@@ -379,5 +598,18 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary4
// Direction enum test
[Fact]
public Task TestOutDirection() => Run("out-direction");
+
+ // Merge enum tests
+ [Fact]
+ public Task TestMergeOnCreate() => Run("merge-on-create");
+
+ [Fact]
+ public Task TestMergeOnMatch() => Run("merge-on-match");
+
+ [Fact]
+ public Task TestMergeOutV() => Run("merge-out-v");
+
+ [Fact]
+ public Task TestMergeInV() => Run("merge-in-v");
}
}
diff --git
a/gremlin-js/gremlin-javascript/lib/structure/io/binary/internals/MapSerializer.js
b/gremlin-js/gremlin-javascript/lib/structure/io/binary/internals/MapSerializer.js
index b3db2853c9..6ca8500f28 100644
---
a/gremlin-js/gremlin-javascript/lib/structure/io/binary/internals/MapSerializer.js
+++
b/gremlin-js/gremlin-javascript/lib/structure/io/binary/internals/MapSerializer.js
@@ -111,7 +111,7 @@ export default class MapSerializer {
if (value_flag === 0x01) {
return null;
}
- if (value_flag !== 0x00) {
+ if (value_flag !== 0x00 && value_flag !== 0x02) {
throw new Error(`MapSerializer: unexpected
{value_flag}=0x${value_flag.toString(16)}`);
}
return this.deserializeValue(reader, value_flag, type_code);
diff --git a/gremlin-js/gremlin-javascript/test/unit/graphbinary/model-test.js
b/gremlin-js/gremlin-javascript/test/unit/graphbinary/model-test.js
index bca8a47d7a..a61bfb566e 100644
--- a/gremlin-js/gremlin-javascript/test/unit/graphbinary/model-test.js
+++ b/gremlin-js/gremlin-javascript/test/unit/graphbinary/model-test.js
@@ -124,13 +124,6 @@ function runRead(name, comparator = assertEqual) {
});
}
-// unimplemented type
-function skip(name, reason) {
- describe(name, () => {
- it.skip(`${reason}`, () => {});
- });
-}
-
function assertEqual(actual, expected) {
if (Number.isNaN(expected) && Number.isNaN(actual)) return;
if (Object.is(expected, -0) && Object.is(actual, -0)) return;
@@ -165,6 +158,89 @@ function setComparator(actual, expected) {
assert.deepStrictEqual([...actual].sort(), [...expected].sort());
}
+function orderedMapComparator(actual, expected) {
+ assert.instanceOf(actual, Map);
+ assert.instanceOf(expected, Map);
+ assert.deepStrictEqual([...actual.entries()], [...expected.entries()]);
+}
+
+function treeComparator(actual, expected) {
+ assert.isTrue(actual.equals(expected));
+}
+
+function pathComparator(actual, expected) {
+ assert.deepStrictEqual(actual.objects, expected.objects);
+ assert.strictEqual(actual.labels.length, expected.labels.length);
+ for (let ix = 0; ix < actual.labels.length; ix++) {
+ setComparator(actual.labels[ix], expected.labels[ix]);
+ }
+}
+
+function vertexLabelComparator(actual, expected) {
+ assert.strictEqual(actual.id, expected.id);
+ setComparator(actual.labels, expected.labels);
+}
+
+function propertyComparator(actual, expected) {
+ assert.strictEqual(actual.key, expected.key);
+ assert.deepStrictEqual(actual.value, expected.value);
+}
+
+function vertexPropertyComparator(actual, expected) {
+ assert.strictEqual(actual.id, expected.id);
+ assert.strictEqual(actual.label, expected.label);
+ assert.deepStrictEqual(actual.value, expected.value);
+ assert.strictEqual(actual.properties.length, expected.properties.length);
+ for (let ix = 0; ix < actual.properties.length; ix++) {
+ propertyComparator(actual.properties[ix], expected.properties[ix]);
+ }
+}
+
+function vertexComparator(actual, expected) {
+ assert.strictEqual(actual.id, expected.id);
+ assert.strictEqual(actual.label, expected.label);
+ setComparator(actual.labels, expected.labels);
+ assert.strictEqual(actual.properties.length, expected.properties.length);
+ for (let ix = 0; ix < actual.properties.length; ix++) {
+ vertexPropertyComparator(actual.properties[ix], expected.properties[ix]);
+ }
+}
+
+function edgeComparator(actual, expected) {
+ assert.strictEqual(actual.id, expected.id);
+ assert.strictEqual(actual.label, expected.label);
+ setComparator(actual.labels, expected.labels);
+ assert.strictEqual(actual.outV.id, expected.outV.id);
+ assert.strictEqual(actual.inV.id, expected.inV.id);
+ assert.strictEqual(actual.properties.length, expected.properties.length);
+ for (let ix = 0; ix < actual.properties.length; ix++) {
+ propertyComparator(actual.properties[ix], expected.properties[ix]);
+ }
+}
+
+function graphComparator(actual, expected) {
+ assert.strictEqual(actual.vertices.size, expected.vertices.size);
+ assert.strictEqual(actual.edges.size, expected.edges.size);
+ assert.deepStrictEqual([...actual.vertices.keys()],
[...expected.vertices.keys()]);
+ assert.deepStrictEqual([...actual.edges.keys()], [...expected.edges.keys()]);
+ for (const [id, expectedVertex] of expected.vertices) {
+ vertexComparator(actual.vertices.get(id), expectedVertex);
+ }
+ for (const [id, expectedEdge] of expected.edges) {
+ edgeComparator(actual.edges.get(id), expectedEdge);
+ }
+}
+
+function primitivePdtComparator(actual, expected) {
+ assert.strictEqual(actual.name, expected.name);
+ assert.strictEqual(actual.value, expected.value);
+}
+
+function compositePdtComparator(actual, expected) {
+ assert.strictEqual(actual.name, expected.name);
+ assert.deepStrictEqual(actual.fields, expected.fields);
+}
+
function setCardinalityComparator(actual, expected) {
assert.strictEqual(actual.id, expected.id);
assert.strictEqual(actual.label, expected.label);
@@ -182,9 +258,14 @@ function invalidDateComparator(actual, expected) {
}
describe('GraphBinary v4 Model Tests', () => {
- // run mode (31 entries)
+ // run mode
run('pos-biginteger');
run('neg-biginteger');
+ run('zero-biginteger');
+ run('sign-boundary-pos-biginteger');
+ run('sign-boundary-neg-biginteger');
+ run('uint8-primitive-pdt', primitivePdtComparator);
+ run('point-composite-pdt', compositePdtComparator);
run('empty-binary');
run('str-binary');
run('max-double');
@@ -199,6 +280,7 @@ describe('GraphBinary v4 Model Tests', () => {
run('false-boolean');
run('single-byte-string');
run('mixed-string');
+ run('empty-string');
run('var-type-list');
run('empty-list');
run('no-prop-edge');
@@ -207,15 +289,26 @@ describe('GraphBinary v4 Model Tests', () => {
run('empty-map');
run('traversal-path');
run('empty-path');
+ run('path-zero-labels', pathComparator);
+ run('empty-tree', treeComparator);
+ run('tree-null-key', treeComparator);
+ run('tree-mixed-key-types', treeComparator);
+ run('tree-deep-nesting', treeComparator);
run('edge-property');
run('null-property');
run('empty-set');
run('no-prop-vertex');
+ run('multi-label-vertex', vertexLabelComparator);
+ run('empty-label-vertex', vertexLabelComparator);
run('id-t');
run('out-direction');
+ run('merge-on-create');
+ run('merge-on-match');
+ run('merge-out-v');
+ run('merge-in-v');
run('neg-zero-double', negZeroComparator);
- // runWriteRead mode (23 entries)
+ // runWriteRead mode
runWriteRead('min-byte');
runWriteRead('max-byte');
runWriteRead('max-float');
@@ -239,35 +332,29 @@ describe('GraphBinary v4 Model Tests', () => {
runWriteRead('meta-vertexproperty');
runWriteRead('set-cardinality-vertexproperty', setCardinalityComparator);
runWriteRead('traversal-vertex');
+ // JS deserializes safe Long values to Number, so vertex-property ids can't
be re-emitted byte-exactly.
+ runWriteRead('tinker-graph', graphComparator);
+ // label set ordering isn't guaranteed after a JS object round trip.
+ runWriteRead('path-multiple-labels', pathComparator);
+ // JS preserves Map entry order, but its writer doesn't emit the ordered-map
value flag.
+ runWriteRead('ordered-string-int-map', orderedMapComparator);
+ runWriteRead('traversal-tree', treeComparator); // vertex properties aren't
serialized
- // Tree
- runWriteRead('traversal-tree'); // vertex properties aren't serialized
-
- // empty-tree has no .gbin resource, so exercise an in-memory round trip
- describe('empty-tree', () => {
- it('in-memory round trip', async () => {
- const empty = model['empty-tree'];
- const roundTripped = await anySerializer.deserialize(
- StreamReader.fromBuffer(anySerializer.serialize(empty)),
- );
- assert.deepStrictEqual(roundTripped, empty);
- assert.isTrue(roundTripped.isLeaf());
- });
- });
-
- // runRead mode (5 entries)
+ // runRead mode
+ // JS Number can't re-emit this as a Float.
runRead('neg-zero-float', negZeroComparator);
+ // invalid Date models can't be serialized back.
runRead('max-offsetdatetime', invalidDateComparator);
runRead('min-offsetdatetime', invalidDateComparator);
+ // properties aren't serialized in JS for this path fixture.
runRead('prop-path');
+ // this fixture has complex keys that JS can't write back byte-exactly.
runRead('var-type-map');
-
- // skip mode (7 entries)
- skip('single-byte-char', 'Char type (0x80) not implemented');
- skip('multi-byte-char', 'Char type (0x80) not implemented');
- skip('tinker-graph', 'Graph type not implemented');
- skip('pos-bigdecimal', 'BigDecimal type not implemented');
- skip('neg-bigdecimal', 'BigDecimal type not implemented');
- skip('forever-duration', 'Duration type not implemented');
- skip('zero-duration', 'Duration type not implemented');
-});
\ No newline at end of file
+ // typed nulls deserialize to plain null, so the original type can't be
re-emitted.
+ runRead('null-int');
+ runRead('null-long');
+ runRead('null-string');
+ runRead('null-list');
+ runRead('null-map');
+ runRead('null-set');
+});
diff --git a/gremlin-js/gremlin-javascript/test/unit/graphbinary/model.js
b/gremlin-js/gremlin-javascript/test/unit/graphbinary/model.js
index 63aa9dbfb3..c06f4c4965 100644
--- a/gremlin-js/gremlin-javascript/test/unit/graphbinary/model.js
+++ b/gremlin-js/gremlin-javascript/test/unit/graphbinary/model.js
@@ -17,15 +17,26 @@
* under the License.
*/
-import { Vertex, Edge, Property, VertexProperty, Path, Tree } from
'../../../lib/structure/graph.js';
-import { direction, t } from '../../../lib/process/traversal.js';
+import {
+ Graph,
+ Vertex,
+ Edge,
+ Property,
+ VertexProperty,
+ Path,
+ Tree,
+ CompositePDT,
+ PrimitivePDT
+} from '../../../lib/structure/graph.js';
+import { direction, merge, t } from '../../../lib/process/traversal.js';
/*
* Unsupported types (no map entries, .gbin files exist but types not
implemented):
- * - single-byte-char, multi-byte-char (Char 0x80 not implemented)
- * - tinker-graph (Graph type not implemented)
- * - pos-bigdecimal, neg-bigdecimal (BigDecimal type not implemented)
- * - forever-duration, zero-duration (Duration type not implemented)
+ * - single-byte-char, two-byte-char, three-byte-char, four-byte-char (Char
0x80 not implemented)
+ * - pos-bigdecimal, neg-bigdecimal, zero-bigdecimal, scale-zero-bigdecimal,
+ * negative-scale-bigdecimal, small-decimal-bigdecimal (BigDecimal type not
implemented)
+ * - forever-duration, zero-duration, positive-duration, negative-duration,
+ * nanos-duration (Duration type not implemented)
*/
const model = {};
@@ -33,6 +44,13 @@ const model = {};
// BigInteger values
model['pos-biginteger'] = BigInt('123456789987654321123456789987654321');
model['neg-biginteger'] = BigInt('-123456789987654321123456789987654321');
+model['zero-biginteger'] = 0n;
+model['sign-boundary-pos-biginteger'] = 128n;
+model['sign-boundary-neg-biginteger'] = -129n;
+
+// Provider-defined type values
+model['uint8-primitive-pdt'] = new PrimitivePDT('Uint8', '10');
+model['point-composite-pdt'] = new CompositePDT('Point', { x: 1, y: 2 });
// Byte values (JS has no byte type, deserializes to Number)
model['min-byte'] = -128;
@@ -64,6 +82,12 @@ model['neg-zero-float'] = -0;
// Null
model['unspecified-null'] = null;
+model['null-int'] = null;
+model['null-long'] = null;
+model['null-string'] = null;
+model['null-list'] = null;
+model['null-map'] = null;
+model['null-set'] = null;
// Boolean values
model['true-boolean'] = true;
@@ -72,6 +96,7 @@ model['false-boolean'] = false;
// String values
model['single-byte-string'] = 'abc';
model['mixed-string'] = 'abc\u0391\u0392\u0393';
+model['empty-string'] = '';
// List values
model['var-bulklist'] = ['marko', 'josh', 'josh'];
@@ -111,6 +136,14 @@ model['var-type-map'] = new Map([
['test', 123]
]);
model['empty-map'] = new Map();
+model['ordered-string-int-map'] = new Map([
+ ['delta', 4],
+ ['alpha', 1],
+ ['charlie', 3],
+ ['bravo', 2],
+ ['echo', 5],
+ ['foxtrot', 6]
+]);
// Path values
model['traversal-path'] = new Path(
@@ -118,6 +151,8 @@ model['traversal-path'] = new Path(
[new Vertex(1, 'person'), new Vertex(10, 'software'), new Vertex(11,
'software')]
);
model['empty-path'] = new Path([], []);
+model['path-zero-labels'] = new Path([new Set()], ['marko']);
+model['path-multiple-labels'] = new Path([new Set(['a', 'b'])], ['marko']);
// Tree values
// tree for g.V(10).out().tree(): v[10] -> v[11]
@@ -125,6 +160,16 @@ const traversalTree = new Tree();
traversalTree.getOrCreateChild(new Vertex(10,
'software')).getOrCreateChild(new Vertex(11, 'software'));
model['traversal-tree'] = traversalTree;
model['empty-tree'] = new Tree();
+const treeNullKey = new Tree();
+treeNullKey.getOrCreateChild(null);
+model['tree-null-key'] = treeNullKey;
+const treeMixedKeyTypes = new Tree();
+treeMixedKeyTypes.getOrCreateChild('name');
+treeMixedKeyTypes.getOrCreateChild(123);
+model['tree-mixed-key-types'] = treeMixedKeyTypes;
+const treeDeepNesting = new Tree();
+treeDeepNesting.getOrCreateChild('root').getOrCreateChild('branch').getOrCreateChild('leaf');
+model['tree-deep-nesting'] = treeDeepNesting;
// Complex path with nested properties
const propPathVertex = new Vertex(1, 'person', [
@@ -183,6 +228,10 @@ model['set-cardinality-vertexproperty'] = new
VertexProperty(1, 'person', new Se
// Enum values
model['id-t'] = t.id;
model['out-direction'] = direction.out;
+model['merge-on-create'] = merge.onCreate;
+model['merge-on-match'] = merge.onMatch;
+model['merge-out-v'] = merge.outV;
+model['merge-in-v'] = merge.inV;
// Complex vertex with properties (from .gbin deserialization structure)
const name = new VertexProperty(0, 'name', 'marko');
@@ -202,9 +251,86 @@ const santaFe = new VertexProperty(9, 'location', 'santa
fe', [
new Property('startTime', 2005)
]);
model['traversal-vertex'] = new Vertex(1, 'person', [name, sanDiego,
santaCruz, brussels, santaFe]);
+model['multi-label-vertex'] = new Vertex(1, ['person', 'employee']);
+model['empty-label-vertex'] = new Vertex(1, 'vertex', [], []);
// DateTime values (invalid dates for overflow cases)
model['max-offsetdatetime'] = new Date(NaN); // Year 999999999 overflows JS
Date
model['min-offsetdatetime'] = new Date(NaN); // Year -999999999 overflows JS
Date
-export { model };
\ No newline at end of file
+class CrewGraphFactory {
+ static vertexProperty(id, label, value, metaProperties = []) {
+ return new VertexProperty(
+ id,
+ label,
+ value,
+ metaProperties.map(([key, metaValue]) => new Property(key, metaValue))
+ );
+ }
+
+ static addVertex(graph, id, label, propertySpecs) {
+ const vertex = new Vertex(id, label);
+ for (const spec of propertySpecs) {
+ vertex.properties.push(CrewGraphFactory.vertexProperty(spec[0], spec[1],
spec[2], spec[3] || []));
+ }
+ graph.vertices.set(id, vertex);
+ return vertex;
+ }
+
+ static addEdge(graph, id, outV, label, inV, properties = []) {
+ const edge = new Edge(id, outV, label, inV, properties.map(([key, value])
=> new Property(key, value)));
+ graph.edges.set(id, edge);
+ return edge;
+ }
+
+ static create() {
+ const graph = new Graph();
+ const v1 = CrewGraphFactory.addVertex(graph, 1, 'person', [
+ [0, 'name', 'marko'],
+ [6, 'location', 'san diego', [['startTime', 1997], ['endTime', 2001]]],
+ [7, 'location', 'santa cruz', [['startTime', 2001], ['endTime', 2004]]],
+ [8, 'location', 'brussels', [['startTime', 2004], ['endTime', 2005]]],
+ [9, 'location', 'santa fe', [['startTime', 2005]]]
+ ]);
+ const v7 = CrewGraphFactory.addVertex(graph, 7, 'person', [
+ [1, 'name', 'stephen'],
+ [10, 'location', 'centreville', [['startTime', 1990], ['endTime',
2000]]],
+ [11, 'location', 'dulles', [['startTime', 2000], ['endTime', 2006]]],
+ [12, 'location', 'purcellville', [['startTime', 2006]]]
+ ]);
+ const v8 = CrewGraphFactory.addVertex(graph, 8, 'person', [
+ [2, 'name', 'matthias'],
+ [13, 'location', 'bremen', [['startTime', 2004], ['endTime', 2007]]],
+ [14, 'location', 'baltimore', [['startTime', 2007], ['endTime', 2011]]],
+ [15, 'location', 'oakland', [['startTime', 2011], ['endTime', 2014]]],
+ [16, 'location', 'seattle', [['startTime', 2014]]]
+ ]);
+ const v9 = CrewGraphFactory.addVertex(graph, 9, 'person', [
+ [3, 'name', 'daniel'],
+ [17, 'location', 'spremberg', [['startTime', 1982], ['endTime', 2005]]],
+ [18, 'location', 'kaiserslautern', [['startTime', 2005], ['endTime',
2009]]],
+ [19, 'location', 'aachen', [['startTime', 2009]]]
+ ]);
+ const v10 = CrewGraphFactory.addVertex(graph, 10, 'software', [[4, 'name',
'gremlin']]);
+ const v11 = CrewGraphFactory.addVertex(graph, 11, 'software', [[5, 'name',
'tinkergraph']]);
+ CrewGraphFactory.addEdge(graph, 13, v1, 'develops', v10, [['since',
2009]]);
+ CrewGraphFactory.addEdge(graph, 14, v1, 'develops', v11, [['since',
2010]]);
+ CrewGraphFactory.addEdge(graph, 15, v1, 'uses', v10, [['skill', 4]]);
+ CrewGraphFactory.addEdge(graph, 16, v1, 'uses', v11, [['skill', 5]]);
+ CrewGraphFactory.addEdge(graph, 17, v7, 'develops', v10, [['since',
2010]]);
+ CrewGraphFactory.addEdge(graph, 18, v7, 'develops', v11, [['since',
2011]]);
+ CrewGraphFactory.addEdge(graph, 19, v7, 'uses', v10, [['skill', 5]]);
+ CrewGraphFactory.addEdge(graph, 20, v7, 'uses', v11, [['skill', 4]]);
+ CrewGraphFactory.addEdge(graph, 21, v8, 'develops', v10, [['since',
2012]]);
+ CrewGraphFactory.addEdge(graph, 22, v8, 'uses', v10, [['skill', 3]]);
+ CrewGraphFactory.addEdge(graph, 23, v8, 'uses', v11, [['skill', 3]]);
+ CrewGraphFactory.addEdge(graph, 24, v9, 'uses', v10, [['skill', 5]]);
+ CrewGraphFactory.addEdge(graph, 25, v9, 'uses', v11, [['skill', 3]]);
+ CrewGraphFactory.addEdge(graph, 26, v10, 'traverses', v11);
+ return graph;
+ }
+}
+
+model['tinker-graph'] = CrewGraphFactory.create();
+
+export { model };
diff --git
a/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV4.py
b/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV4.py
index 90556996d1..1cf5b0f856 100644
---
a/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV4.py
+++
b/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV4.py
@@ -1060,4 +1060,4 @@ class PrimitivePDTIO(_GraphBinaryTypeIO):
def _read_primitive_pdt(cls, b, r):
name = r.read_object(b)
value = r.read_object(b)
- return PrimitivePDT(name, value)
\ No newline at end of file
+ return PrimitivePDT(name, value)
diff --git a/gremlin-python/src/main/python/tests/unit/structure/io/model.py
b/gremlin-python/src/main/python/tests/unit/structure/io/model.py
index dae5c04297..8410872d06 100644
--- a/gremlin-python/src/main/python/tests/unit/structure/io/model.py
+++ b/gremlin-python/src/main/python/tests/unit/structure/io/model.py
@@ -19,13 +19,13 @@ under the License.
import datetime
import uuid
-from gremlin_python.statics import short, long, bigint, BigDecimal, SingleByte
-from gremlin_python.structure.graph import Vertex, Edge, Property,
VertexProperty, Path, Tree
-from gremlin_python.process.traversal import Direction, Traverser, T
+from collections import OrderedDict
+from gremlin_python.statics import short, long, bigint, BigDecimal,
SingleByte, SingleChar
+from gremlin_python.structure.graph import Graph, Vertex, Edge, Property,
VertexProperty, Path, Tree, CompositePDT, PrimitivePDT
+from gremlin_python.process.traversal import Direction, Merge, T
"""
The following models aren't supported.
-tinker-graph Graph type not implemented
max-offsetdatetime Too large for datetime
min-offsetdatetime Too small for datetime
forever-duration Too large for duration
@@ -43,8 +43,17 @@ model = {}
model["pos-bigdecimal"] = BigDecimal(33, 123456789987654321123456789987654321)
model["neg-bigdecimal"] = BigDecimal(33, -123456789987654321123456789987654321)
+model["zero-bigdecimal"] = BigDecimal(0, 0)
+model["scale-zero-bigdecimal"] = BigDecimal(0, 1234)
+model["negative-scale-bigdecimal"] = BigDecimal(-2, 1234)
+model["small-decimal-bigdecimal"] = BigDecimal(2, 1234)
model["pos-biginteger"] = bigint(123456789987654321123456789987654321)
model["neg-biginteger"] = bigint(-123456789987654321123456789987654321)
+model["zero-biginteger"] = bigint(0)
+model["sign-boundary-pos-biginteger"] = bigint(128)
+model["sign-boundary-neg-biginteger"] = bigint(-129)
+model["uint8-primitive-pdt"] = PrimitivePDT("Uint8", "10")
+model["point-composite-pdt"] = CompositePDT("Point", {"x": 1, "y": 2})
model["min-byte"] = SingleByte(-128)
model["max-byte"] = SingleByte(127)
model["empty-binary"] = bytes("", "utf8")
@@ -58,15 +67,27 @@ model["pos-inf-double"] = float('inf')
model["neg-inf-double"] = float('-inf')
model["neg-zero-double"] = -0.0
model["single-byte-char"] = 'a'
-model["multi-byte-char"] = '\u03A9'
+model["two-byte-char"] = '\u03A9'
+model["three-byte-char"] = SingleChar('\u20AC')
+model["four-byte-char"] = SingleChar('\U0001F600')
model["unspecified-null"] = None
+model["null-int"] = None
+model["null-long"] = None
+model["null-string"] = None
+model["null-list"] = None
+model["null-map"] = None
+model["null-set"] = None
model["true-boolean"] = True
model["false-boolean"] = False
model["single-byte-string"] = "abc"
model["mixed-string"] = "abc\u0391\u0392\u0393"
+model["empty-string"] = ""
model["var-bulklist"] = ["marko", "josh", "josh"]
model["empty-bulklist"] = []
model["zero-duration"] = datetime.timedelta()
+model["positive-duration"] = datetime.timedelta(seconds=123)
+model["negative-duration"] = datetime.timedelta(seconds=-123)
+model["nanos-duration"] = datetime.timedelta(seconds=123, microseconds=456.789)
model["traversal-edge"] = Edge(
13,
Vertex(1, 'person'),
@@ -93,17 +114,37 @@ model["var-type-map"] = {
None: None
}
model["empty-map"] = {}
+model["ordered-string-int-map"] = OrderedDict([
+ ("delta", 4),
+ ("alpha", 1),
+ ("charlie", 3),
+ ("bravo", 2),
+ ("echo", 5),
+ ("foxtrot", 6)
+])
model["traversal-path"] = Path(
[set(), set(), set()],
[Vertex(1, "person"), Vertex(10, "software"), Vertex(11, "software")]
)
model["empty-path"] = Path([], [])
+model["path-zero-labels"] = Path([set()], ["marko"])
+model["path-multiple-labels"] = Path([{"a", "b"}], ["marko"])
# tree for g.V(10).out().tree(): v[10] -> v[11]
_traversal_tree = Tree()
_traversal_tree.get_or_create_child(Vertex(10,
"software")).get_or_create_child(Vertex(11, "software"))
model["traversal-tree"] = _traversal_tree
model["empty-tree"] = Tree()
+_tree_null_key = Tree()
+_tree_null_key.get_or_create_child(None)
+model["tree-null-key"] = _tree_null_key
+_tree_mixed_key_types = Tree()
+_tree_mixed_key_types.get_or_create_child("name")
+_tree_mixed_key_types.get_or_create_child(123)
+model["tree-mixed-key-types"] = _tree_mixed_key_types
+_tree_deep_nesting = Tree()
+_tree_deep_nesting.get_or_create_child("root").get_or_create_child("branch").get_or_create_child("leaf")
+model["tree-deep-nesting"] = _tree_deep_nesting
model["prop-path"] = Path(
[set(), set(), set()],
@@ -135,6 +176,10 @@ model["meta-vertexproperty"] = VertexProperty(1, "person",
"stephen", None, [Pro
model["set-cardinality-vertexproperty"] = VertexProperty(1, "person",
{"stephen", "marko"}, None, [Property("a", "b", None)])
model["id-t"] = T.id
model["out-direction"] = Direction.OUT
+model["merge-on-create"] = Merge.on_create
+model["merge-on-match"] = Merge.on_match
+model["merge-out-v"] = Merge.out_v
+model["merge-in-v"] = Merge.in_v
santa_fe = VertexProperty(
9, "location", "santa fe", None,
@@ -158,4 +203,82 @@ model["traversal-vertex"] = Vertex(1, "person", [
Property("name", name, None), Property("location", [
san_diego, santa_cruz, brussels, santa_fe
], None)])
-model["vertex-traverser"] = Traverser(model["traversal-vertex"], 1)
+model["multi-label-vertex"] = Vertex(1, labels=["person", "employee"])
+model["empty-label-vertex"] = Vertex(1, labels=[])
+
+
+class _CrewGraphFactory:
+ @staticmethod
+ def vertex_property(id, label, value, vertex, meta_properties=None):
+ vp = VertexProperty(id, label, value, vertex)
+ for key, meta_value in meta_properties or []:
+ vp.properties.append(Property(key, meta_value, vp))
+ return vp
+
+ @staticmethod
+ def add_vertex(graph, id, label, property_specs):
+ vertex = Vertex(id, label)
+ for spec in property_specs:
+ vertex.properties.append(
+ _CrewGraphFactory.vertex_property(
+ spec[0], spec[1], spec[2], vertex, spec[3] if len(spec) >
3 else []))
+ graph.vertices[id] = vertex
+ return vertex
+
+ @staticmethod
+ def add_edge(graph, id, out_v, label, in_v, properties=None):
+ edge = Edge(id, out_v, label, in_v)
+ for key, value in properties or []:
+ edge.properties.append(Property(key, value, edge))
+ graph.edges[id] = edge
+ return edge
+
+ @staticmethod
+ def create():
+ graph = Graph()
+ v1 = _CrewGraphFactory.add_vertex(graph, 1, "person", [
+ (0, "name", "marko"),
+ (6, "location", "san diego", [("startTime", 1997), ("endTime",
2001)]),
+ (7, "location", "santa cruz", [("startTime", 2001), ("endTime",
2004)]),
+ (8, "location", "brussels", [("startTime", 2004), ("endTime",
2005)]),
+ (9, "location", "santa fe", [("startTime", 2005)])
+ ])
+ v7 = _CrewGraphFactory.add_vertex(graph, 7, "person", [
+ (1, "name", "stephen"),
+ (10, "location", "centreville", [("startTime", 1990), ("endTime",
2000)]),
+ (11, "location", "dulles", [("startTime", 2000), ("endTime",
2006)]),
+ (12, "location", "purcellville", [("startTime", 2006)])
+ ])
+ v8 = _CrewGraphFactory.add_vertex(graph, 8, "person", [
+ (2, "name", "matthias"),
+ (13, "location", "bremen", [("startTime", 2004), ("endTime",
2007)]),
+ (14, "location", "baltimore", [("startTime", 2007), ("endTime",
2011)]),
+ (15, "location", "oakland", [("startTime", 2011), ("endTime",
2014)]),
+ (16, "location", "seattle", [("startTime", 2014)])
+ ])
+ v9 = _CrewGraphFactory.add_vertex(graph, 9, "person", [
+ (3, "name", "daniel"),
+ (17, "location", "spremberg", [("startTime", 1982), ("endTime",
2005)]),
+ (18, "location", "kaiserslautern", [("startTime", 2005),
("endTime", 2009)]),
+ (19, "location", "aachen", [("startTime", 2009)])
+ ])
+ v10 = _CrewGraphFactory.add_vertex(graph, 10, "software", [(4, "name",
"gremlin")])
+ v11 = _CrewGraphFactory.add_vertex(graph, 11, "software", [(5, "name",
"tinkergraph")])
+ _CrewGraphFactory.add_edge(graph, 13, v1, "develops", v10, [("since",
2009)])
+ _CrewGraphFactory.add_edge(graph, 14, v1, "develops", v11, [("since",
2010)])
+ _CrewGraphFactory.add_edge(graph, 15, v1, "uses", v10, [("skill", 4)])
+ _CrewGraphFactory.add_edge(graph, 16, v1, "uses", v11, [("skill", 5)])
+ _CrewGraphFactory.add_edge(graph, 17, v7, "develops", v10, [("since",
2010)])
+ _CrewGraphFactory.add_edge(graph, 18, v7, "develops", v11, [("since",
2011)])
+ _CrewGraphFactory.add_edge(graph, 19, v7, "uses", v10, [("skill", 5)])
+ _CrewGraphFactory.add_edge(graph, 20, v7, "uses", v11, [("skill", 4)])
+ _CrewGraphFactory.add_edge(graph, 21, v8, "develops", v10, [("since",
2012)])
+ _CrewGraphFactory.add_edge(graph, 22, v8, "uses", v10, [("skill", 3)])
+ _CrewGraphFactory.add_edge(graph, 23, v8, "uses", v11, [("skill", 3)])
+ _CrewGraphFactory.add_edge(graph, 24, v9, "uses", v10, [("skill", 5)])
+ _CrewGraphFactory.add_edge(graph, 25, v9, "uses", v11, [("skill", 3)])
+ _CrewGraphFactory.add_edge(graph, 26, v10, "traverses", v11)
+ return graph
+
+
+model["tinker-graph"] = _CrewGraphFactory.create()
diff --git
a/gremlin-python/src/main/python/tests/unit/structure/io/test_graphbinaryv4model.py
b/gremlin-python/src/main/python/tests/unit/structure/io/test_graphbinaryv4model.py
index 4ebc739584..dc8ed2a34f 100644
---
a/gremlin-python/src/main/python/tests/unit/structure/io/test_graphbinaryv4model.py
+++
b/gremlin-python/src/main/python/tests/unit/structure/io/test_graphbinaryv4model.py
@@ -38,6 +38,37 @@ test_resource_directory =
os.environ.get('IO_TEST_DIRECTORY', default_dir + grem
writer = GraphBinaryWriter()
reader = GraphBinaryReader()
+def decimal_cmp(x, y):
+ return x.scale == y.scale and x.unscaled_value == y.unscaled_value and
x.value == y.value
+
+def vertex_label_cmp(x, y):
+ return x == y and x.labels == y.labels
+
+def property_cmp(x, y):
+ return x.key == y.key and x.value == y.value
+
+def vertex_property_cmp(x, y):
+ return x == y and x.label == y.label and x.value == y.value and \
+ len(x.properties) == len(y.properties) and \
+ all(property_cmp(xp, yp) for xp, yp in zip(x.properties,
y.properties))
+
+def vertex_cmp(x, y):
+ return x == y and x.label == y.label and x.labels == y.labels and \
+ len(x.properties) == len(y.properties) and \
+ all(vertex_property_cmp(xp, yp) for xp, yp in zip(x.properties,
y.properties))
+
+def edge_cmp(x, y):
+ return x == y and x.label == y.label and x.labels == y.labels and \
+ x.outV == y.outV and x.inV == y.inV and \
+ len(x.properties) == len(y.properties) and \
+ all(property_cmp(xp, yp) for xp, yp in zip(x.properties,
y.properties))
+
+def graph_cmp(x, y):
+ return x.vertices.keys() == y.vertices.keys() and \
+ x.edges.keys() == y.edges.keys() and \
+ all(vertex_cmp(x.vertices[k], y.vertices[k]) for k in
x.vertices.keys()) and \
+ all(edge_cmp(x.edges[k], y.edges[k]) for k in x.edges.keys())
+
def get_entry(title):
return model[title]
@@ -47,23 +78,29 @@ def read_file_by_name(resource_name):
return bytearray(resource_file.read())
def test_pos_bigdecimal():
- def decimal_cmp(x, y):
- if x.scale == y.scale and x.unscaled_value == y.unscaled_value and
x.value == y.value:
- return True
- else:
- return False
-
+ # BigDecimal writes through Python BigInteger, which may not preserve
byte-exact sign padding.
run_writeread("pos-bigdecimal", decimal_cmp)
def test_neg_bigdecimal():
- def decimal_cmp(x, y):
- if x.scale == y.scale and x.unscaled_value == y.unscaled_value and
x.value == y.value:
- return True
- else:
- return False
-
+ # BigDecimal writes through Python BigInteger, which may not preserve
byte-exact sign padding.
run_writeread("neg-bigdecimal", decimal_cmp)
+def test_zero_bigdecimal():
+ # Use the same reduced mode as other Python BigDecimal model cases.
+ run_writeread("zero-bigdecimal", decimal_cmp)
+
+def test_scale_zero_bigdecimal():
+ # Use the same reduced mode as other Python BigDecimal model cases.
+ run_writeread("scale-zero-bigdecimal", decimal_cmp)
+
+def test_negative_scale_bigdecimal():
+ # Use the same reduced mode as other Python BigDecimal model cases.
+ run_writeread("negative-scale-bigdecimal", decimal_cmp)
+
+def test_small_decimal_bigdecimal():
+ # Use the same reduced mode as other Python BigDecimal model cases.
+ run_writeread("small-decimal-bigdecimal", decimal_cmp)
+
def test_pos_biginteger():
# gremlin-python adds an extra 0 byte to the value.
run_writeread("pos-biginteger")
@@ -72,6 +109,25 @@ def test_neg_biginteger():
# gremlin-python adds an extra 0 byte to the value.
run_writeread("neg-biginteger")
+def test_zero_biginteger():
+ # gremlin-python may add an extra sign-padding byte to the value.
+ run_writeread("zero-biginteger")
+
+def test_sign_boundary_pos_biginteger():
+ # gremlin-python may add an extra sign-padding byte to the value.
+ run_writeread("sign-boundary-pos-biginteger")
+
+def test_sign_boundary_neg_biginteger():
+ # gremlin-python can't serialize -129 because BigIntIO computes a byte
length
+ # that is too small for signed two's-complement encoding.
+ run_read("sign-boundary-neg-biginteger")
+
+def test_uint8_primitive_pdt():
+ run("uint8-primitive-pdt")
+
+def test_point_composite_pdt():
+ run("point-composite-pdt")
+
def test_min_byte():
run("min-byte")
@@ -116,6 +172,17 @@ def test_neg_zero_double():
def test_zero_duration():
run("zero-duration")
+def test_positive_duration():
+ run("positive-duration")
+
+def test_negative_duration():
+ # timedelta.seconds normalizes negative values, so the writer can't
preserve the wire value.
+ run_read("negative-duration")
+
+def test_nanos_duration():
+ # Python timedelta only preserves microseconds, not arbitrary nanoseconds.
+ run_read("nanos-duration")
+
def test_traversal_edge():
# properties aren't serialized in gremlin-python
run_writeread("traversal-edge")
@@ -151,6 +218,9 @@ def test_var_type_map():
def test_empty_map():
run("empty-map")
+def test_ordered_string_int_map():
+ run("ordered-string-int-map")
+
def test_traversal_path():
# gremlin-python serializes/deserializes "null" for props not empty list
run_writeread("traversal-path")
@@ -158,19 +228,29 @@ def test_traversal_path():
def test_empty_path():
run("empty-path")
+def test_path_zero_labels():
+ run("path-zero-labels")
+
+def test_path_multiple_labels():
+ # label set ordering isn't guaranteed after a Python object round trip.
+ run_writeread("path-multiple-labels")
+
def test_traversal_tree():
# gremlin-python doesn't serialize vertex properties, so the read tree's
# vertices have no properties; vertex equality is by id so the model
matches.
run_writeread("traversal-tree")
def test_empty_tree():
- # no .gbin resource exists for an empty tree, so exercise an in-memory
round trip
- from gremlin_python.structure.graph import Tree
- empty = model["empty-tree"]
- round_tripped = reader.read_object(writer.write_object(empty))
- assert isinstance(round_tripped, Tree)
- assert empty == round_tripped
- assert round_tripped.is_leaf()
+ run("empty-tree")
+
+def test_tree_null_key():
+ run("tree-null-key")
+
+def test_tree_mixed_key_types():
+ run("tree-mixed-key-types")
+
+def test_tree_deep_nesting():
+ run("tree-deep-nesting")
def test_prop_path():
# gremlin-python doesn't serialize properties
@@ -226,23 +306,57 @@ def test_out_direction():
run("out-direction")
def test_var_bulklist():
+ # BulkList is deserialized as a plain list, so the writer emits a regular
List.
run_read("var-bulklist")
-def test_var_bulklist():
+def test_empty_bulklist():
+ # BulkList is deserialized as a plain list, so the writer emits a regular
List.
run_read("empty-bulklist")
def test_single_byte_char():
# char is serialized as string
run_writeread("single-byte-char")
-def test_multi_byte_char():
+def test_two_byte_char():
# char is serialized as string
- run_writeread("multi-byte-char")
+ run_writeread("two-byte-char")
+
+def test_three_byte_char():
+ # char is serialized as string
+ run_writeread("three-byte-char")
+
+def test_four_byte_char():
+ # char is serialized as string
+ run_writeread("four-byte-char")
def test_unspecified_null():
# no serializer for plain null
run_writeread("unspecified-null")
+def test_null_int():
+ # typed nulls deserialize to plain None, so the original type can't be
re-emitted.
+ run_read("null-int")
+
+def test_null_long():
+ # typed nulls deserialize to plain None, so the original type can't be
re-emitted.
+ run_read("null-long")
+
+def test_null_string():
+ # typed nulls deserialize to plain None, so the original type can't be
re-emitted.
+ run_read("null-string")
+
+def test_null_list():
+ # typed nulls deserialize to plain None, so the original type can't be
re-emitted.
+ run_read("null-list")
+
+def test_null_map():
+ # typed nulls deserialize to plain None, so the original type can't be
re-emitted.
+ run_read("null-map")
+
+def test_null_set():
+ # typed nulls deserialize to plain None, so the original type can't be
re-emitted.
+ run_read("null-set")
+
def test_true_boolean():
run("true-boolean")
@@ -255,6 +369,38 @@ def test_single_byte_string():
def test_mixed_string():
run("mixed-string")
+def test_empty_string():
+ run("empty-string")
+
+def test_traversal_vertex():
+ # properties aren't serialized in gremlin-python
+ run_writeread("traversal-vertex")
+
+def test_multi_label_vertex():
+ # Vertex equality is id-only, so compare labels explicitly.
+ run_writeread("multi-label-vertex", vertex_label_cmp)
+
+def test_empty_label_vertex():
+ # Vertex equality is id-only, so compare labels explicitly.
+ run_writeread("empty-label-vertex", vertex_label_cmp)
+
+def test_tinker_graph():
+ # The hand-built graph is structurally equivalent, but it doesn't preserve
+ # every wire-level numeric type tag needed for byte-exact writes.
+ run_writeread("tinker-graph", graph_cmp)
+
+def test_merge_on_create():
+ run("merge-on-create")
+
+def test_merge_on_match():
+ run("merge-on-match")
+
+def test_merge_out_v():
+ run("merge-out-v")
+
+def test_merge_in_v():
+ run("merge-in-v")
+
def run(resource_name, comparator = None):
"""
Runs the regular set of tests for the type which is
@@ -315,4 +461,4 @@ def run_writeread(resource_name, comparator = None):
assert comparator(model, round_tripped)
else:
assert model == read
- assert model == round_tripped
\ No newline at end of file
+ assert model == round_tripped
diff --git
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSerializationIntegrateTest.java
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSerializationIntegrateTest.java
index 9e41f45d79..bbcbfd5738 100644
---
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSerializationIntegrateTest.java
+++
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSerializationIntegrateTest.java
@@ -338,8 +338,11 @@ public class GremlinServerSerializationIntegrateTest
extends AbstractGremlinServ
assertEquals("g:CompositePdt", pdtNode.get("@type").asText());
final JsonNode value = pdtNode.get(GraphSONTokens.VALUEPROP);
assertEquals("Point", value.get("type").asText());
- assertEquals(1,
value.get("fields").get("x").get(GraphSONTokens.VALUEPROP).intValue());
- assertEquals(2,
value.get("fields").get("y").get(GraphSONTokens.VALUEPROP).intValue());
+ final JsonNode fields =
value.get("fields").get(GraphSONTokens.VALUEPROP);
+ assertEquals("x", fields.get(0).asText());
+ assertEquals(1,
fields.get(1).get(GraphSONTokens.VALUEPROP).intValue());
+ assertEquals("y", fields.get(2).asText());
+ assertEquals(2,
fields.get(3).get(GraphSONTokens.VALUEPROP).intValue());
}
}
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/empty-label-vertex-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/empty-label-vertex-v4.gbin
new file mode 100644
index 0000000000..eae30101be
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/empty-label-vertex-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/empty-string-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/empty-string-v4.gbin
new file mode 100644
index 0000000000..f8287f3da7
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/empty-string-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/empty-tree-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/empty-tree-v4.gbin
new file mode 100644
index 0000000000..4be0227de7
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/empty-tree-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/four-byte-char-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/four-byte-char-v4.gbin
new file mode 100644
index 0000000000..ed5831f36f
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/four-byte-char-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/merge-in-v-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/merge-in-v-v4.gbin
new file mode 100644
index 0000000000..7998e4009f
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/merge-in-v-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/merge-on-create-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/merge-on-create-v4.gbin
new file mode 100644
index 0000000000..af8f22e257
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/merge-on-create-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/merge-on-match-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/merge-on-match-v4.gbin
new file mode 100644
index 0000000000..e31b45bfb2
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/merge-on-match-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/merge-out-v-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/merge-out-v-v4.gbin
new file mode 100644
index 0000000000..fafab80fb0
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/merge-out-v-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/multi-label-vertex-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/multi-label-vertex-v4.gbin
new file mode 100644
index 0000000000..f18f8fbbbd
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/multi-label-vertex-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/nanos-duration-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/nanos-duration-v4.gbin
new file mode 100644
index 0000000000..e73df638e5
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/nanos-duration-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/negative-duration-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/negative-duration-v4.gbin
new file mode 100644
index 0000000000..16d08d701a
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/negative-duration-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/negative-scale-bigdecimal-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/negative-scale-bigdecimal-v4.gbin
new file mode 100644
index 0000000000..9cb1daf9e2
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/negative-scale-bigdecimal-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-int-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-int-v4.gbin
new file mode 100644
index 0000000000..40fdece9d2
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-int-v4.gbin
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-list-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-list-v4.gbin
new file mode 100644
index 0000000000..93938cf057
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-list-v4.gbin
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-long-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-long-v4.gbin
new file mode 100644
index 0000000000..03afaa5de0
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-long-v4.gbin
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-map-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-map-v4.gbin
new file mode 100644
index 0000000000..bbe779818e
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-map-v4.gbin
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-set-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-set-v4.gbin
new file mode 100644
index 0000000000..d67137bfd2
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-set-v4.gbin
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-string-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-string-v4.gbin
new file mode 100644
index 0000000000..d8d3825962
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/null-string-v4.gbin
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/ordered-string-int-map-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/ordered-string-int-map-v4.gbin
new file mode 100644
index 0000000000..1e8097ca81
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/ordered-string-int-map-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/path-multiple-labels-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/path-multiple-labels-v4.gbin
new file mode 100644
index 0000000000..a01de6154a
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/path-multiple-labels-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/path-zero-labels-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/path-zero-labels-v4.gbin
new file mode 100644
index 0000000000..a456ed2bb5
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/path-zero-labels-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/point-composite-pdt-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/point-composite-pdt-v4.gbin
new file mode 100644
index 0000000000..3c5c3a5eb4
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/point-composite-pdt-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/positive-duration-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/positive-duration-v4.gbin
new file mode 100644
index 0000000000..11b750d97a
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/positive-duration-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/scale-zero-bigdecimal-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/scale-zero-bigdecimal-v4.gbin
new file mode 100644
index 0000000000..18bbdc206b
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/scale-zero-bigdecimal-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/sign-boundary-neg-biginteger-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/sign-boundary-neg-biginteger-v4.gbin
new file mode 100644
index 0000000000..fbf5e60d4e
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/sign-boundary-neg-biginteger-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/sign-boundary-pos-biginteger-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/sign-boundary-pos-biginteger-v4.gbin
new file mode 100644
index 0000000000..afcf9b041e
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/sign-boundary-pos-biginteger-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/small-decimal-bigdecimal-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/small-decimal-bigdecimal-v4.gbin
new file mode 100644
index 0000000000..321d4cfc1c
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/small-decimal-bigdecimal-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/three-byte-char-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/three-byte-char-v4.gbin
new file mode 100644
index 0000000000..e4927c407b
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/three-byte-char-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/tree-deep-nesting-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/tree-deep-nesting-v4.gbin
new file mode 100644
index 0000000000..72b0f37865
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/tree-deep-nesting-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/tree-mixed-key-types-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/tree-mixed-key-types-v4.gbin
new file mode 100644
index 0000000000..40f0ec93ea
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/tree-mixed-key-types-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/tree-null-key-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/tree-null-key-v4.gbin
new file mode 100644
index 0000000000..0d7f35dfa4
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/tree-null-key-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/multi-byte-char-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/two-byte-char-v4.gbin
similarity index 100%
rename from
gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/multi-byte-char-v4.gbin
rename to
gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/two-byte-char-v4.gbin
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/uint8-primitive-pdt-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/uint8-primitive-pdt-v4.gbin
new file mode 100644
index 0000000000..eb81eea59c
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/uint8-primitive-pdt-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/zero-bigdecimal-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/zero-bigdecimal-v4.gbin
new file mode 100644
index 0000000000..1e3af93198
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/zero-bigdecimal-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/zero-biginteger-v4.gbin
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/zero-biginteger-v4.gbin
new file mode 100644
index 0000000000..8cd75a9567
Binary files /dev/null and
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary/zero-biginteger-v4.gbin
differ
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/empty-label-vertex-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/empty-label-vertex-v4.json
new file mode 100644
index 0000000000..0d729d3637
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/empty-label-vertex-v4.json
@@ -0,0 +1,10 @@
+{
+ "@type" : "g:Vertex",
+ "@value" : {
+ "id" : {
+ "@type" : "g:Int32",
+ "@value" : 1
+ },
+ "label" : [ ]
+ }
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/empty-string-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/empty-string-v4.json
new file mode 100644
index 0000000000..3cc762b550
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/empty-string-v4.json
@@ -0,0 +1 @@
+""
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/merge-in-v-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/merge-in-v-v4.json
new file mode 100644
index 0000000000..3f56a2d5e1
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/merge-in-v-v4.json
@@ -0,0 +1,4 @@
+{
+ "@type" : "g:Merge",
+ "@value" : "inV"
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/merge-on-create-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/merge-on-create-v4.json
new file mode 100644
index 0000000000..b1f1094b4d
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/merge-on-create-v4.json
@@ -0,0 +1,4 @@
+{
+ "@type" : "g:Merge",
+ "@value" : "onCreate"
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/merge-on-match-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/merge-on-match-v4.json
new file mode 100644
index 0000000000..330dea4040
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/merge-on-match-v4.json
@@ -0,0 +1,4 @@
+{
+ "@type" : "g:Merge",
+ "@value" : "onMatch"
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/merge-out-v-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/merge-out-v-v4.json
new file mode 100644
index 0000000000..fa6342fd4e
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/merge-out-v-v4.json
@@ -0,0 +1,4 @@
+{
+ "@type" : "g:Merge",
+ "@value" : "outV"
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/multi-label-vertex-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/multi-label-vertex-v4.json
new file mode 100644
index 0000000000..a568881135
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/multi-label-vertex-v4.json
@@ -0,0 +1,10 @@
+{
+ "@type" : "g:Vertex",
+ "@value" : {
+ "id" : {
+ "@type" : "g:Int32",
+ "@value" : 1
+ },
+ "label" : [ "person", "employee" ]
+ }
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/nanos-duration-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/nanos-duration-v4.json
new file mode 100644
index 0000000000..9a7c0a6eac
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/nanos-duration-v4.json
@@ -0,0 +1,4 @@
+{
+ "@type" : "g:Duration",
+ "@value" : "PT2M3.000456789S"
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/negative-duration-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/negative-duration-v4.json
new file mode 100644
index 0000000000..ca738da37b
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/negative-duration-v4.json
@@ -0,0 +1,4 @@
+{
+ "@type" : "g:Duration",
+ "@value" : "PT-2M-3S"
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/negative-scale-bigdecimal-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/negative-scale-bigdecimal-v4.json
new file mode 100644
index 0000000000..e4e57921ae
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/negative-scale-bigdecimal-v4.json
@@ -0,0 +1,4 @@
+{
+ "@type" : "g:BigDecimal",
+ "@value" : 1.234E+5
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/ordered-string-int-map-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/ordered-string-int-map-v4.json
new file mode 100644
index 0000000000..fa7cc60b6a
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/ordered-string-int-map-v4.json
@@ -0,0 +1,22 @@
+{
+ "@type" : "g:Map",
+ "@value" : [ "delta", {
+ "@type" : "g:Int32",
+ "@value" : 4
+ }, "alpha", {
+ "@type" : "g:Int32",
+ "@value" : 1
+ }, "charlie", {
+ "@type" : "g:Int32",
+ "@value" : 3
+ }, "bravo", {
+ "@type" : "g:Int32",
+ "@value" : 2
+ }, "echo", {
+ "@type" : "g:Int32",
+ "@value" : 5
+ }, "foxtrot", {
+ "@type" : "g:Int32",
+ "@value" : 6
+ } ]
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/path-multiple-labels-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/path-multiple-labels-v4.json
new file mode 100644
index 0000000000..f1fc5c5f95
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/path-multiple-labels-v4.json
@@ -0,0 +1,16 @@
+{
+ "@type" : "g:Path",
+ "@value" : {
+ "labels" : {
+ "@type" : "g:List",
+ "@value" : [ {
+ "@type" : "g:Set",
+ "@value" : [ "a", "b" ]
+ } ]
+ },
+ "objects" : {
+ "@type" : "g:List",
+ "@value" : [ "marko" ]
+ }
+ }
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/path-zero-labels-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/path-zero-labels-v4.json
new file mode 100644
index 0000000000..055a9573de
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/path-zero-labels-v4.json
@@ -0,0 +1,16 @@
+{
+ "@type" : "g:Path",
+ "@value" : {
+ "labels" : {
+ "@type" : "g:List",
+ "@value" : [ {
+ "@type" : "g:Set",
+ "@value" : [ ]
+ } ]
+ },
+ "objects" : {
+ "@type" : "g:List",
+ "@value" : [ "marko" ]
+ }
+ }
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/point-composite-pdt-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/point-composite-pdt-v4.json
new file mode 100644
index 0000000000..39f2b188a8
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/point-composite-pdt-v4.json
@@ -0,0 +1,16 @@
+{
+ "@type" : "g:CompositePdt",
+ "@value" : {
+ "type" : "Point",
+ "fields" : {
+ "@type" : "g:Map",
+ "@value" : [ "x", {
+ "@type" : "g:Int32",
+ "@value" : 1
+ }, "y", {
+ "@type" : "g:Int32",
+ "@value" : 2
+ } ]
+ }
+ }
+}
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/positive-duration-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/positive-duration-v4.json
new file mode 100644
index 0000000000..9d25f26d45
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/positive-duration-v4.json
@@ -0,0 +1,4 @@
+{
+ "@type" : "g:Duration",
+ "@value" : "PT2M3S"
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/scale-zero-bigdecimal-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/scale-zero-bigdecimal-v4.json
new file mode 100644
index 0000000000..248f75b08b
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/scale-zero-bigdecimal-v4.json
@@ -0,0 +1,4 @@
+{
+ "@type" : "g:BigDecimal",
+ "@value" : 1234
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/sign-boundary-neg-biginteger-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/sign-boundary-neg-biginteger-v4.json
new file mode 100644
index 0000000000..ac8603df5f
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/sign-boundary-neg-biginteger-v4.json
@@ -0,0 +1,4 @@
+{
+ "@type" : "g:BigInteger",
+ "@value" : -129
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/sign-boundary-pos-biginteger-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/sign-boundary-pos-biginteger-v4.json
new file mode 100644
index 0000000000..adb4a52396
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/sign-boundary-pos-biginteger-v4.json
@@ -0,0 +1,4 @@
+{
+ "@type" : "g:BigInteger",
+ "@value" : 128
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/small-decimal-bigdecimal-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/small-decimal-bigdecimal-v4.json
new file mode 100644
index 0000000000..ff1cd1e182
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/small-decimal-bigdecimal-v4.json
@@ -0,0 +1,4 @@
+{
+ "@type" : "g:BigDecimal",
+ "@value" : 12.34
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/multi-byte-char-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/three-byte-char-v4.json
similarity index 54%
copy from
gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/multi-byte-char-v4.json
copy to
gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/three-byte-char-v4.json
index 46acefff3e..df42204445 100644
---
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/multi-byte-char-v4.json
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/three-byte-char-v4.json
@@ -1,4 +1,4 @@
{
"@type" : "g:Char",
- "@value" : "Ω"
+ "@value" : "€"
}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/multi-byte-char-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/two-byte-char-v4.json
similarity index 100%
rename from
gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/multi-byte-char-v4.json
rename to
gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/two-byte-char-v4.json
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/uint8-primitive-pdt-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/uint8-primitive-pdt-v4.json
new file mode 100644
index 0000000000..ae994ba0c3
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/uint8-primitive-pdt-v4.json
@@ -0,0 +1,7 @@
+{
+ "@type" : "g:PrimitivePdt",
+ "@value" : {
+ "type" : "Uint8",
+ "value" : "10"
+ }
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/zero-bigdecimal-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/zero-bigdecimal-v4.json
new file mode 100644
index 0000000000..ef5815d110
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/zero-bigdecimal-v4.json
@@ -0,0 +1,4 @@
+{
+ "@type" : "g:BigDecimal",
+ "@value" : 0
+}
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/zero-biginteger-v4.json
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/zero-biginteger-v4.json
new file mode 100644
index 0000000000..4c719fdb15
--- /dev/null
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/zero-biginteger-v4.json
@@ -0,0 +1,4 @@
+{
+ "@type" : "g:BigInteger",
+ "@value" : 0
+}
\ No newline at end of file
diff --git
a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/AbstractTypedCompatibilityTest.java
b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/AbstractTypedCompatibilityTest.java
index f38e9eb64d..a986c1b2be 100644
---
a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/AbstractTypedCompatibilityTest.java
+++
b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/AbstractTypedCompatibilityTest.java
@@ -20,6 +20,7 @@ package org.apache.tinkerpop.gremlin.structure.io;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
+import org.apache.tinkerpop.gremlin.process.traversal.Merge;
import org.apache.tinkerpop.gremlin.process.traversal.Operator;
import org.apache.tinkerpop.gremlin.process.traversal.Order;
import org.apache.tinkerpop.gremlin.process.traversal.P;
@@ -28,7 +29,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.Pop;
import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
import org.apache.tinkerpop.gremlin.process.traversal.Scope;
import org.apache.tinkerpop.gremlin.process.traversal.TextP;
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
import org.apache.tinkerpop.gremlin.process.traversal.util.Metrics;
@@ -42,6 +42,8 @@ import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.structure.VertexProperty;
import
org.apache.tinkerpop.gremlin.structure.io.graphbinary.GraphBinaryCompatibilityTest;
import
org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTypedCompatibilityTest;
+import org.apache.tinkerpop.gremlin.structure.io.pdt.CompositePDT;
+import org.apache.tinkerpop.gremlin.structure.io.pdt.PrimitivePDT;
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
import org.apache.tinkerpop.gremlin.util.function.Lambda;
import org.apache.tinkerpop.gremlin.util.message.RequestMessage;
@@ -73,6 +75,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -116,6 +119,57 @@ public abstract class AbstractTypedCompatibilityTest
extends AbstractCompatibili
assertEquals(resource, recycled);
}
+ @Test
+ public void shouldReadWriteZeroBigDecimal() throws Exception {
+ final String resourceName = "zero-bigdecimal";
+
+ final BigDecimal resource = findModelEntryObject(resourceName);
+ final BigDecimal fromStatic = read(readFromResource(resourceName),
BigDecimal.class);
+ final BigDecimal recycled = read(write(fromStatic, BigDecimal.class,
resourceName), BigDecimal.class);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteScaleZeroBigDecimal() throws Exception {
+ final String resourceName = "scale-zero-bigdecimal";
+
+ final BigDecimal resource = findModelEntryObject(resourceName);
+ final BigDecimal fromStatic = read(readFromResource(resourceName),
BigDecimal.class);
+ final BigDecimal recycled = read(write(fromStatic, BigDecimal.class,
resourceName), BigDecimal.class);
+ assertNotSame(fromStatic, recycled);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteNegativeScaleBigDecimal() throws Exception {
+ final String resourceName = "negative-scale-bigdecimal";
+
+ final BigDecimal resource = findModelEntryObject(resourceName);
+ final BigDecimal fromStatic = read(readFromResource(resourceName),
BigDecimal.class);
+ final BigDecimal recycled = read(write(fromStatic, BigDecimal.class,
resourceName), BigDecimal.class);
+ assertNotSame(fromStatic, recycled);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteSmallDecimalBigDecimal() throws Exception {
+ final String resourceName = "small-decimal-bigdecimal";
+
+ final BigDecimal resource = findModelEntryObject(resourceName);
+ final BigDecimal fromStatic = read(readFromResource(resourceName),
BigDecimal.class);
+ final BigDecimal recycled = read(write(fromStatic, BigDecimal.class,
resourceName), BigDecimal.class);
+ assertNotSame(fromStatic, recycled);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
@Test
public void shouldReadWritePositiveBigInteger() throws Exception {
final String resourceName = "pos-biginteger";
@@ -142,6 +196,44 @@ public abstract class AbstractTypedCompatibilityTest
extends AbstractCompatibili
assertEquals(resource, recycled);
}
+ @Test
+ public void shouldReadWriteZeroBigInteger() throws Exception {
+ final String resourceName = "zero-biginteger";
+
+ final BigInteger resource = findModelEntryObject(resourceName);
+ final BigInteger fromStatic = read(readFromResource(resourceName),
BigInteger.class);
+ final BigInteger recycled = read(write(fromStatic, BigInteger.class,
resourceName), BigInteger.class);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteSignBoundaryPositiveBigInteger() throws
Exception {
+ final String resourceName = "sign-boundary-pos-biginteger";
+
+ final BigInteger resource = findModelEntryObject(resourceName);
+ final BigInteger fromStatic = read(readFromResource(resourceName),
BigInteger.class);
+ final BigInteger recycled = read(write(fromStatic, BigInteger.class,
resourceName), BigInteger.class);
+ assertNotSame(fromStatic, recycled);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteSignBoundaryNegativeBigInteger() throws
Exception {
+ final String resourceName = "sign-boundary-neg-biginteger";
+
+ final BigInteger resource = findModelEntryObject(resourceName);
+ final BigInteger fromStatic = read(readFromResource(resourceName),
BigInteger.class);
+ final BigInteger recycled = read(write(fromStatic, BigInteger.class,
resourceName), BigInteger.class);
+ assertNotSame(fromStatic, recycled);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
@Test
public void shouldReadWriteMinByte() throws Exception {
final String resourceName = "min-byte";
@@ -329,6 +421,45 @@ public abstract class AbstractTypedCompatibilityTest
extends AbstractCompatibili
assertEquals(resource, recycled);
}
+ @Test
+ public void shouldReadWritePositiveDuration() throws Exception {
+ final String resourceName = "positive-duration";
+
+ final Duration resource = findModelEntryObject(resourceName);
+ final Duration fromStatic = read(readFromResource(resourceName),
Duration.class);
+ final Duration recycled = read(write(fromStatic, Duration.class,
resourceName), Duration.class);
+ assertNotSame(fromStatic, recycled);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteNegativeDuration() throws Exception {
+ final String resourceName = "negative-duration";
+
+ final Duration resource = findModelEntryObject(resourceName);
+ final Duration fromStatic = read(readFromResource(resourceName),
Duration.class);
+ final Duration recycled = read(write(fromStatic, Duration.class,
resourceName), Duration.class);
+ assertNotSame(fromStatic, recycled);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteNanosDuration() throws Exception {
+ final String resourceName = "nanos-duration";
+
+ final Duration resource = findModelEntryObject(resourceName);
+ final Duration fromStatic = read(readFromResource(resourceName),
Duration.class);
+ final Duration recycled = read(write(fromStatic, Duration.class,
resourceName), Duration.class);
+ assertNotSame(fromStatic, recycled);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
@Test
public void shouldReadWriteEdge() throws Exception {
final String resourceName = "traversal-edge";
@@ -559,6 +690,21 @@ public abstract class AbstractTypedCompatibilityTest
extends AbstractCompatibili
assertEquals(resource, recycled);
}
+ @Test
+ public void shouldReadWriteOrderedMap() throws Exception {
+ final String resourceName = "ordered-string-int-map";
+
+ final Map resource = findModelEntryObject(resourceName);
+ final Map fromStatic = read(readFromResource(resourceName), Map.class);
+ final Map recycled = read(write(fromStatic, Map.class, resourceName),
Map.class);
+ assertThat(fromStatic instanceof LinkedHashMap, is(true));
+ assertThat(recycled instanceof LinkedHashMap, is(true));
+ assertEquals(new ArrayList<>(resource.keySet()), new
ArrayList<>(fromStatic.keySet()));
+ assertEquals(new ArrayList<>(resource.keySet()), new
ArrayList<>(recycled.keySet()));
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
@Test
public void shouldReadWriteMaxOffsetDateTime() throws Exception {
final String resourceName = "max-offsetdatetime";
@@ -624,6 +770,32 @@ public abstract class AbstractTypedCompatibilityTest
extends AbstractCompatibili
assertEquals(resource, recycled);
}
+ @Test
+ public void shouldReadWritePathWithZeroLabels() throws Exception {
+ final String resourceName = "path-zero-labels";
+
+ final Path resource = findModelEntryObject(resourceName);
+ final Path fromStatic = read(readFromResource(resourceName),
Path.class);
+ final Path recycled = read(write(fromStatic, Path.class,
resourceName), Path.class);
+ assertNotSame(fromStatic, recycled);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWritePathWithMultipleLabels() throws Exception {
+ final String resourceName = "path-multiple-labels";
+
+ final Path resource = findModelEntryObject(resourceName);
+ final Path fromStatic = read(readFromResource(resourceName),
Path.class);
+ final Path recycled = read(write(fromStatic, Path.class,
resourceName), Path.class);
+ assertNotSame(fromStatic, recycled);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
@Test
public void shouldReadWriteEdgeProperty() throws Exception {
final String resourceName = "edge-property";
@@ -764,6 +936,34 @@ public abstract class AbstractTypedCompatibilityTest
extends AbstractCompatibili
assertVertex(resource, recycled);
}
+ @Test
+ public void shouldReadWriteMultiLabelVertex() throws Exception {
+ final String resourceName = "multi-label-vertex";
+
+ final Vertex resource = findModelEntryObject(resourceName);
+ final Vertex fromStatic = read(readFromResource(resourceName),
Vertex.class);
+ final Vertex recycled = read(write(fromStatic, Vertex.class,
resourceName), Vertex.class);
+ assertNotSame(fromStatic, recycled);
+ assertEquals(resource.id(), fromStatic.id());
+ assertEquals(resource.id(), recycled.id());
+ assertEquals(resource.labels(), fromStatic.labels());
+ assertEquals(resource.labels(), recycled.labels());
+ }
+
+ @Test
+ public void shouldReadWriteEmptyLabelVertex() throws Exception {
+ final String resourceName = "empty-label-vertex";
+
+ final Vertex resource = findModelEntryObject(resourceName);
+ final Vertex fromStatic = read(readFromResource(resourceName),
Vertex.class);
+ final Vertex recycled = read(write(fromStatic, Vertex.class,
resourceName), Vertex.class);
+ assertNotSame(fromStatic, recycled);
+ assertEquals(resource.id(), fromStatic.id());
+ assertEquals(resource.id(), recycled.id());
+ assertEquals(resource.labels(), fromStatic.labels());
+ assertEquals(resource.labels(), recycled.labels());
+ }
+
@Test
public void shouldReadWriteVertexProperty() throws Exception {
final String resourceName = "traversal-vertexproperty";
@@ -833,6 +1033,80 @@ public abstract class AbstractTypedCompatibilityTest
extends AbstractCompatibili
assertEquals(resource, recycled);
}
+ @Test
+ public void shouldReadWriteMergeOnCreate() throws Exception {
+ final String resourceName = "merge-on-create";
+
+ final Merge resource = findModelEntryObject(resourceName);
+ final Merge fromStatic = read(readFromResource(resourceName),
Merge.class);
+ final Merge recycled = read(write(fromStatic, Merge.class,
resourceName), Merge.class);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteMergeOnMatch() throws Exception {
+ final String resourceName = "merge-on-match";
+
+ final Merge resource = findModelEntryObject(resourceName);
+ final Merge fromStatic = read(readFromResource(resourceName),
Merge.class);
+ final Merge recycled = read(write(fromStatic, Merge.class,
resourceName), Merge.class);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteMergeOutV() throws Exception {
+ final String resourceName = "merge-out-v";
+
+ final Merge resource = findModelEntryObject(resourceName);
+ final Merge fromStatic = read(readFromResource(resourceName),
Merge.class);
+ final Merge recycled = read(write(fromStatic, Merge.class,
resourceName), Merge.class);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteMergeInV() throws Exception {
+ final String resourceName = "merge-in-v";
+
+ final Merge resource = findModelEntryObject(resourceName);
+ final Merge fromStatic = read(readFromResource(resourceName),
Merge.class);
+ final Merge recycled = read(write(fromStatic, Merge.class,
resourceName), Merge.class);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWritePrimitiveProviderDefinedType() throws Exception
{
+ final String resourceName = "uint8-primitive-pdt";
+
+ final PrimitivePDT resource = findModelEntryObject(resourceName);
+ final PrimitivePDT fromStatic = read(readFromResource(resourceName),
PrimitivePDT.class);
+ final PrimitivePDT recycled = read(write(fromStatic,
PrimitivePDT.class, resourceName), PrimitivePDT.class);
+ assertNotSame(fromStatic, recycled);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteCompositeProviderDefinedType() throws Exception
{
+ final String resourceName = "point-composite-pdt";
+
+ final CompositePDT resource = findModelEntryObject(resourceName);
+ final CompositePDT fromStatic = read(readFromResource(resourceName),
CompositePDT.class);
+ final CompositePDT recycled = read(write(fromStatic,
CompositePDT.class, resourceName), CompositePDT.class);
+ assertNotSame(fromStatic, recycled);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
@Test
public void shouldReadWriteVarBulkList() throws Exception {
final String resourceName = "var-bulklist";
@@ -876,8 +1150,20 @@ public abstract class AbstractTypedCompatibilityTest
extends AbstractCompatibili
}
@Test
- public void shouldReadWriteMultiByteChar() throws Exception {
- final String resourceName = "multi-byte-char";
+ public void shouldReadWriteTwoByteChar() throws Exception {
+ final String resourceName = "two-byte-char";
+
+ final Character resource = findModelEntryObject(resourceName);
+ final Character fromStatic = read(readFromResource(resourceName),
Character.class);
+ final Character recycled = read(write(fromStatic, Character.class,
resourceName), Character.class);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteThreeByteChar() throws Exception {
+ final String resourceName = "three-byte-char";
final Character resource = findModelEntryObject(resourceName);
final Character fromStatic = read(readFromResource(resourceName),
Character.class);
@@ -935,6 +1221,18 @@ public abstract class AbstractTypedCompatibilityTest
extends AbstractCompatibili
assertEquals(resource, recycled);
}
+ @Test
+ public void shouldReadWriteEmptyString() throws Exception {
+ final String resourceName = "empty-string";
+
+ final String resource = findModelEntryObject(resourceName);
+ final String fromStatic = read(readFromResource(resourceName),
String.class);
+ final String recycled = read(write(fromStatic, String.class,
resourceName), String.class);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
@Test
public void shouldReadWriteMixedString() throws Exception {
final String resourceName = "mixed-string";
diff --git
a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/Model.java
b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/Model.java
index dcec668220..ac08ad8313 100644
---
a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/Model.java
+++
b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/Model.java
@@ -20,15 +20,22 @@ package org.apache.tinkerpop.gremlin.structure.io;
import org.apache.commons.configuration2.BaseConfiguration;
import org.apache.commons.configuration2.Configuration;
+import org.apache.tinkerpop.gremlin.process.traversal.Merge;
+import org.apache.tinkerpop.gremlin.process.traversal.Path;
import
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyPath;
-import
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.MutablePath;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.io.pdt.CompositePDT;
+import org.apache.tinkerpop.gremlin.structure.io.pdt.PrimitivePDT;
import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedFactory;
import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedProperty;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
import
org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty;
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
@@ -49,6 +56,8 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -62,6 +71,9 @@ import static
org.apache.tinkerpop.gremlin.structure.util.detached.DetachedFacto
/**
* Defines the supported types for IO and the versions (and configurations) to
which they apply and are tested.
*
+ * The following GraphBinary model resources aren't supported by the Java
model:
+ * four-byte-char Character cannot represent a supplementary
Unicode code point as a single scalar value
+ *
* @author Stephen Mallette (http://stephen.genoprime.com)
*/
public class Model {
@@ -112,6 +124,14 @@ public class Model {
map.put(null, null);
addCoreEntry(map, "var-type-map", "Map is redefined so that to provide
the ability to allow for non-String keys, which is not possible in JSON.");
addCoreEntry(Collections.EMPTY_MAP, "empty-map");
+ final Map<Object,Object> orderedMap = new LinkedHashMap<>();
+ orderedMap.put("delta", 4);
+ orderedMap.put("alpha", 1);
+ orderedMap.put("charlie", 3);
+ orderedMap.put("bravo", 2);
+ orderedMap.put("echo", 5);
+ orderedMap.put("foxtrot", 6);
+ addCoreEntry(orderedMap, "ordered-string-int-map");
addCoreEntry(new HashSet<>(Arrays.asList(2, "person", true, null)),
"var-type-set", "Allows a JSON collection to behave as a Set.");
addCoreEntry(Collections.EMPTY_SET, "empty-set");
@@ -121,19 +141,42 @@ public class Model {
addCoreEntry(Direction.OUT, "out-direction", "");
addCoreEntry(T.id, "id-t", "");
+ addCoreEntry(Merge.onCreate, "merge-on-create", "");
+ addCoreEntry(Merge.onMatch, "merge-on-match", "");
+ addCoreEntry(Merge.outV, "merge-out-v", "");
+ addCoreEntry(Merge.inV, "merge-in-v", "");
addCoreEntry('a', "single-byte-char", "");
- addCoreEntry('\u03A9', "multi-byte-char", "");
+ addCoreEntry('\u03A9', "two-byte-char", "");
+ addCoreEntry('\u20AC', "three-byte-char", "");
addEntry("Core", () -> null, "unspecified-null", "");
+ addEntry("Typed Null", () -> null, "null-int", "");
+ addEntry("Typed Null", () -> null, "null-long", "");
+ addEntry("Typed Null", () -> null, "null-string", "");
+ addEntry("Typed Null", () -> null, "null-list", "");
+ addEntry("Typed Null", () -> null, "null-map", "");
+ addEntry("Typed Null", () -> null, "null-set", "");
addCoreEntry(true, "true-boolean", "");
addCoreEntry(false, "false-boolean", "");
addCoreEntry("abc", "single-byte-string", "");
addCoreEntry("abc\u0391\u0392\u0393", "mixed-string", "");
+ addCoreEntry("", "empty-string", "");
addCoreEntry(g.V(10).out().tree().next(), "traversal-tree", "");
+ addCoreEntry(new Tree<>(), "empty-tree", "");
+ final Tree<Object> nullKeyTree = new Tree<>();
+ nullKeyTree.getOrCreateChild(null);
+ addCoreEntry(nullKeyTree, "tree-null-key", "");
+ final Tree<Object> mixedKeyTree = new Tree<>();
+ mixedKeyTree.getOrCreateChild("name");
+ mixedKeyTree.getOrCreateChild(123);
+ addCoreEntry(mixedKeyTree, "tree-mixed-key-types", "");
+ final Tree<Object> deepTree = new Tree<>();
+
deepTree.getOrCreateChild("root").getOrCreateChild("branch").getOrCreateChild("leaf");
+ addCoreEntry(deepTree, "tree-deep-nesting", "");
addGraphStructureEntry(graph.edges().next(), "traversal-edge", "");
addGraphStructureEntry(DetachedFactory.detach(graph.edges().next(),
false), "no-prop-edge", "");
@@ -141,6 +184,10 @@ public class Model {
addGraphStructureEntry(detach(g.V().out().out().path().next(), false),
"traversal-path", "");
addGraphStructureEntry(EmptyPath.instance(), "empty-path", "");
addGraphStructureEntry(detach(g.V().out().out().path().next(), true),
"prop-path", "");
+ final Path zeroLabelsPath = MutablePath.make().extend("marko",
Collections.emptySet());
+ addGraphStructureEntry(zeroLabelsPath, "path-zero-labels", "");
+ final Path multipleLabelsPath = MutablePath.make().extend("marko", new
LinkedHashSet<>(Arrays.asList("a", "b")));
+ addGraphStructureEntry(multipleLabelsPath, "path-multiple-labels", "");
addGraphStructureEntry(graph.edges().next().properties().next(),
"edge-property", "");
addGraphStructureEntry(new DetachedProperty<>("", null),
"null-property", "");
@@ -149,6 +196,16 @@ public class Model {
addGraphStructureEntry(graph.vertices().next(), "traversal-vertex",
"");
addGraphStructureEntry(DetachedFactory.detach(graph.vertices().next(),
false), "no-prop-vertex", "");
+ final Vertex multiLabelVertex = DetachedVertex.build()
+ .setId(1)
+ .setLabels(new LinkedHashSet<>(Arrays.asList("person",
"employee")))
+ .create();
+ addGraphStructureEntry(multiLabelVertex, "multi-label-vertex", "");
+ final Vertex emptyLabelVertex = DetachedVertex.build()
+ .setId(1)
+ .setLabels(Collections.emptySet())
+ .create();
+ addGraphStructureEntry(emptyLabelVertex, "empty-label-vertex", "");
addGraphStructureEntry(graph.vertices().next().properties().next(),
"traversal-vertexproperty", "");
final Map<String,Object> metaProperties = new HashMap<>();
@@ -165,15 +222,24 @@ public class Model {
addGraphProcessEntry(bulkSet, "var-bulklist", "");
addGraphProcessEntry(new BulkSet(), "empty-bulklist", "");
-
addGraphProcessEntry(g.V().hasLabel("person").asAdmin().nextTraverser(),
"vertex-traverser", "");
- addGraphProcessEntry(g.V().both().barrier().asAdmin().nextTraverser(),
"bulked-traverser", "");
- addGraphProcessEntry(EmptyTraverser.instance(), "empty-traverser", "");
-
addExtendedEntry(new
BigDecimal("123.456789987654321123456789987654321"), "pos-bigdecimal", "");
addExtendedEntry(new
BigDecimal("-123.456789987654321123456789987654321"), "neg-bigdecimal", "");
+ addExtendedEntry(BigDecimal.ZERO, "zero-bigdecimal", "");
+ addExtendedEntry(new BigDecimal(new BigInteger("1234"), 0),
"scale-zero-bigdecimal", "");
+ addExtendedEntry(new BigDecimal(new BigInteger("1234"), -2),
"negative-scale-bigdecimal", "");
+ addExtendedEntry(new BigDecimal("12.34"), "small-decimal-bigdecimal",
"");
addExtendedEntry(new
BigInteger("123456789987654321123456789987654321"), "pos-biginteger", "");
addExtendedEntry(new
BigInteger("-123456789987654321123456789987654321"), "neg-biginteger", "");
+ addExtendedEntry(BigInteger.ZERO, "zero-biginteger", "");
+ addExtendedEntry(BigInteger.valueOf(128),
"sign-boundary-pos-biginteger", "");
+ addExtendedEntry(BigInteger.valueOf(-129),
"sign-boundary-neg-biginteger", "");
+
+ addExtendedEntry(new PrimitivePDT("Uint8", "10"),
"uint8-primitive-pdt", "");
+ final Map<String,Object> pointFields = new LinkedHashMap<>();
+ pointFields.put("x", 1);
+ pointFields.put("y", 2);
+ addExtendedEntry(new CompositePDT("Point", pointFields),
"point-composite-pdt", "");
addExtendedEntry(Byte.MAX_VALUE, "max-byte", "");
addExtendedEntry(Byte.MIN_VALUE, "min-byte", "");
@@ -183,6 +249,9 @@ public class Model {
addExtendedEntry(Duration.ZERO, "zero-duration","The following example
is a zero `Duration`");
addExtendedEntry(ChronoUnit.FOREVER.getDuration(),
"forever-duration","");
+ addExtendedEntry(Duration.ofSeconds(123), "positive-duration","");
+ addExtendedEntry(Duration.ofSeconds(-123), "negative-duration","");
+ addExtendedEntry(Duration.ofSeconds(123, 456789), "nanos-duration","");
addExtendedEntry(OffsetDateTime.MAX, "max-offsetdatetime", "");
addExtendedEntry(OffsetDateTime.MIN, "min-offsetdatetime", "");
diff --git
a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphbinary/GraphBinaryCompatibilityTest.java
b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphbinary/GraphBinaryCompatibilityTest.java
index 092c1adf6c..7ede7cfab5 100644
---
a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphbinary/GraphBinaryCompatibilityTest.java
+++
b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphbinary/GraphBinaryCompatibilityTest.java
@@ -21,11 +21,13 @@ package
org.apache.tinkerpop.gremlin.structure.io.graphbinary;
import io.netty.buffer.ByteBufAllocator;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
import
org.apache.tinkerpop.gremlin.structure.io.AbstractTypedCompatibilityTest;
import org.apache.tinkerpop.gremlin.structure.io.Buffer;
import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryReader;
import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryWriter;
import org.apache.tinkerpop.gremlin.util.ser.NettyBufferFactory;
+import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -33,6 +35,12 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
/**
* @author Stephen Mallette (http://stephen.genoprime.com)
@@ -107,6 +115,102 @@ public class GraphBinaryCompatibilityTest extends
AbstractTypedCompatibilityTest
}
}
+ @Test
+ public void shouldReadNullInt() throws Exception {
+ final String resourceName = "null-int";
+
+ final Integer fromStatic = read(readFromResource(resourceName),
Integer.class);
+ assertNull(fromStatic);
+ }
+
+ @Test
+ public void shouldReadNullLong() throws Exception {
+ final String resourceName = "null-long";
+
+ final Long fromStatic = read(readFromResource(resourceName),
Long.class);
+ assertNull(fromStatic);
+ }
+
+ @Test
+ public void shouldReadNullString() throws Exception {
+ final String resourceName = "null-string";
+
+ final String fromStatic = read(readFromResource(resourceName),
String.class);
+ assertNull(fromStatic);
+ }
+
+ @Test
+ public void shouldReadNullList() throws Exception {
+ final String resourceName = "null-list";
+
+ final List fromStatic = read(readFromResource(resourceName),
List.class);
+ assertNull(fromStatic);
+ }
+
+ @Test
+ public void shouldReadNullMap() throws Exception {
+ final String resourceName = "null-map";
+
+ final Map fromStatic = read(readFromResource(resourceName), Map.class);
+ assertNull(fromStatic);
+ }
+
+ @Test
+ public void shouldReadNullSet() throws Exception {
+ final String resourceName = "null-set";
+
+ final Set fromStatic = read(readFromResource(resourceName), Set.class);
+ assertNull(fromStatic);
+ }
+
+ @Test
+ public void shouldReadWriteEmptyTree() throws Exception {
+ final String resourceName = "empty-tree";
+
+ final Tree resource = findModelEntryObject(resourceName);
+ final Tree fromStatic = read(readFromResource(resourceName),
Tree.class);
+ final Tree recycled = read(write(fromStatic, Tree.class,
resourceName), Tree.class);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteTreeWithNullKey() throws Exception {
+ final String resourceName = "tree-null-key";
+
+ final Tree resource = findModelEntryObject(resourceName);
+ final Tree fromStatic = read(readFromResource(resourceName),
Tree.class);
+ final Tree recycled = read(write(fromStatic, Tree.class,
resourceName), Tree.class);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteTreeWithMixedKeyTypes() throws Exception {
+ final String resourceName = "tree-mixed-key-types";
+
+ final Tree resource = findModelEntryObject(resourceName);
+ final Tree fromStatic = read(readFromResource(resourceName),
Tree.class);
+ final Tree recycled = read(write(fromStatic, Tree.class,
resourceName), Tree.class);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
+ @Test
+ public void shouldReadWriteTreeWithDeepNesting() throws Exception {
+ final String resourceName = "tree-deep-nesting";
+
+ final Tree resource = findModelEntryObject(resourceName);
+ final Tree fromStatic = read(readFromResource(resourceName),
Tree.class);
+ final Tree recycled = read(write(fromStatic, Tree.class,
resourceName), Tree.class);
+ assertEquals(fromStatic, recycled);
+ assertEquals(resource, fromStatic);
+ assertEquals(resource, recycled);
+ }
+
// TODO: revisit
// @Override
// public void shouldReadWriteAuthenticationChallenge() throws Exception {