You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2017/07/18 13:08:57 UTC

[05/43] tinkerpop git commit: Add Gremlin-CSharp and Gremlin-DotNet

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/37a24719/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
new file mode 100644
index 0000000..747a94e
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
@@ -0,0 +1,308 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using Gremlin.Net.Structure;
+using Gremlin.Net.Structure.IO.GraphSON;
+using Moq;
+using Newtonsoft.Json.Linq;
+using Xunit;
+
+namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
+{
+    public class GraphSONReaderTests
+    {
+        private GraphSONReader CreateStandardGraphSONReader()
+        {
+            return new GraphSONReader();
+        }
+
+        [Fact]
+        public void ShouldDeserializeWithCustomDeserializerForNewType()
+        {
+            var deserializerByGraphSONType = new Dictionary<string, IGraphSONDeserializer>
+            {
+                {"NS:TestClass", new TestGraphSONDeserializer()}
+            };
+            var reader = new GraphSONReader(deserializerByGraphSONType);
+            var graphSON = "{\"@type\":\"NS:TestClass\",\"@value\":\"test\"}";
+
+            var jObject = JObject.Parse(graphSON);
+            var readObj = reader.ToObject(jObject);
+
+            Assert.Equal("test", readObj.Value);
+        }
+
+        [Fact]
+        public void ShouldDeserializeWithCustomDeserializerForCommonType()
+        {
+            var customSerializerMock = new Mock<IGraphSONDeserializer>();
+            var overrideTypeString = "g:Int64";
+            var customSerializerByType = new Dictionary<string, IGraphSONDeserializer>
+            {
+                {overrideTypeString, customSerializerMock.Object}
+            };
+            var reader = new GraphSONReader(customSerializerByType);
+
+
+            reader.ToObject(JObject.Parse($"{{\"@type\":\"{overrideTypeString}\",\"@value\":12}}"));
+
+            customSerializerMock.Verify(m => m.Objectify(It.IsAny<JToken>(), It.IsAny<GraphSONReader>()));
+        }
+
+        [Fact]
+        public void ShouldDeserializeDateToDateTime()
+        {
+            var graphSon = "{\"@type\":\"g:Date\",\"@value\":1475583442552}";
+            var reader = CreateStandardGraphSONReader();
+
+            DateTime readDateTime = reader.ToObject(JObject.Parse(graphSon));
+
+            var expectedDateTime = TestUtils.FromJavaTime(1475583442552);
+            Assert.Equal(expectedDateTime, readDateTime);
+        }
+
+        [Fact]
+        public void ShouldDeserializeDictionary()
+        {
+            var serializedDict = "{\"age\":[{\"@type\":\"g:Int32\",\"@value\":29}],\"name\":[\"marko\"]}";
+            var reader = CreateStandardGraphSONReader();
+
+            var jObject = JObject.Parse(serializedDict);
+            var deserializedDict = reader.ToObject(jObject);
+
+            var expectedDict = new Dictionary<string, dynamic>
+            {
+                {"age", new List<object> {29}},
+                {"name", new List<object> {"marko"}}
+            };
+            Assert.Equal(expectedDict, deserializedDict);
+        }
+
+        [Fact]
+        public void ShouldDeserializeEdge()
+        {
+            var graphSon =
+                "{\"@type\":\"g:Edge\", \"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":17},\"label\":\"knows\",\"inV\":\"x\",\"outV\":\"y\",\"inVLabel\":\"xLab\",\"properties\":{\"aKey\":\"aValue\",\"bKey\":true}}}";
+            var reader = CreateStandardGraphSONReader();
+
+            Edge readEdge = reader.ToObject(JObject.Parse(graphSon));
+
+            Assert.Equal((long) 17, readEdge.Id);
+            Assert.Equal("knows", readEdge.Label);
+            Assert.Equal(new Vertex("x", "xLabel"), readEdge.InV);
+            Assert.Equal(new Vertex("y"), readEdge.OutV);
+        }
+
+        [Fact]
+        public void ShouldDeserializeInt()
+        {
+            var serializedValue = "{\"@type\":\"g:Int32\",\"@value\":5}";
+            var reader = CreateStandardGraphSONReader();
+
+            var jObject = JObject.Parse(serializedValue);
+            var deserializedValue = reader.ToObject(jObject);
+
+            Assert.Equal(5, deserializedValue);
+        }
+
+        [Fact]
+        public void ShouldDeserializeLong()
+        {
+            var serializedValue = "{\"@type\":\"g:Int64\",\"@value\":5}";
+            var reader = CreateStandardGraphSONReader();
+
+            var jObject = JObject.Parse(serializedValue);
+            var deserializedValue = reader.ToObject(jObject);
+
+            Assert.Equal((long) 5, deserializedValue);
+        }
+
+        [Fact]
+        public void ShouldDeserializeFloat()
+        {
+            var serializedValue = "{\"@type\":\"g:Float\",\"@value\":31.3}";
+            var reader = CreateStandardGraphSONReader();
+
+            var jObject = JObject.Parse(serializedValue);
+            var deserializedValue = reader.ToObject(jObject);
+
+            Assert.Equal((float) 31.3, deserializedValue);
+        }
+
+        [Fact]
+        public void ShouldDeserializeDouble()
+        {
+            var serializedValue = "{\"@type\":\"g:Double\",\"@value\":31.2}";
+            var reader = CreateStandardGraphSONReader();
+
+            var jObject = JObject.Parse(serializedValue);
+            var deserializedValue = reader.ToObject(jObject);
+
+            Assert.Equal(31.2, deserializedValue);
+        }
+
+        [Fact]
+        public void ShouldDeserializeList()
+        {
+            var serializedValue = "[{\"@type\":\"g:Int32\",\"@value\":5},{\"@type\":\"g:Int32\",\"@value\":6}]";
+            var reader = CreateStandardGraphSONReader();
+
+            var jObject = JArray.Parse(serializedValue);
+            var deserializedValue = reader.ToObject(jObject);
+
+            Assert.Equal(new List<object> {5, 6}, deserializedValue);
+        }
+
+        [Fact]
+        public void ShouldDeserializePath()
+        {
+            var graphSon =
+                "{\"@type\":\"g:Path\",\"@value\":{\"labels\":[[\"a\"],[\"b\",\"c\"],[]],\"objects\":[{\"@type\":\"g:Vertex\",\"@value\":{\"id\":{\"@type\":\"g:Int32\",\"@value\":1},\"label\":\"person\",\"properties\":{\"name\":[{\"@type\":\"g:VertexProperty\",\"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":0},\"value\":\"marko\",\"label\":\"name\"}}],\"age\":[{\"@type\":\"g:VertexProperty\",\"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":1},\"value\":{\"@type\":\"g:Int32\",\"@value\":29},\"label\":\"age\"}}]}}},{\"@type\":\"g:Vertex\",\"@value\":{\"id\":{\"@type\":\"g:Int32\",\"@value\":3},\"label\":\"software\",\"properties\":{\"name\":[{\"@type\":\"g:VertexProperty\",\"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":4},\"value\":\"lop\",\"label\":\"name\"}}],\"lang\":[{\"@type\":\"g:VertexProperty\",\"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":5},\"value\":\"java\",\"label\":\"lang\"}}]}}},\"lop\"]}}";
+            var reader = CreateStandardGraphSONReader();
+
+            Path readPath = reader.ToObject(JObject.Parse(graphSon));
+
+            Assert.Equal("[v[1], v[3], lop]", readPath.ToString());
+            Assert.Equal(new Vertex(1), readPath[0]);
+            Assert.Equal(new Vertex(1), readPath["a"]);
+            Assert.Equal("lop", readPath[2]);
+            Assert.Equal(3, readPath.Count);
+        }
+
+        [Fact]
+        public void ShouldDeserializePropertyWithEdgeElement()
+        {
+            var graphSon =
+                "{\"@type\":\"g:Property\",\"@value\":{\"key\":\"aKey\",\"value\":{\"@type\":\"g:Int64\",\"@value\":17},\"element\":{\"@type\":\"g:Edge\",\"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":122},\"label\":\"knows\",\"inV\":\"x\",\"outV\":\"y\",\"inVLabel\":\"xLab\"}}}}";
+            var reader = CreateStandardGraphSONReader();
+
+            Property readProperty = reader.ToObject(JObject.Parse(graphSon));
+
+            Assert.Equal("aKey", readProperty.Key);
+            Assert.Equal((long) 17, readProperty.Value);
+            Assert.Equal(typeof(Edge), readProperty.Element.GetType());
+            var edge = readProperty.Element as Edge;
+            Assert.Equal((long) 122, edge.Id);
+            Assert.Equal("knows", edge.Label);
+            Assert.Equal("x", edge.InV.Id);
+            Assert.Equal("y", edge.OutV.Id);
+        }
+
+        [Fact]
+        public void ShouldDeserializeTimestampToDateTime()
+        {
+            var graphSon = "{\"@type\":\"g:Timestamp\",\"@value\":1475583442558}";
+            var reader = CreateStandardGraphSONReader();
+
+            DateTime readDateTime = reader.ToObject(JObject.Parse(graphSon));
+
+            var expectedDateTime = TestUtils.FromJavaTime(1475583442558);
+            Assert.Equal(expectedDateTime, readDateTime);
+        }
+
+        [Fact]
+        public void ShouldDeserializeGuid()
+        {
+            var graphSon = "{\"@type\":\"g:UUID\",\"@value\":\"41d2e28a-20a4-4ab0-b379-d810dede3786\"}";
+            var reader = CreateStandardGraphSONReader();
+
+            Guid readGuid = reader.ToObject(JObject.Parse(graphSon));
+
+            Assert.Equal(Guid.Parse("41d2e28a-20a4-4ab0-b379-d810dede3786"), readGuid);
+        }
+
+        [Fact]
+        public void ShouldDeserializeVertexProperty()
+        {
+            var graphSon =
+                "{\"@type\":\"g:VertexProperty\",\"@value\":{\"id\":\"anId\",\"label\":\"aKey\",\"value\":true,\"vertex\":{\"@type\":\"g:Int32\",\"@value\":9}}}";
+            var reader = CreateStandardGraphSONReader();
+
+            VertexProperty readVertexProperty = reader.ToObject(JObject.Parse(graphSon));
+
+            Assert.Equal("anId", readVertexProperty.Id);
+            Assert.Equal("aKey", readVertexProperty.Label);
+            Assert.True(readVertexProperty.Value);
+            Assert.NotNull(readVertexProperty.Vertex);
+        }
+
+        [Fact]
+        public void ShouldDeserializeVertexPropertyWithLabel()
+        {
+            var graphSon =
+                "{\"@type\":\"g:VertexProperty\", \"@value\":{\"id\":{\"@type\":\"g:Int32\",\"@value\":1},\"label\":\"name\",\"value\":\"marko\"}}";
+            var reader = CreateStandardGraphSONReader();
+
+            VertexProperty readVertexProperty = reader.ToObject(JObject.Parse(graphSon));
+
+            Assert.Equal(1, readVertexProperty.Id);
+            Assert.Equal("name", readVertexProperty.Label);
+            Assert.Equal("marko", readVertexProperty.Value);
+            Assert.Null(readVertexProperty.Vertex);
+        }
+
+        [Fact]
+        public void ShouldDeserializeVertex()
+        {
+            var graphSon = "{\"@type\":\"g:Vertex\", \"@value\":{\"id\":{\"@type\":\"g:Float\",\"@value\":45.23}}}";
+            var reader = CreateStandardGraphSONReader();
+
+            var readVertex = reader.ToObject(JObject.Parse(graphSon));
+
+            Assert.Equal(new Vertex(45.23f), readVertex);
+        }
+
+        [Fact]
+        public void ShouldDeserializeVertexWithEdges()
+        {
+            var graphSon =
+                "{\"@type\":\"g:Vertex\", \"@value\":{\"id\":{\"@type\":\"g:Int32\",\"@value\":1},\"label\":\"person\",\"outE\":{\"created\":[{\"id\":{\"@type\":\"g:Int32\",\"@value\":9},\"inV\":{\"@type\":\"g:Int32\",\"@value\":3},\"properties\":{\"weight\":{\"@type\":\"g:Double\",\"@value\":0.4}}}],\"knows\":[{\"id\":{\"@type\":\"g:Int32\",\"@value\":7},\"inV\":{\"@type\":\"g:Int32\",\"@value\":2},\"properties\":{\"weight\":{\"@type\":\"g:Double\",\"@value\":0.5}}},{\"id\":{\"@type\":\"g:Int32\",\"@value\":8},\"inV\":{\"@type\":\"g:Int32\",\"@value\":4},\"properties\":{\"weight\":{\"@type\":\"g:Double\",\"@value\":1.0}}}]},\"properties\":{\"name\":[{\"id\":{\"@type\":\"g:Int64\",\"@value\":0},\"value\":\"marko\"}],\"age\":[{\"id\":{\"@type\":\"g:Int64\",\"@value\":1},\"value\":{\"@type\":\"g:Int32\",\"@value\":29}}]}}}";
+            var reader = CreateStandardGraphSONReader();
+
+            var readVertex = reader.ToObject(JObject.Parse(graphSon));
+
+            Assert.Equal(new Vertex(1), readVertex);
+            Assert.Equal("person", readVertex.Label);
+            Assert.Equal(typeof(int), readVertex.Id.GetType());
+        }
+
+        [Fact]
+        public void ShouldDeserializeTraverser()
+        {
+            dynamic d = JObject.Parse("{\"@type\":\"g:Traverser\",\"@value\":1}");
+
+            Assert.NotNull(d);
+            Assert.Equal("g:Traverser", (string)d["@type"]);
+        }
+    }
+
+    internal class TestGraphSONDeserializer : IGraphSONDeserializer
+    {
+        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        {
+            return new TestClass {Value = graphsonObject.ToString()};
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/37a24719/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs
new file mode 100644
index 0000000..49786d7
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs
@@ -0,0 +1,329 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using Gremlin.Net.Process.Traversal;
+using Gremlin.Net.Structure;
+using Gremlin.Net.Structure.IO.GraphSON;
+using Moq;
+using Xunit;
+
+namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
+{
+    public class GraphSONWriterTests
+    {
+        private GraphSONWriter CreateStandardGraphSONWriter()
+        {
+            return new GraphSONWriter();
+        }
+
+        [Fact]
+        public void ShouldSerializeInt()
+        {
+            var writer = CreateStandardGraphSONWriter();
+
+            var graphSon = writer.WriteObject(1);
+
+            Assert.Equal("{\"@type\":\"g:Int32\",\"@value\":1}", graphSon);
+        }
+
+        [Fact]
+        public void ShouldSerializeLong()
+        {
+            var writer = CreateStandardGraphSONWriter();
+
+            var graphSon = writer.WriteObject((long) 2);
+
+            Assert.Equal("{\"@type\":\"g:Int64\",\"@value\":2}", graphSon);
+        }
+
+        [Fact]
+        public void ShouldSerializeFloat()
+        {
+            var writer = CreateStandardGraphSONWriter();
+
+            var graphSon = writer.WriteObject((float) 3.2);
+
+            Assert.Equal("{\"@type\":\"g:Float\",\"@value\":3.2}", graphSon);
+        }
+
+        [Fact]
+        public void ShouldSerializeDouble()
+        {
+            var writer = CreateStandardGraphSONWriter();
+
+            var graphSon = writer.WriteObject(3.2);
+
+            Assert.Equal("{\"@type\":\"g:Double\",\"@value\":3.2}", graphSon);
+        }
+
+        [Fact]
+        public void ShouldSerializeBoolean()
+        {
+            var writer = CreateStandardGraphSONWriter();
+
+            var graphSon = writer.WriteObject(true);
+
+            Assert.Equal("true", graphSon);
+        }
+
+        [Fact]
+        public void ShouldSerializeArray()
+        {
+            var writer = CreateStandardGraphSONWriter();
+            var array = new[] {5, 6};
+
+            var serializedGraphSON = writer.WriteObject(array);
+
+            var expectedGraphSON = "[{\"@type\":\"g:Int32\",\"@value\":5},{\"@type\":\"g:Int32\",\"@value\":6}]";
+            Assert.Equal(expectedGraphSON, serializedGraphSON);
+        }
+
+        [Fact]
+        public void ShouldSerializeBinding()
+        {
+            var writer = CreateStandardGraphSONWriter();
+            var binding = new Binding("theKey", 123);
+
+            var graphSon = writer.WriteObject(binding);
+
+            const string expected =
+                "{\"@type\":\"g:Binding\",\"@value\":{\"value\":{\"@type\":\"g:Int32\",\"@value\":123},\"key\":\"theKey\"}}";
+            Assert.Equal(expected, graphSon);
+        }
+
+        [Fact]
+        public void ShouldSerializeWithCustomSerializerForNewType()
+        {
+            var customSerializerByType = new Dictionary<Type, IGraphSONSerializer>
+            {
+                {typeof(TestClass), new TestGraphSONSerializer {TestNamespace = "NS"}}
+            };
+            var writer = new GraphSONWriter(customSerializerByType);
+            var testObj = new TestClass {Value = "test"};
+
+            var serialized = writer.WriteObject(testObj);
+
+            Assert.Equal("{\"@type\":\"NS:TestClass\",\"@value\":\"test\"}", serialized);
+        }
+
+        [Fact]
+        public void ShouldSerializeWithCustomSerializerForCommonType()
+        {
+            var customSerializerMock = new Mock<IGraphSONSerializer>();
+            var customSerializerByType = new Dictionary<Type, IGraphSONSerializer>
+            {
+                {typeof(int), customSerializerMock.Object}
+            };
+            var writer = new GraphSONWriter(customSerializerByType);
+
+            writer.WriteObject(12);
+
+            customSerializerMock.Verify(m => m.Dictify(It.Is<int>(v => v == 12), It.IsAny<GraphSONWriter>()));
+        }
+
+        [Fact]
+        public void ShouldSerializeDateTime()
+        {
+            var writer = CreateStandardGraphSONWriter();
+            var dateTime = TestUtils.FromJavaTime(1475583442552);
+
+            var graphSon = writer.WriteObject(dateTime);
+
+            const string expected = "{\"@type\":\"g:Date\",\"@value\":1475583442552}";
+            Assert.Equal(expected, graphSon);
+        }
+
+        [Fact]
+        public void ShouldSerializeDictionary()
+        {
+            var writer = CreateStandardGraphSONWriter();
+            var dictionary = new Dictionary<string, dynamic>
+            {
+                {"age", new List<int> {29}},
+                {"name", new List<string> {"marko"}}
+            };
+
+            var serializedDict = writer.WriteObject(dictionary);
+
+            var expectedGraphSON = "{\"age\":[{\"@type\":\"g:Int32\",\"@value\":29}],\"name\":[\"marko\"]}";
+            Assert.Equal(expectedGraphSON, serializedDict);
+        }
+
+        [Fact]
+        public void ShouldSerializeEdge()
+        {
+            var writer = CreateStandardGraphSONWriter();
+            var edge = new Edge(7, new Vertex(0, "person"), "knows", new Vertex(1, "dog"));
+
+            var graphSON = writer.WriteObject(edge);
+
+            const string expected =
+                "{\"@type\":\"g:Edge\",\"@value\":{\"id\":{\"@type\":\"g:Int32\",\"@value\":7},\"outV\":{\"@type\":\"g:Int32\",\"@value\":0},\"outVLabel\":\"person\",\"label\":\"knows\",\"inV\":{\"@type\":\"g:Int32\",\"@value\":1},\"inVLabel\":\"dog\"}}";
+            Assert.Equal(expected, graphSON);
+        }
+
+        [Fact]
+        public void ShouldSerializeEnum()
+        {
+            var writer = CreateStandardGraphSONWriter();
+
+            var serializedEnum = writer.WriteObject(T.label);
+
+            var expectedGraphSON = "{\"@type\":\"g:T\",\"@value\":\"label\"}";
+            Assert.Equal(expectedGraphSON, serializedEnum);
+        }
+
+        [Fact]
+        public void ShouldSerializeList()
+        {
+            var writer = CreateStandardGraphSONWriter();
+            var list = new List<int> {5, 6};
+
+            var serializedGraphSON = writer.WriteObject(list.ToArray());
+
+            var expectedGraphSON = "[{\"@type\":\"g:Int32\",\"@value\":5},{\"@type\":\"g:Int32\",\"@value\":6}]";
+            Assert.Equal(expectedGraphSON, serializedGraphSON);
+        }
+
+        [Fact]
+        public void ShouldSerializePredicateWithTwoValues()
+        {
+            var writer = CreateStandardGraphSONWriter();
+            var predicate = new TraversalPredicate("within", new List<int> {1, 2});
+
+            var serializedPredicate = writer.WriteObject(predicate);
+
+            var expectedGraphSON =
+                "{\"@type\":\"g:P\",\"@value\":{\"predicate\":\"within\",\"value\":[{\"@type\":\"g:Int32\",\"@value\":1},{\"@type\":\"g:Int32\",\"@value\":2}]}}";
+            Assert.Equal(expectedGraphSON, serializedPredicate);
+        }
+
+        [Fact]
+        public void ShouldSerializePredicateWithSingleValue()
+        {
+            var writer = CreateStandardGraphSONWriter();
+            var predicate = new TraversalPredicate("lt", 5);
+
+            var serializedPredicate = writer.WriteObject(predicate);
+
+            var expectedGraphSON =
+                "{\"@type\":\"g:P\",\"@value\":{\"predicate\":\"lt\",\"value\":{\"@type\":\"g:Int32\",\"@value\":5}}}";
+            Assert.Equal(expectedGraphSON, serializedPredicate);
+        }
+
+        [Fact]
+        public void ShouldSerializePropertyWithEdgeElement()
+        {
+            var writer = CreateStandardGraphSONWriter();
+            var property = new Property("aKey", "aValue", new Edge("anId", new Vertex(1), "edgeLabel", new Vertex(2)));
+
+            var graphSON = writer.WriteObject(property);
+
+            const string expected =
+                "{\"@type\":\"g:Property\",\"@value\":{\"key\":\"aKey\",\"value\":\"aValue\",\"element\":{\"@type\":\"g:Edge\",\"@value\":{\"id\":\"anId\",\"outV\":{\"@type\":\"g:Int32\",\"@value\":1},\"label\":\"edgeLabel\",\"inV\":{\"@type\":\"g:Int32\",\"@value\":2}}}}}";
+            Assert.Equal(expected, graphSON);
+        }
+
+        [Fact]
+        public void ShouldSerializePropertyWithVertexPropertyElement()
+        {
+            var writer = CreateStandardGraphSONWriter();
+            var property = new Property("name", "marko",
+                new VertexProperty("anId", "aKey", 21345, new Vertex("vertexId")));
+
+            var graphSON = writer.WriteObject(property);
+
+            const string expected =
+                "{\"@type\":\"g:Property\",\"@value\":{\"key\":\"name\",\"value\":\"marko\",\"element\":{\"@type\":\"g:VertexProperty\",\"@value\":{\"id\":\"anId\",\"label\":\"aKey\",\"vertex\":\"vertexId\"}}}}";
+            Assert.Equal(expected, graphSON);
+        }
+
+        [Fact]
+        public void ShouldSerializeVertexProperty()
+        {
+            var writer = CreateStandardGraphSONWriter();
+            var vertexProperty = new VertexProperty("blah", "keyA", true, new Vertex("stephen"));
+
+            var graphSON = writer.WriteObject(vertexProperty);
+
+            const string expected =
+                "{\"@type\":\"g:VertexProperty\",\"@value\":{\"id\":\"blah\",\"label\":\"keyA\",\"value\":true,\"vertex\":\"stephen\"}}";
+            Assert.Equal(expected, graphSON);
+        }
+
+        [Fact]
+        public void ShouldSerializeGuid()
+        {
+            var writer = CreateStandardGraphSONWriter();
+            var guid = Guid.Parse("41d2e28a-20a4-4ab0-b379-d810dede3786");
+
+            var graphSon = writer.WriteObject(guid);
+
+            const string expected = "{\"@type\":\"g:UUID\",\"@value\":\"41d2e28a-20a4-4ab0-b379-d810dede3786\"}";
+            Assert.Equal(expected, graphSon);
+        }
+
+        [Fact]
+        public void ShouldSerializeVertex()
+        {
+            var writer = CreateStandardGraphSONWriter();
+            var vertex = new Vertex(45.23f);
+
+            var graphSON = writer.WriteObject(vertex);
+
+            const string expected =
+                "{\"@type\":\"g:Vertex\",\"@value\":{\"id\":{\"@type\":\"g:Float\",\"@value\":45.23},\"label\":\"vertex\"}}";
+            Assert.Equal(expected, graphSON);
+        }
+
+        [Fact]
+        public void ShouldSerializeVertexWithLabel()
+        {
+            var writer = CreateStandardGraphSONWriter();
+            var vertex = new Vertex((long) 123, "project");
+
+            var graphSON = writer.WriteObject(vertex);
+
+            const string expected =
+                "{\"@type\":\"g:Vertex\",\"@value\":{\"id\":{\"@type\":\"g:Int64\",\"@value\":123},\"label\":\"project\"}}";
+            Assert.Equal(expected, graphSON);
+        }
+    }
+
+    internal enum T
+    {
+        label
+    }
+
+    internal class TestGraphSONSerializer : IGraphSONSerializer
+    {
+        public string TestNamespace { get; set; }
+
+        public Dictionary<string, dynamic> Dictify(dynamic objectData, GraphSONWriter writer)
+        {
+            return GraphSONUtil.ToTypedValue(nameof(TestClass), objectData.Value, TestNamespace);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/37a24719/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/StrategyWriterTests.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/StrategyWriterTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/StrategyWriterTests.cs
new file mode 100644
index 0000000..4bdb141
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/StrategyWriterTests.cs
@@ -0,0 +1,66 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using Gremlin.Net.Process.Traversal;
+using Gremlin.Net.Process.Traversal.Strategy.Decoration;
+using Gremlin.Net.Structure.IO.GraphSON;
+using Xunit;
+
+namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
+{
+    public class StrategyWriterTests
+    {
+        private GraphSONWriter CreateGraphSONWriter()
+        {
+            return new GraphSONWriter();
+        }
+
+        [Fact]
+        public void ShouldSerializeSubgraphStrategyWithoutValues()
+        {
+            var subgraphStrategy = new SubgraphStrategy();
+            var writer = CreateGraphSONWriter();
+
+            var graphSon = writer.WriteObject(subgraphStrategy);
+
+            const string expected = "{\"@type\":\"g:SubgraphStrategy\",\"@value\":{}}";
+            Assert.Equal(expected, graphSon);
+        }
+
+        [Fact]
+        public void ShouldDeserializeSubgraphStrategyWithVertexCriterion()
+        {
+            var vertexCriterionBytecode = new Bytecode();
+            vertexCriterionBytecode.AddStep("has", "name", "marko");
+            var vertexCriterion = new TestTraversal(vertexCriterionBytecode);
+            var subgraphStrategy = new SubgraphStrategy(vertexCriterion);
+            var writer = CreateGraphSONWriter();
+
+            var graphSon = writer.WriteObject(subgraphStrategy);
+
+            const string expected =
+                "{\"@type\":\"g:SubgraphStrategy\",\"@value\":{\"vertices\":{\"@type\":\"g:Bytecode\",\"@value\":{\"step\":[[\"has\",\"name\",\"marko\"]]}}}}";
+            Assert.Equal(expected, graphSon);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/37a24719/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/TestClass.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/TestClass.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/TestClass.cs
new file mode 100644
index 0000000..13d1bca
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/TestClass.cs
@@ -0,0 +1,30 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
+{
+    internal class TestClass
+    {
+        public dynamic Value { get; set; }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/37a24719/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/TestUtils.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/TestUtils.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/TestUtils.cs
new file mode 100644
index 0000000..7ed7542
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/TestUtils.cs
@@ -0,0 +1,36 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using System;
+
+namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
+{
+    internal class TestUtils
+    {
+        public static DateTime FromJavaTime(long javaTimestamp)
+        {
+            var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+            return epoch.AddMilliseconds(javaTimestamp);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/37a24719/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/PathTests.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/PathTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/PathTests.cs
new file mode 100644
index 0000000..e4ffb6e
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/PathTests.cs
@@ -0,0 +1,416 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Gremlin.Net.Structure;
+using Xunit;
+
+namespace Gremlin.Net.UnitTest.Structure
+{
+    public class PathTests
+    {
+        [Fact]
+        public void ShouldAssignPropertiesCorrectly()
+        {
+            var labels = new List<List<string>>
+            {
+                new List<string> {"a", "b"},
+                new List<string> {"c", "b"},
+                new List<string>()
+            };
+            var objects = new List<object> {1, new Vertex(1), "hello"};
+
+            var path = new Path(labels, objects);
+
+            Assert.Equal(labels, path.Labels);
+            Assert.Equal(objects, path.Objects);
+        }
+
+        [Fact]
+        public void ShouldReturnTrueForContainsKeyWhenGivenKeyExists()
+        {
+            var labels = new List<List<string>>
+            {
+                new List<string> {"a", "b"},
+                new List<string> {"c", "b"},
+                new List<string>()
+            };
+            var path = new Path(labels, new List<object>());
+
+            var containsKey = path.ContainsKey("c");
+
+            Assert.True(containsKey);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForContainsKeyWhenGivenKeyDoesNotExist()
+        {
+            var labels = new List<List<string>>
+            {
+                new List<string> {"a", "b"},
+                new List<string> {"c", "b"},
+                new List<string>()
+            };
+            var path = new Path(labels, new List<object>());
+
+            var containsKey = path.ContainsKey("z");
+
+            Assert.False(containsKey);
+        }
+
+        [Fact]
+        public void ShouldReturnCountOfObjectsForCountProperty()
+        {
+            var objects = new List<object> {1, new Vertex(1), "hello"};
+            var path = new Path(new List<List<string>>(), objects);
+
+            var count = path.Count;
+
+            Assert.Equal(3, count);
+        }
+
+        [Fact]
+        public void ShouldEnumeratorObjectsIntoListWhenToListIsCalled()
+        {
+            var objects = new List<object> {1, new Vertex(1), "hello"};
+            var path = new Path(new List<List<string>>(), objects);
+
+            var enumeratedObj = path.ToList();
+
+            Assert.Equal(objects, enumeratedObj);
+        }
+
+        [Fact]
+        public void ShouldReturnTrueForEqualsOfTwoEqualPaths()
+        {
+            var firstPath =
+                new Path(
+                    new List<List<string>>
+                    {
+                        new List<string> {"a", "b"},
+                        new List<string> {"c", "b"},
+                        new List<string>()
+                    }, new List<object> {1, new Vertex(1), "hello"});
+            var secondPath =
+                new Path(
+                    new List<List<string>>
+                    {
+                        new List<string> {"a", "b"},
+                        new List<string> {"c", "b"},
+                        new List<string>()
+                    }, new List<object> {1, new Vertex(1), "hello"});
+
+            var equals = firstPath.Equals(secondPath);
+
+            Assert.True(equals);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForEqualsOfPathsWithDifferentLabels()
+        {
+            var firstPath =
+                new Path(
+                    new List<List<string>>
+                    {
+                        new List<string> {"a", "b"},
+                        new List<string> {"c", "b"},
+                        new List<string>()
+                    }, new List<object> {1, new Vertex(1), "hello"});
+            var secondPath =
+                new Path(
+                    new List<List<string>>
+                    {
+                        new List<string> {"a"},
+                        new List<string> {"c", "b"},
+                        new List<string>()
+                    }, new List<object> {1, new Vertex(1), "hello"});
+
+            var equals = firstPath.Equals(secondPath);
+
+            Assert.False(equals);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForEqualsOfPathsWithDifferentObjects()
+        {
+            var firstPath =
+                new Path(
+                    new List<List<string>>
+                    {
+                        new List<string> {"a", "b"},
+                        new List<string> {"c", "b"},
+                        new List<string>()
+                    }, new List<object> {1, new Vertex(1), "hello"});
+            var secondPath =
+                new Path(
+                    new List<List<string>>
+                    {
+                        new List<string> {"a", "b"},
+                        new List<string> {"c", "b"},
+                        new List<string>()
+                    }, new List<object> {3, new Vertex(1), "hello"});
+
+            var equals = firstPath.Equals(secondPath);
+
+            Assert.False(equals);
+        }
+
+        [Fact]
+        public void ShouldReturnTrueForEqualsObjectOfTwoEqualPaths()
+        {
+            var firstPath =
+                new Path(
+                    new List<List<string>>
+                    {
+                        new List<string> {"a", "b"},
+                        new List<string> {"c", "b"},
+                        new List<string>()
+                    }, new List<object> { 1, new Vertex(1), "hello" });
+            object secondPath =
+                new Path(
+                    new List<List<string>>
+                    {
+                        new List<string> {"a", "b"},
+                        new List<string> {"c", "b"},
+                        new List<string>()
+                    }, new List<object> { 1, new Vertex(1), "hello" });
+
+            var equals = firstPath.Equals(secondPath);
+
+            Assert.True(equals);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForEqualsObjectOfPathsWithDifferentLabels()
+        {
+            var firstPath =
+                new Path(
+                    new List<List<string>>
+                    {
+                        new List<string> {"a", "b"},
+                        new List<string> {"c", "b"},
+                        new List<string>()
+                    }, new List<object> { 1, new Vertex(1), "hello" });
+            object secondPath =
+                new Path(
+                    new List<List<string>>
+                    {
+                        new List<string> {"a"},
+                        new List<string> {"c", "b"},
+                        new List<string>()
+                    }, new List<object> { 1, new Vertex(1), "hello" });
+
+            var equals = firstPath.Equals(secondPath);
+
+            Assert.False(equals);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForEqualsObjectOfPathsWithDifferentObjects()
+        {
+            var firstPath =
+                new Path(
+                    new List<List<string>>
+                    {
+                        new List<string> {"a", "b"},
+                        new List<string> {"c", "b"},
+                        new List<string>()
+                    }, new List<object> { 1, new Vertex(1), "hello" });
+            object secondPath =
+                new Path(
+                    new List<List<string>>
+                    {
+                        new List<string> {"a", "b"},
+                        new List<string> {"c", "b"},
+                        new List<string>()
+                    }, new List<object> { 3, new Vertex(1), "hello" });
+
+            var equals = firstPath.Equals(secondPath);
+
+            Assert.False(equals);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForEqualsWhereOtherIsNull()
+        {
+            var path = new Path(new List<List<string>> {new List<string> {"a", "b"},}, new List<object> {1});
+
+            var equals = path.Equals(null);
+
+            Assert.False(equals);
+        }
+
+        [Fact]
+        public void ShouldReturnEqualHashcodesForEqualPaths()
+        {
+            var firstPath =
+                new Path(
+                    new List<List<string>>
+                    {
+                        new List<string> {"a", "b"},
+                        new List<string> {"c", "b"},
+                        new List<string>()
+                    }, new List<object> { 1, new Vertex(1), "hello" });
+            var secondPath =
+                new Path(
+                    new List<List<string>>
+                    {
+                        new List<string> {"a", "b"},
+                        new List<string> {"c", "b"},
+                        new List<string>()
+                    }, new List<object> { 1, new Vertex(1), "hello" });
+
+            var firstHashCode = firstPath.GetHashCode();
+            var secondHashCode = secondPath.GetHashCode();
+
+            Assert.Equal(firstHashCode, secondHashCode);
+        }
+
+        [Fact]
+        public void ShouldThrowWhenInvalidIndexIsAccessed()
+        {
+            var objects = new List<object> {1, new Vertex(1), "hello"};
+            var path = new Path(new List<List<string>>(), objects);
+
+            Assert.Throws<ArgumentOutOfRangeException>(() => path[3]);
+        }
+
+        [Fact]
+        public void ShouldReturnObjectsByTheirIndex()
+        {
+            var objects = new List<object> {1, new Vertex(1), "hello"};
+            var path = new Path(new List<List<string>>(), objects);
+
+            Assert.Equal(1, path[0]);
+            Assert.Equal(new Vertex(1), path[1]);
+            Assert.Equal("hello", path[2]);
+        }
+
+        [Fact]
+        public void ShouldReturnAllObjectsWhenTheirKeyIsAccessed()
+        {
+            var labels = new List<List<string>>
+            {
+                new List<string> {"a", "b"},
+                new List<string> {"c", "b"},
+                new List<string>()
+            };
+            var objects = new List<object> {1, new Vertex(1), "hello"};
+            var path = new Path(labels, objects);
+
+            var bObjects = path["b"];
+
+            Assert.Equal(new List<object> {1, new Vertex(1)}, bObjects);
+        }
+
+        [Fact]
+        public void ShouldReturnObjectsByTheirKey()
+        {
+            var labels = new List<List<string>>
+            {
+                new List<string> {"a"},
+                new List<string> {"c", "b"},
+                new List<string>()
+            };
+            var objects = new List<object> {1, new Vertex(1), "hello"};
+            var path = new Path(labels, objects);
+
+            Assert.Equal(1, path["a"]);
+            Assert.Equal(new Vertex(1), path["c"]);
+            Assert.Equal(new Vertex(1), path["b"]);
+        }
+
+        [Fact]
+        public void ShouldThrowWhenUnknownKeyIsAccessed()
+        {
+            var path = new Path(new List<List<string>>(), new List<object>());
+
+            Assert.Throws<KeyNotFoundException>(() => path["unknownKey"]);
+        }
+
+        [Fact]
+        public void ShouldReturnCommonStringRepresentationForToString()
+        {
+            var labels = new List<List<string>>
+            {
+                new List<string> {"a", "b"},
+                new List<string> {"c", "b"},
+                new List<string>()
+            };
+            var objects = new List<object> {1, new Vertex(1), "hello"};
+            var path = new Path(labels, objects);
+
+            var pathStr = path.ToString();
+
+            Assert.Equal("[1, v[1], hello]", pathStr);
+        }
+
+        [Fact]
+        public void ShouldReturnTrueAndObjectsForTryGetWhenKeyWithMultipleObjectsIsProvided()
+        {
+            var labels = new List<List<string>>
+            {
+                new List<string> {"a", "b"},
+                new List<string> {"c", "b"},
+                new List<string>()
+            };
+            var objects = new List<object> {1, new Vertex(1), "hello"};
+            var path = new Path(labels, objects);
+
+            var success = path.TryGetValue("b", out object actualObj);
+
+            Assert.True(success);
+            Assert.Equal(new List<object> {1, new Vertex(1)}, actualObj);
+        }
+
+        [Fact]
+        public void ShouldReturnTrueAndCorrectObjectForTryGet()
+        {
+            var labels = new List<List<string>>
+            {
+                new List<string> {"a"},
+                new List<string> {"c", "b"},
+                new List<string>()
+            };
+            var objects = new List<object> {1, new Vertex(1), "hello"};
+            var path = new Path(labels, objects);
+
+            var success = path.TryGetValue("b", out object actualObj);
+
+            Assert.True(success);
+            Assert.Equal(new Vertex(1), actualObj);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForTryGetWhenUnknownKeyIsProvided()
+        {
+            var path = new Path(new List<List<string>>(), new List<object>());
+
+            var success = path.TryGetValue("unknownKey", out object _);
+
+            Assert.False(success);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/37a24719/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/PropertyTests.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/PropertyTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/PropertyTests.cs
new file mode 100644
index 0000000..e457dbd
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/PropertyTests.cs
@@ -0,0 +1,165 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using Gremlin.Net.Structure;
+using Xunit;
+
+namespace Gremlin.Net.UnitTest.Structure
+{
+    public class PropertyTests
+    {
+        [Fact]
+        public void ShouldAssignPropertiesCorrectly()
+        {
+            const string key = "age";
+            const int value = 29;
+            var element = new Vertex(1);
+
+            var property = new Property(key, value, element);
+
+            Assert.Equal(key, property.Key);
+            Assert.Equal(value, property.Value);
+            Assert.Equal(element, property.Element);
+        }
+
+        [Fact]
+        public void ShouldReturnTrueForEqualsOfTwoEqualProperties()
+        {
+            var firstProperty = new Property("age", 29, new Vertex(1));
+            var secondProperty = new Property("age", 29, new Vertex(1));
+
+            var areEqual = firstProperty.Equals(secondProperty);
+
+            Assert.True(areEqual);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForEqualsWhereOtherIsNull()
+        {
+            var property = new Property("age", 29, new Vertex(1));
+
+            var areEqual = property.Equals(null);
+
+            Assert.False(areEqual);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForEqualsOfPropertiesWithDifferentKeys()
+        {
+            var firstProperty = new Property("age", 29, new Vertex(1));
+            var secondProperty = new Property("aDifferentKey", 29, new Vertex(1));
+
+            var areEqual = firstProperty.Equals(secondProperty);
+
+            Assert.False(areEqual);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForEqualsOfPropertiesWithDifferentValues()
+        {
+            var firstProperty = new Property("age", 29, new Vertex(1));
+            var secondProperty = new Property("age", 12, new Vertex(1));
+
+            var areEqual = firstProperty.Equals(secondProperty);
+
+            Assert.False(areEqual);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForEqualsOfPropertiesWithDifferentElements()
+        {
+            var firstProperty = new Property("age", 29, new Vertex(1));
+            var secondProperty = new Property("age", 29, new Vertex(1234));
+
+            var areEqual = firstProperty.Equals(secondProperty);
+
+            Assert.False(areEqual);
+        }
+
+        [Fact]
+        public void ShouldReturnTrueForEqualsObjectOfTwoEqualProperties()
+        {
+            var firstProperty = new Property("age", 29, new Vertex(1));
+            object secondProperty = new Property("age", 29, new Vertex(1));
+
+            var areEqual = firstProperty.Equals(secondProperty);
+
+            Assert.True(areEqual);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForEqualsObjectOfPropertiesWithDifferentKeys()
+        {
+            var firstProperty = new Property("age", 29, new Vertex(1));
+            object secondProperty = new Property("aDifferentKey", 29, new Vertex(1));
+
+            var areEqual = firstProperty.Equals(secondProperty);
+
+            Assert.False(areEqual);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForEqualsObjectOfPropertiesWithDifferentValues()
+        {
+            var firstProperty = new Property("age", 29, new Vertex(1));
+            object secondProperty = new Property("age", 12, new Vertex(1));
+
+            var areEqual = firstProperty.Equals(secondProperty);
+
+            Assert.False(areEqual);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForEqualsObjectOfPropertiesWithDifferentElements()
+        {
+            var firstProperty = new Property("age", 29, new Vertex(1));
+            object secondProperty = new Property("age", 29, new Vertex(1234));
+
+            var areEqual = firstProperty.Equals(secondProperty);
+
+            Assert.False(areEqual);
+        }
+
+        [Fact]
+        public void ShouldReturnEqualHashcodesForEqualProperties()
+        {
+            var firstProperty = new Property("age", 29, new Vertex(1));
+            var secondProperty = new Property("age", 29, new Vertex(1));
+
+            var firstHashCode = firstProperty.GetHashCode();
+            var secondHashCode = secondProperty.GetHashCode();
+
+            Assert.Equal(firstHashCode, secondHashCode);
+        }
+
+        [Fact]
+        public void ShouldReturnCommonStringRepresentationForToString()
+        {
+            var property = new Property("age", 29, new Vertex(1));
+
+            var stringRepresentation = property.ToString();
+
+            Assert.Equal("p[age->29]", stringRepresentation);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/37a24719/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/VertexPropertyTests.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/VertexPropertyTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/VertexPropertyTests.cs
new file mode 100644
index 0000000..9288940
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/VertexPropertyTests.cs
@@ -0,0 +1,69 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using Gremlin.Net.Structure;
+using Xunit;
+
+namespace Gremlin.Net.UnitTest.Structure
+{
+    public class VertexPropertyTests
+    {
+        [Fact]
+        public void ShouldAssignPropertiesCorrectly()
+        {
+            const long id = 24;
+            const string label = "name";
+            const string value = "marko";
+            var vertex = new Vertex(1);
+
+            var vertexProperty = new VertexProperty(id, label, value, vertex);
+
+            Assert.Equal(label, vertexProperty.Label);
+            Assert.Equal(label, vertexProperty.Key);
+            Assert.Equal(value, vertexProperty.Value);
+            Assert.Equal(id, vertexProperty.Id);
+            Assert.Equal(vertex, vertexProperty.Vertex);
+        }
+
+        [Fact]
+        public void ShouldReturnTrueForEqualsOfTwoEqualVertexProperties()
+        {
+            var firstVertexProperty = new VertexProperty((long) 24, "name", "marko", new Vertex(1));
+            var secondVertexProperty = new VertexProperty((long) 24, "name", "marko", new Vertex(1));
+
+            var areEqual = firstVertexProperty.Equals(secondVertexProperty);
+
+            Assert.True(areEqual);
+        }
+
+        [Fact]
+        public void ShouldReturnCommonStringRepresentationForToString()
+        {
+            var vertexProperty = new VertexProperty((long) 24, "name", "marko", new Vertex(1));
+
+            var stringRepresentation = vertexProperty.ToString();
+
+            Assert.Equal("vp[name->marko]", stringRepresentation);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/37a24719/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/VertexTests.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/VertexTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/VertexTests.cs
new file mode 100644
index 0000000..8a93da5
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/VertexTests.cs
@@ -0,0 +1,80 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using Gremlin.Net.Structure;
+using Xunit;
+
+namespace Gremlin.Net.UnitTest.Structure
+{
+    public class VertexTests
+    {
+        [Fact]
+        public void ShouldReturnCommonStringRepresentationForToString()
+        {
+            var vertex = new Vertex(12345);
+
+            var vertexString = vertex.ToString();
+
+            Assert.Equal("v[12345]", vertexString);
+        }
+
+        [Fact]
+        public void ShouldReturnTrueForEqualsOfTwoEqualVertices()
+        {
+            var firstVertex = new Vertex(1);
+            var secondVertex = new Vertex(1);
+
+            var areEqual = firstVertex.Equals(secondVertex);
+
+            Assert.True(areEqual);
+        }
+
+        [Fact]
+        public void ShouldReturnFalseForEqualsWhereOtherIsNull()
+        {
+            var vertex = new Vertex(1);
+
+            var areEqual = vertex.Equals(null);
+
+            Assert.False(areEqual);
+        }
+
+        [Fact]
+        public void ShouldReturnSpecifiedLabelForLabelProperty()
+        {
+            const string specifiedLabel = "person";
+
+            var vertex = new Vertex(1, specifiedLabel);
+
+            Assert.Equal(specifiedLabel, vertex.Label);
+        }
+
+        [Fact]
+        public void ShouldReturnDefaultLabelForLabelPropertyWhenNoLabelSpecified()
+        {
+            var vertex = new Vertex(1);
+
+            Assert.Equal("vertex", vertex.Label);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/37a24719/gremlin-dotnet/test/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/pom.xml b/gremlin-dotnet/test/pom.xml
new file mode 100644
index 0000000..e625d60
--- /dev/null
+++ b/gremlin-dotnet/test/pom.xml
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.tinkerpop</groupId>
+        <artifactId>gremlin-dotnet</artifactId>
+        <version>3.2.5-SNAPSHOT</version>
+    </parent>
+    <artifactId>Gremlin-DotNet-Tests</artifactId>
+    <packaging>${packaging.type}</packaging>
+    <properties>
+        <!-- provides a way to convert maven.test.skip value to skipTests for use in skipping dotnet tests -->
+        <maven.test.skip>false</maven.test.skip>
+        <skipTests>${maven.test.skip}</skipTests>
+        <!-- this path only works when maven is started from the direct parent directory, this should be fixed -->
+        <gremlin.server.dir>${project.parent.parent.basedir}/gremlin-server</gremlin.server.dir>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.tinkerpop</groupId>
+            <artifactId>gremlin-core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.groovy</groupId>
+            <artifactId>groovy</artifactId>
+            <version>${groovy.version}</version>
+            <classifier>indy</classifier>
+        </dependency>
+        <!-- TESTING -->
+        <dependency>
+            <groupId>org.apache.tinkerpop</groupId>
+            <artifactId>tinkergraph-gremlin</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tinkerpop</groupId>
+            <artifactId>gremlin-test</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tinkerpop</groupId>
+            <artifactId>gremlin-server</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+            <scope>test</scope>
+            <version>${slf4j.version}</version>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>gremlin-dotnet-standard</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <properties>
+                <packaging.type>pom</packaging.type>
+            </properties>
+        </profile>
+        <!-- activates the building of .NET components and requires that the .NET Core SDK be installed on the system -->
+        <profile>
+            <id>gremlin-dotnet</id>
+            <activation>
+                <activeByDefault>false</activeByDefault>
+                <file>
+                    <exists>.glv</exists>
+                </file>
+            </activation>
+            <properties>
+                <packaging.type>dotnet-integration-test</packaging.type>
+            </properties>
+            <build>
+                <directory>${basedir}/target</directory>
+                <finalName>${project.artifactId}-${project.version}</finalName>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.eobjects.build</groupId>
+                        <artifactId>dotnet-maven-plugin</artifactId>
+                        <extensions>true</extensions>
+                        <configuration>
+                            <skip>${skipTests}</skip>
+                        </configuration>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.codehaus.gmavenplus</groupId>
+                        <artifactId>gmavenplus-plugin</artifactId>
+                        <dependencies>
+                            <dependency>
+                                <groupId>org.codehaus.groovy</groupId>
+                                <artifactId>groovy-all</artifactId>
+                                <version>${groovy.version}</version>
+                                <scope>runtime</scope>
+                            </dependency>
+                            <dependency>
+                                <groupId>log4j</groupId>
+                                <artifactId>log4j</artifactId>
+                                <version>1.2.17</version>
+                                <scope>runtime</scope>
+                            </dependency>
+                        </dependencies>
+                        <executions>
+                            <execution>
+                                <id>gremlin-server-start</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>execute</goal>
+                                </goals>
+                                <configuration>
+                                    <scripts>
+                                        <script>
+                                            <![CDATA[
+import org.apache.tinkerpop.gremlin.server.GremlinServer
+import org.apache.tinkerpop.gremlin.server.Settings
+import org.apache.tinkerpop.gremlin.server.Settings.ScriptEngineSettings
+
+if (${skipTests}) return
+
+log.info("Starting Gremlin Server instances for native testing of gremlin-dotnet")
+def settings = Settings.read("${gremlin.server.dir}/conf/gremlin-server-modern.yaml")
+settings.graphs.graph = "${gremlin.server.dir}/conf/tinkergraph-empty.properties"
+settings.scriptEngines["gremlin-groovy"].scripts = ["${gremlin.server.dir}/scripts/generate-modern.groovy"]
+settings.port = 45950
+
+def server = new GremlinServer(settings)
+server.start().join()
+
+project.setContextValue("gremlin.dotnet.server", server)
+log.info("Gremlin Server with no authentication started on port 45950")
+]]>
+                                        </script>
+                                    </scripts>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>gremlin-server-stop</id>
+                                <phase>post-integration-test</phase>
+                                <goals>
+                                    <goal>execute</goal>
+                                </goals>
+                                <configuration>
+                                    <scripts>
+                                        <script>
+                                            <![CDATA[
+import org.apache.tinkerpop.gremlin.server.GremlinServer
+
+if (${skipTests}) return
+
+log.info("Tests for native gremlin-dotnet complete")
+
+def server = project.getContextValue("gremlin.dotnet.server")
+log.info("Shutting down $server")
+server.stop().join()
+
+log.info("Gremlin Server instance shutdown for gremlin-dotnet")
+]]>
+                                        </script>
+                                    </scripts>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/37a24719/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 7b9c57a..d619278 100644
--- a/pom.xml
+++ b/pom.xml
@@ -121,6 +121,8 @@ limitations under the License.
         <module>gremlin-groovy-test</module>
         <module>tinkergraph-gremlin</module>
         <module>gremlin-python</module>
+        <module>gremlin-csharp-generator</module>
+        <module>gremlin-dotnet</module>
         <module>hadoop-gremlin</module>
         <module>spark-gremlin</module>
         <module>giraph-gremlin</module>
@@ -311,6 +313,13 @@ limitations under the License.
                         <exclude>**/.glv</exclude>
                         <exclude>bin/gremlin.sh</exclude>
                         <exclude>gremlin-console/bin/gremlin.sh</exclude>
+                        <exclude>**/Debug/**</exclude>
+                        <exclude>**/Release/**</exclude>
+                        <exclude>**/obj/**</exclude>
+                        <exclude>**/*.sln</exclude>
+                        <exclude>**/*.user</exclude>
+                        <exclude>**/*.csproj</exclude>
+                        <exclude>**/.vs/**</exclude>
                     </excludes>
                     <licenses>
                         <license implementation="org.apache.rat.analysis.license.ApacheSoftwareLicense20"/>