[ 
https://issues.apache.org/jira/browse/TINKERPOP-2992?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18057562#comment-18057562
 ] 

ASF GitHub Bot commented on TINKERPOP-2992:
-------------------------------------------

spmallette commented on code in PR #3303:
URL: https://github.com/apache/tinkerpop/pull/3303#discussion_r2787675072


##########
gremlin-go/driver/cucumber/cucumberSteps_test.go:
##########
@@ -588,174 +592,205 @@ func (tg *tinkerPopGraph) 
theResultShouldBe(characterizedAs string, table *godog
        }
 }
 
+// compareMapEquals compares two maps for equality by checking if they have 
the same length
+// and if every key-value pair in the actual map has a logically equal 
counterpart in the expected map.
 func compareMapEquals(expected map[interface{}]interface{}, actual 
map[interface{}]interface{}) bool {
+       if len(actual) != len(expected) {
+               return false
+       }
        for k, a := range actual {
                var e interface{}
                containsKey := false
                for ke, ee := range expected {
-                       if fmt.Sprint(k) == fmt.Sprint(ke) {
+                       if compareSingleEqual(k, ke) {
                                containsKey = true
                                e = ee
                                break
-                       } else {
-                               if reflect.ValueOf(k).Kind() == reflect.Ptr &&
-                                       reflect.ValueOf(ke).Kind() == 
reflect.Ptr {
-                                       switch k.(type) {
-                                       case *gremlingo.Vertex:
-                                               switch ke.(type) {
-                                               case *gremlingo.Vertex:
-                                                       if 
fmt.Sprint(*k.(*gremlingo.Vertex)) == fmt.Sprint(*ke.(*gremlingo.Vertex)) {
-                                                               containsKey = 
true
-                                                       }
-                                               default:
-                                                       // Not equal.
-                                               }
-                                       default:
-                                               // If we are here we probably 
need to implement an additional type like the Vertex above.
-                                               if 
fmt.Sprint(*k.(*interface{})) == fmt.Sprint(*ke.(*interface{})) {
-                                                       fmt.Println("WARNING: 
Encountered unknown pointer type as map key.")
-                                                       containsKey = true
-                                               }
-                                       }
-                                       if containsKey {
-                                               e = ee
-                                               break
-                                       }
-                               }
                        }
                }
                if !containsKey {
                        fmt.Printf("Map comparison error: Failed to find key %s 
in %v\n", k, expected)
                        return false
                }
 
-               if a == nil && e == nil {
-                       continue
-               } else if a == nil || e == nil {
-                       // One value is nil, other is not. They are not equal.
-                       fmt.Printf("Map comparison error: One map has a nil 
key, other does not.\n")
+               if !compareSingleEqual(a, e) {
+                       fmt.Printf("Map comparison error: Expected != Actual 
(%v!=%v)\n", e, a)
                        return false
-               } else {
-                       switch reflect.TypeOf(a).Kind() {
-                       case reflect.Array, reflect.Slice:
-                               switch reflect.TypeOf(e).Kind() {
-                               case reflect.Array, reflect.Slice:
-                                       // Compare arrays
-                                       if 
!compareListEqualsWithoutOrder(e.([]interface{}), a.([]interface{})) {
-                                               return false
-                                       }
-                               default:
-                                       fmt.Printf("Map comparison error: 
Expected type is Array/Slice, actual is %s.\n", reflect.TypeOf(a).Kind())
-                                       return false
-                               }
-                       case reflect.Map:
-                               switch reflect.TypeOf(a).Kind() {
-                               case reflect.Map:
-                                       // Compare maps
-                                       if 
!compareMapEquals(e.(map[interface{}]interface{}), 
a.(map[interface{}]interface{})) {
-                                               return false
-                                       }
-                               default:
-                                       fmt.Printf("Map comparison error: 
Expected type is Map, actual is %s.\n", reflect.TypeOf(a).Kind())
-                                       return false
-                               }
-                       default:
-                               if fmt.Sprint(a) != fmt.Sprint(e) {
-                                       fmt.Printf("Map comparison error: 
Expected != Actual (%s!=%s)\n", fmt.Sprint(a), fmt.Sprint(e))
-                                       return false
-                               }
-                       }
                }
        }
        return true
 }
 
-func compareListEqualsWithoutOrder(expected []interface{}, actual 
[]interface{}) bool {
-       // This is a little weird, but there isn't a good solution to either of 
these problems:
-       //              1. Comparison of types in Go. No deep equals which 
actually works properly. Needs to be done manually.
-       //              2. In place deletion in a loop.
-       // So to do in place deletion in a loop we can do the following:
-       //              1. Loop from back to wrong (don't need to worry about 
deleted indices that way.
-       //              2. Create a new slice with the index removed when we 
fix the item we want to delete.
-       // To do an orderless copy, a copy of the expected result is created. 
Results are removed as they are found. This stops
-       // the following from returning equal [1 2 2 2] and [1 1 1 2]
-
-       // Shortcut.
-       if fmt.Sprint(expected) == fmt.Sprint(actual) {
+// compareSingleEqual is the core logical equality function used for Gremlin 
Gherkin tests.
+// It avoids using fmt.Sprint which can include memory addresses for pointers 
(like Vertices or Edges),
+// leading to false negatives in tests. It performs recursive comparisons for 
complex types
+// and handles Gremlin-specific elements by comparing their IDs.
+func compareSingleEqual(actual interface{}, expected interface{}) bool {
+       if actual == nil && expected == nil {
                return true
+       } else if actual == nil || expected == nil {
+               return false
        }
+
+       actualSet, ok1 := actual.(*gremlingo.SimpleSet)
+       expectedSet, ok2 := expected.(*gremlingo.SimpleSet)
+       if ok1 && ok2 {
+               return compareListEqualsWithoutOrder(expectedSet.ToSlice(), 
actualSet.ToSlice())
+       } else if ok1 || ok2 {
+               return false
+       }
+
+       actualPath, ok1 := actual.(*gremlingo.Path)
+       expectedPath, ok2 := expected.(*gremlingo.Path)
+       if ok1 && ok2 {
+               return compareListEqualsWithOrder(expectedPath.Objects, 
actualPath.Objects)
+       } else if ok1 || ok2 {
+               return false
+       }
+
+       actualV, ok1 := actual.(*gremlingo.Vertex)
+       expectedV, ok2 := expected.(*gremlingo.Vertex)
+       if ok1 && ok2 {
+               return actualV.Id == expectedV.Id
+       }
+
+       actualE, ok1 := actual.(*gremlingo.Edge)
+       expectedE, ok2 := expected.(*gremlingo.Edge)
+       if ok1 && ok2 {
+               return actualE.Id == expectedE.Id
+       }
+
+       actualVP, ok1 := actual.(*gremlingo.VertexProperty)
+       expectedVP, ok2 := expected.(*gremlingo.VertexProperty)
+       if ok1 && ok2 {
+               return actualVP.Id == expectedVP.Id
+       }
+
+       actualP, ok1 := actual.(*gremlingo.Property)
+       expectedP, ok2 := expected.(*gremlingo.Property)
+       if ok1 && ok2 {
+               return actualP.Key == expectedP.Key && 
compareSingleEqual(actualP.Value, expectedP.Value)
+       }
+
+       switch a := actual.(type) {
+       case map[interface{}]interface{}:
+               e, ok := expected.(map[interface{}]interface{})
+               if !ok {
+                       return false
+               }
+               return compareMapEquals(e, a)
+       case []interface{}:
+               e, ok := expected.([]interface{})
+               if !ok {
+                       return false
+               }
+               return compareListEqualsWithOrder(e, a)
+       case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, 
uint64, float32, float64:
+               return compareNumeric(actual, expected)
+       default:
+               return fmt.Sprint(actual) == fmt.Sprint(expected)
+       }
+}
+
+// compareNumeric normalizes different numeric types to float64 to allow for 
comparison
+// between different precisions and representations (e.g. int64 vs float32).
+// It also explicitly handles NaN equality which is required for some Gremlin 
tests.
+func compareNumeric(actual interface{}, expected interface{}) bool {
+       var aVal, eVal float64
+       switch a := actual.(type) {
+       case int:
+               aVal = float64(a)
+       case int8:
+               aVal = float64(a)
+       case int16:
+               aVal = float64(a)
+       case int32:
+               aVal = float64(a)
+       case int64:
+               aVal = float64(a)

Review Comment:
   i dont want to overcomplicate the testing, but `Set` was vexing Go and after 
trying a few more surgical things, i let AI go kinda wild here. maybe it's 
doing way more than necessary. should this be revisited more carefully?





> Gherkin suite missing orderability on set, uuid, date
> -----------------------------------------------------
>
>                 Key: TINKERPOP-2992
>                 URL: https://issues.apache.org/jira/browse/TINKERPOP-2992
>             Project: TinkerPop
>          Issue Type: Improvement
>          Components: test-suite
>    Affects Versions: 3.6.5
>            Reporter: Stephen Mallette
>            Priority: Minor
>
> Orderability.feature has todos in it for set, uuid and date.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to