Skip to content

Commit 5971ac4

Browse files
authored
Fix bugs and add comprehensive test coverage for pkg/stdlib/objects (#809)
1 parent 1e5f051 commit 5971ac4

8 files changed

Lines changed: 1162 additions & 704 deletions

File tree

pkg/stdlib/objects/has_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package objects_test
22

33
import (
44
"context"
5+
"fmt"
56
"testing"
67

78
"github.com/MontFerret/ferret/pkg/runtime"
@@ -79,4 +80,43 @@ func TestHas(t *testing.T) {
7980
So(err, ShouldBeError)
8081
So(val, ShouldEqual, runtime.None)
8182
})
83+
84+
Convey("When key is empty string", t, func() {
85+
obj := runtime.NewObjectWith(
86+
runtime.NewObjectProperty("", runtime.NewString("empty")),
87+
)
88+
89+
val, err := objects.Has(context.Background(), obj, runtime.NewString(""))
90+
valBool := val.(runtime.Boolean)
91+
92+
So(err, ShouldEqual, nil)
93+
So(bool(valBool), ShouldEqual, true)
94+
})
95+
96+
Convey("When object has many keys", t, func() {
97+
properties := make([]*runtime.ObjectProperty, 100)
98+
for i := 0; i < 100; i++ {
99+
properties[i] = runtime.NewObjectProperty(
100+
fmt.Sprintf("key%d", i),
101+
runtime.NewInt(i),
102+
)
103+
}
104+
obj := runtime.NewObjectWith(properties...)
105+
106+
// Test existing key
107+
val, err := objects.Has(context.Background(), obj, runtime.NewString("key50"))
108+
valBool := val.(runtime.Boolean)
109+
110+
So(err, ShouldEqual, nil)
111+
So(bool(valBool), ShouldEqual, true)
112+
113+
// Test non-existing key
114+
val, err = objects.Has(context.Background(), obj, runtime.NewString("key999"))
115+
valBool = val.(runtime.Boolean)
116+
117+
So(err, ShouldEqual, nil)
118+
So(bool(valBool), ShouldEqual, false)
119+
})
82120
}
121+
122+

pkg/stdlib/objects/keep_keys_test.go

Lines changed: 29 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -49,38 +49,38 @@ func TestKeepKeys(t *testing.T) {
4949
})
5050

5151
Convey("Result object is independent of the source object", t, func() {
52-
//arr := runtime.NewArrayWith(runtime.Int(0))
53-
//obj := runtime.NewObjectWith(
54-
// runtime.NewObjectProperty("a", arr),
55-
//)
56-
//resultObj := runtime.NewObjectWith(
57-
// runtime.NewObjectProperty("a", runtime.NewArrayWith(runtime.Int(0))),
58-
//)
59-
//
60-
//afterKeepKeys, err := objects.KeepKeys(context.Background(), obj, runtime.NewString("a"))
61-
//
62-
//So(err, ShouldBeNil)
63-
64-
//_ = arr.Add(nil, runtime.NewInt(1))
65-
//
66-
//So(afterKeepKeys.Compare(resultObj), ShouldEqual, 0)
52+
arr := runtime.NewArrayWith(runtime.Int(0))
53+
obj := runtime.NewObjectWith(
54+
runtime.NewObjectProperty("a", arr),
55+
)
56+
57+
afterKeepKeys, err := objects.KeepKeys(context.Background(), obj, runtime.NewString("a"))
58+
59+
So(err, ShouldBeNil)
60+
61+
arr.Add(context.Background(), runtime.NewInt(1))
62+
63+
resultObj := runtime.NewObjectWith(
64+
runtime.NewObjectProperty("a", runtime.NewArrayWith(runtime.Int(0))),
65+
)
66+
So(runtime.CompareValues(afterKeepKeys, resultObj), ShouldEqual, 0)
6767
})
6868
}
6969

