Repository: gavv/httpexpect
Pull request #215 (2022-12-30 09:39:23)

[#212] add sorting to Every, Transform and Filter funcs of Object

maxfilov: #212 
coveralls: 
[![Coverage Status](https://coveralls.io/builds/55531794/badge)](https://coveralls.io/builds/55531794)

Coverage: 95.43%. Remained the same when pulling **1e05a61430dc7fc53def236cdc904e1be9740788 on maxfilov:master** into **0978c258998559dc00df2c87cf186483169778d0 on gavv:master**.


Patch:
diff --git a/object.go b/object.go
index e49f58f..df7dc4f 100644
--- a/object.go
+++ b/object.go
@@ -225,15 +225,15 @@ func (o *Object) Every(fn func(key string, value *Value)) *Object {
 
 	chainFailure := false
 
-	for key, val := range o.value {
+	for _, kv := range o.sortedKV() {
 		valueChain := o.chain.clone()
-		valueChain.replace("Every[%q]", key)
+		valueChain.replace("Every[%q]", kv.key)
 
 		valueChain.setFailCallback(func() {
 			chainFailure = true
 		})
 
-		fn(key, newValue(valueChain, val))
+		fn(kv.key, newValue(valueChain, kv.val))
 
 	}
 
@@ -286,16 +286,16 @@ func (o *Object) Filter(fn func(key string, value *Value) bool) *Object {
 
 	filteredObject := make(map[string]interface{})
 
-	for key, element := range o.value {
+	for _, kv := range o.sortedKV() {
 		valueChain := o.chain.clone()
 		valueChain.setSeverity(SeverityLog)
 		chainFailed := false
 		valueChain.setFailCallback(func() {
 			chainFailed = true
 		})
-		valueChain.replace("Filter[%q]", key)
-		if fn(key, newValue(valueChain, element)) && !chainFailed {
-			filteredObject[key] = element
+		valueChain.replace("Filter[%q]", kv.key)
+		if fn(kv.key, newValue(valueChain, kv.val)) && !chainFailed {
+			filteredObject[kv.key] = kv.val
 		}
 	}
 
@@ -333,9 +333,9 @@ func (o *Object) Transform(fn func(key string, value interface{}) interface{}) *
 
 	object := map[string]interface{}{}
 
-	for key, val := range o.value {
-		transformedValue := fn(key, val)
-		object[key] = transformedValue
+	for _, kv := range o.sortedKV() {
+		transformedValue := fn(kv.key, kv.val)
+		object[kv.key] = transformedValue
 	}
 
 	return newObject(o.chain, object)


Test patch:
diff --git a/object_test.go b/object_test.go
index 19bf97a..dc9b25b 100644
--- a/object_test.go
+++ b/object_test.go
@@ -877,6 +877,24 @@ func TestObject_Every(t *testing.T) {
 		object.chain.assertFailed(ts)
 		assert.Equal(t, 2, invoked)
 	})
+
+	t.Run("Every traverse fields is ordered", func(ts *testing.T) {
+		reporter := newMockReporter(ts)
+		object := NewObject(reporter, map[string]interface{}{
+			"bar": "123",
+			"baz": "456",
+			"foo": "foo",
+			"foz": "foo",
+			"b":   "789",
+			"c":   "987",
+		})
+		expectedOrder := []string{"b", "bar", "baz", "c", "foo", "foz"}
+		var actualOrder []string
+		object.Every(func(key string, val *Value) {
+			actualOrder = append(actualOrder, key)
+		})
+		assert.Equal(t, expectedOrder, actualOrder)
+	})
 }
 
 func TestObject_Transform(t *testing.T) {
@@ -948,6 +966,23 @@ func TestObject_Transform(t *testing.T) {
 		})
 		newObject.chain.assertNotFailed(ts)
 	})
+
+	t.Run("Transform is ordered", func(ts *testing.T) {
+		reporter := newMockReporter(ts)
+		object := NewObject(reporter, map[string]interface{}{
+			"foo": "123",
+			"bar": "456",
+			"b":   "456",
+			"baz": "baz",
+		})
+		expectedOrder := []string{"b", "bar", "baz", "foo"}
+		actualOrder := []string{}
+		object.Transform(func(key string, value interface{}) interface{} {
+			actualOrder = append(actualOrder, key)
+			return value
+		})
+		assert.Equal(t, expectedOrder, actualOrder)
+	})
 }
 
 func TestObject_Filter(t *testing.T) {
@@ -1040,6 +1075,24 @@ func TestObject_Filter(t *testing.T) {
 			filteredObject.chain.assertNotFailed(t)
 			object.chain.assertNotFailed(t)
 		})
+
+	t.Run("Filter is ordered", func(ts *testing.T) {
+		reporter := newMockReporter(t)
+		object := NewObject(reporter, map[string]interface{}{
+			"foo":  "bar",
+			"baz":  "qux",
+			"bar":  "qux",
+			"b":    "qux",
+			"quux": "corge",
+		})
+		expectedOrder := []string{"b", "bar", "baz", "foo", "quux"}
+		var actualOrder []string
+		object.Filter(func(key string, value *Value) bool {
+			actualOrder = append(actualOrder, key)
+			return false
+		})
+		assert.Equal(t, expectedOrder, actualOrder)
+	})
 }
 
 func TestObject_Find(t *testing.T) {