This is an automated email from the ASF dual-hosted git repository. florianhockmann pushed a commit to branch TINKERPOP-2518-master in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 9846228a5678a991b13bc0a41db3ec5c00cd7819 Author: Florian Hockmann <[email protected]> AuthorDate: Wed Feb 2 15:36:50 2022 +0100 Merge branch 'TINKERPOP-2518' into TINKERPOP-2518-master --- .../Gherkin/CommonSteps.cs | 22 ++++- .../Gherkin/DeepEqualityExtensions.cs | 96 ++++++++++++++++++++++ .../Gherkin/GherkinTestRunner.cs | 23 ++++-- .../Gherkin/IgnoreException.cs | 5 -- gremlin-test/features/sideEffect/Sack.feature | 12 +-- 5 files changed, 135 insertions(+), 23 deletions(-) diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs index a2e8e85..789e996 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs @@ -48,8 +48,9 @@ namespace Gremlin.Net.IntegrationTest.Gherkin private ITraversal _traversal; private object[] _result; private Exception _error = null; - private static readonly JsonSerializerOptions JsonDeserializingOptions = new JsonSerializerOptions - {PropertyNamingPolicy = JsonNamingPolicy.CamelCase}; + + private static readonly JsonSerializerOptions JsonDeserializingOptions = + new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; public static ScenarioData ScenarioData { get; set; } = new ScenarioData(new GraphSON3MessageSerializer()); @@ -246,7 +247,22 @@ namespace Gremlin.Net.IntegrationTest.Gherkin var expectedArray = expected.ToArray(); foreach (var resultItem in _result) { - Assert.Contains(resultItem, expectedArray); + if (resultItem is Dictionary<object, object> resultItemDict) + { + var expectedArrayContainsResultDictionary = false; + foreach (var expectedItem in expectedArray) + { + if (expectedItem is not Dictionary<object, object> expectedItemDict) continue; + if (!expectedItemDict.DeepEqual(resultItemDict)) continue; + expectedArrayContainsResultDictionary = true; + break; + } + Assert.True(expectedArrayContainsResultDictionary); + } + else + { + Assert.Contains(resultItem, expectedArray); + } } if (characterizedAs != "of") { diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/DeepEqualityExtensions.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/DeepEqualityExtensions.cs new file mode 100644 index 0000000..d0f36e3 --- /dev/null +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/DeepEqualityExtensions.cs @@ -0,0 +1,96 @@ +#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.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace Gremlin.Net.IntegrationTest.Gherkin; + +public static class DeepEqualityExtensions +{ + public static bool DeepEqual(this Dictionary<object, object> first, Dictionary<object, object> second) + { + if (first.Count != second.Count) return false; + + foreach (var (key1, value1) in first) + { + var foundMatch = false; + foreach (var (key2, value2) in second) + { + if (!key1.DeepEqual(key2) || !value1.DeepEqual(value2)) continue; + foundMatch = true; + break; + } + if (!foundMatch) return false; + } + + return true; + } + + private static bool DeepEqual(this object first, object second) + { + if (first == null) + { + if (second != null) return false; + } + else if (first is not string && first is IEnumerable enumerable1) + { + if (second is string || second is not IEnumerable enumerable2) return false; + if (!enumerable1.DeepEqual(enumerable2)) + { + return false; + } + } + else + { + if (!first.Equals(second)) return false; + } + + return true; + } + + private static bool DeepEqual(this IEnumerable first, IEnumerable second) + { + if (first is Dictionary<object, object> dict1) + { + return second is Dictionary<object, object> dict2 && dict1.DeepEqual(dict2); + } + var objectEnum1 = first.ToObjectEnumerable(); + var objectEnum2 = second.ToObjectEnumerable(); + + // I hope that these IEnumerable<object> objects will always be simple collections so we don't need to go + // even deeper... + return objectEnum1.SequenceEqual(objectEnum2); + } + + private static IEnumerable<object> ToObjectEnumerable(this IEnumerable enumerable) + { + if (enumerable.GetType().IsArray) + { + return (IEnumerable<object>)enumerable; + } + + return (IEnumerable<object>)enumerable; + } +} \ No newline at end of file diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs index 183bbc2..dc78ad8 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs @@ -50,17 +50,22 @@ namespace Gremlin.Net.IntegrationTest.Gherkin // they are not failing as a result of the Gremlin itself - they are failing because of shortcomings in // the test suite. // https://issues.apache.org/jira/browse/TINKERPOP-2518 - {"g_withSackX0X_V_outE_sackXsumX_byXweightX_inV_sack_sum", IgnoreReason.NoReason}, - {"g_V_aggregateXaX_byXageX_capXaX_unfold_sum", IgnoreReason.NoReason}, - {"g_withSackX0X_V_repeatXoutE_sackXsumX_byXweightX_inVX_timesX2X_sack", IgnoreReason.NoReason}, + {"g_V_hasIdXnullX", IgnoreReason.NoReason}, + {"g_V_hasIdXeqXnullXX", IgnoreReason.NoReason}, {"g_V_hasIdX2_nullX", IgnoreReason.NoReason}, {"g_V_hasIdX2AsString_nullX", IgnoreReason.NoReason}, - {"g_addVXpersonX_propertyXname_joshX_propertyXage_nullX", IgnoreReason.NoReason}, - {"g_addVXpersonX_propertyXname_markoX_propertyXfriendWeight_null_acl_nullX", IgnoreReason.NoReason}, - {"g_addEXknowsXpropertyXweight_nullXfromXV_hasXname_markoXX_toXV_hasXname_vadasXX", IgnoreReason.NoReason}, - {"g_withBulkXfalseX_withSackX1_sumX_VX1X_localXoutEXknowsX_barrierXnormSackX_inVX_inXknowsX_barrier_sack", IgnoreReason.NoReason}, - {"g_withSackX1_sumX_VX1X_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack", IgnoreReason.NoReason}, - {"g_V_hasXperson_name_markoX_bothXknowsX_groupCount_byXvaluesXnameX_foldX", IgnoreReason.ArrayKeysInMapNotAssertingInGherkin} + { + "g_addVXpersonX_propertyXname_joshX_propertyXage_nullX", + IgnoreReason.NoReason + }, + { + "g_addVXpersonX_propertyXname_markoX_propertyXfriendWeight_null_acl_nullX", + IgnoreReason.NoReason + }, + { + "g_addEXknowsXpropertyXweight_nullXfromXV_hasXname_markoXX_toXV_hasXname_vadasXX", + IgnoreReason.NoReason + } }; private static class Keywords diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs index e025e2f..035cf56 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs @@ -56,11 +56,6 @@ namespace Gremlin.Net.IntegrationTest.Gherkin /// C# does not allow a `null` value to be used as a key. /// </summary> NullKeysInMapNotSupported, - - /// <summary> - /// C# array equality is by reference not contents so the gherkin setup won't assert properly - /// </summary> - ArrayKeysInMapNotAssertingInGherkin, /// <summary> /// The GLV suite does not test against a graph that has null property values enabled. diff --git a/gremlin-test/features/sideEffect/Sack.feature b/gremlin-test/features/sideEffect/Sack.feature index 0e18d5c..dcb4173 100644 --- a/gremlin-test/features/sideEffect/Sack.feature +++ b/gremlin-test/features/sideEffect/Sack.feature @@ -43,7 +43,7 @@ Feature: Step - sack() When iterated to list Then the result should be unordered | result | - | d[3.5].m | + | d[3.5].d | Scenario: g_withSackX0X_V_repeatXoutE_sackXsumX_byXweightX_inVX_timesX2X_sack Given the modern graph @@ -54,8 +54,8 @@ Feature: Step - sack() When iterated to list Then the result should be unordered | result | - | d[2.0].m | - | d[1.4].m | + | d[2.0].d | + | d[1.4].d | @GraphComputerVerificationOneBulk Scenario: g_withBulkXfalseX_withSackX1_sumX_VX1X_localXoutEXknowsX_barrierXnormSackX_inVX_inXknowsX_barrier_sack @@ -68,7 +68,7 @@ Feature: Step - sack() When iterated to list Then the result should be unordered | result | - | d[1.0].m | + | d[1.0].d | @GraphComputerVerificationOneBulk Scenario: g_withBulkXfalseX_withSackX1_sumX_V_out_barrier_sack @@ -95,8 +95,8 @@ Feature: Step - sack() When iterated to list Then the result should be unordered | result | - | d[1.0].m | - | d[1.0].m | + | d[1.0].d | + | d[1.0].d | Scenario: g_V_sackXassignX_byXageX_sack Given the modern graph