7070
func TestKeepKeysStrings(t *testing.T) {
7171
Convey("KeepKeys key 'a'", t, func() {
72-
//obj := runtime.NewObjectWith(
73-
// runtime.NewObjectProperty("a", runtime.NewInt(1)),
74-
// runtime.NewObjectProperty("b", runtime.NewString("string")),
75-
//)
76-
//resultObj := runtime.NewObjectWith(
77-
// runtime.NewObjectProperty("a", runtime.NewInt(1)),
78-
//)
79-
//
80-
//afterKeepKeys, err := objects.KeepKeys(context.Background(), obj, runtime.NewString("a"))
81-
82-
//So(err, ShouldEqual, nil)
83-
//So(afterKeepKeys.Compare(resultObj), ShouldEqual, 0)
72+
obj := runtime.NewObjectWith(
73+
runtime.NewObjectProperty("a", runtime.NewInt(1)),
74+
runtime.NewObjectProperty("b", runtime.NewString("string")),
75+
)
76+
resultObj := runtime.NewObjectWith(
77+
runtime.NewObjectProperty("a", runtime.NewInt(1)),
78+
)
79+
80+
afterKeepKeys, err := objects.KeepKeys(context.Background(), obj, runtime.NewString("a"))
81+
82+
So(err, ShouldEqual, nil)
83+
So(runtime.CompareValues(afterKeepKeys, resultObj), ShouldEqual, 0)
8484
})
8585

8686
Convey("KeepKeys key doesn't exists", t, func() {
@@ -183,22 +183,6 @@ func TestKeepKeysArray(t *testing.T) {
183183
}
184184

185185
func isEqualObjects(obj1 *runtime.Object, obj2 *runtime.Object) bool {
186-
//var val1 runtime.Value
187-
//var val2 runtime.Value
188-
//
189-
//for _, key := range obj1.Keys() {
190-
// val1, _ = obj1.Get(key)
191-
// val2, _ = obj2.Get(key)
192-
// if val1.Compare(val2) != 0 {
193-
// return false
194-
// }
195-
//}
196-
//for _, key := range obj2.Keys() {
197-
// val1, _ = obj1.Get(key)
198-
// val2, _ = obj2.Get(key)
199-
// if val2.Compare(val1) != 0 {
200-
// return false
201-
// }
202-
//}
203-
return true
186+
// Use the built-in Compare method
187+
return runtime.CompareValues(obj1, obj2) == 0
204188
}

pkg/stdlib/objects/keys_test.go

Lines changed: 86 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -11,61 +11,75 @@ import (
1111
. "github.com/smartystreets/goconvey/convey"
1212
)
1313

14-
// TODO: Fix tests
1514
func TestKeys(t *testing.T) {
1615
Convey("Keys(obj, false) should return 'a', 'c', 'b' in any order", t, func() {
17-
//obj := runtime.NewObjectWith(
18-
// runtime.NewObjectProperty("a", runtime.NewInt(0)),
19-
// runtime.NewObjectProperty("b", runtime.NewInt(1)),
20-
// runtime.NewObjectProperty("c", runtime.NewInt(2)),
21-
//)
22-
//
23-
//keys, err := objects.Keys(context.Background(), obj)
24-
//keysArray := keys.(*runtime.Array)
25-
//
26-
//So(err, ShouldEqual, nil)
27-
//So(keysArray.Type().Equals(types.Array), ShouldBeTrue)
28-
//So(keysArray.Length(), ShouldEqual, 3)
29-
//
30-
//for _, k := range []string{"b", "a", "c"} {
31-
// iof := keysArray.IndexOf(runtime.NewString(k))
32-
// So(iof, ShouldNotEqual, -1)
33-
//}
16+
obj := runtime.NewObjectWith(
17+
runtime.NewObjectProperty("a", runtime.NewInt(0)),
18+
runtime.NewObjectProperty("b", runtime.NewInt(1)),
19+
runtime.NewObjectProperty("c", runtime.NewInt(2)),
20+
)
21+
22+
keys, err := objects.Keys(context.Background(), obj)
23+
keysArray := keys.(*runtime.Array)
24+
25+
So(err, ShouldEqual, nil)
26+
actualLength, _ := keysArray.Length(context.Background())
27+
So(actualLength, ShouldEqual, 3)
28+
29+
// Check that all expected keys are present (order doesn't matter)
30+
keyStrings := make([]string, 0, 3)
31+
keysArray.ForEach(context.Background(), func(ctx context.Context, val runtime.Value, idx runtime.Int) (runtime.Boolean, error) {
32+
keyStrings = append(keyStrings, val.String())
33+
return true, nil
34+
})
35+
36+
for _, expectedKey := range []string{"a", "b", "c"} {
37+
found := false
38+
for _, actualKey := range keyStrings {
39+
if actualKey == expectedKey {
40+
found = true
41+
break
42+
}
43+
}
44+
So(found, ShouldBeTrue)
45+
}
3446
})
3547

36-
Convey("Keys(obj, false) should return ['a', 'b', 'c']", t, func() {
37-
//obj := runtime.NewObjectWith(
38-
// runtime.NewObjectProperty("b", runtime.NewInt(0)),
39-
// runtime.NewObjectProperty("a", runtime.NewInt(1)),
40-
// runtime.NewObjectProperty("c", runtime.NewInt(3)),
41-
//)
42-
//
43-
//keys, err := objects.Keys(context.Background(), obj, runtime.NewBoolean(true))
44-
//keysArray := keys.(*runtime.Array)
45-
//
46-
//So(err, ShouldEqual, nil)
47-
//
48-
//for idx, key := range []string{"a", "b", "c"} {
49-
// So(keysArray.Get(runtime.NewInt(idx)), ShouldEqual, runtime.NewString(key))
50-
//}
48+
Convey("Keys(obj, true) should return ['a', 'b', 'c'] in sorted order", t, func() {
49+
obj := runtime.NewObjectWith(
50+
runtime.NewObjectProperty("b", runtime.NewInt(0)),
51+
runtime.NewObjectProperty("a", runtime.NewInt(1)),
52+
runtime.NewObjectProperty("c", runtime.NewInt(3)),
53+
)
54+
55+
keys, err := objects.Keys(context.Background(), obj, runtime.NewBoolean(true))
56+
keysArray := keys.(*runtime.Array)
57+
58+
So(err, ShouldEqual, nil)
59+
60+
expectedKeys := []string{"a", "b", "c"}
61+
for idx, key := range expectedKeys {
62+
actualKey, _ := keysArray.Get(context.Background(), runtime.NewInt(idx))
63+
So(actualKey.String(), ShouldEqual, key)
64+
}
5165
})
5266

5367
Convey("When there are no keys", t, func() {
54-
//obj := runtime.NewObject()
55-
//
56-
//keys, err := objects.Keys(context.Background(), obj, runtime.NewBoolean(true))
57-
//keysArray := keys.(*runtime.Array)
58-
//
59-
//So(err, ShouldEqual, nil)
60-
//So(keysArray.Length(), ShouldEqual, runtime.NewInt(0))
61-
//So(int(keysArray.Length()), ShouldEqual, 0)
62-
//
63-
//keys, err = objects.Keys(context.Background(), obj, runtime.NewBoolean(false))
64-
//keysArray = keys.(*runtime.Array)
65-
//
66-
//So(err, ShouldEqual, nil)
67-
//So(keysArray.Length(), ShouldEqual, runtime.NewInt(0))
68-
//So(int(keysArray.Length()), ShouldEqual, 0)
68+
obj := runtime.NewObject()
69+
70+
keys, err := objects.Keys(context.Background(), obj, runtime.NewBoolean(true))
71+
keysArray := keys.(*runtime.Array)
72+
73+
So(err, ShouldEqual, nil)
74+
actualLength, _ := keysArray.Length(context.Background())
75+
So(actualLength, ShouldEqual, 0)
76+
77+
keys, err = objects.Keys(context.Background(), obj, runtime.NewBoolean(false))
78+
keysArray = keys.(*runtime.Array)
79+
80+
So(err, ShouldEqual, nil)
81+
actualLength, _ = keysArray.Length(context.Background())
82+
So(actualLength, ShouldEqual, 0)
6983
})
7084

7185
Convey("When not enough arguments", t, func() {
@@ -90,4 +104,28 @@ func TestKeys(t *testing.T) {
90104
So(err, ShouldBeError)
91105
})
92106

107+
Convey("When object has special character keys", t, func() {
108+
obj := runtime.NewObjectWith(
109+
runtime.NewObjectProperty("key with spaces", runtime.NewInt(1)),
110+
runtime.NewObjectProperty("key_with_underscores", runtime.NewInt(2)),
111+
runtime.NewObjectProperty("key-with-dashes", runtime.NewInt(3)),
112+
runtime.NewObjectProperty("key.with.dots", runtime.NewInt(4)),
113+
)
114+
115+
keys, err := objects.Keys(context.Background(), obj, runtime.NewBoolean(true))
116+
keysArray := keys.(*runtime.Array)
117+
118+
So(err, ShouldEqual, nil)
119+
actualLength, _ := keysArray.Length(context.Background())
120+
So(actualLength, ShouldEqual, 4)
121+
122+
// Check sorted order
123+
expectedKeys := []string{"key with spaces", "key-with-dashes", "key.with.dots", "key_with_underscores"}
124+
for idx, expectedKey := range expectedKeys {
125+
actualKey, _ := keysArray.Get(context.Background(), runtime.NewInt(idx))
126+
So(actualKey.String(), ShouldEqual, expectedKey)
127+
}
128+
})
93129
}
130+
131+

pkg/stdlib/objects/merge_recursive.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ func MergeRecursive(ctx context.Context, args ...runtime.Value) (runtime.Value,
3838
}
3939

4040
func merge(ctx context.Context, src, dst runtime.Value) (runtime.Value, error) {
41-
if runtime.CompareValues(src, dst) != 0 {
41+
// If both values are equal, no need to merge
42+
if runtime.CompareValues(src, dst) == 0 {
4243
return src, nil
4344
}
4445

0 commit comments

Comments
 (0)