Skip to content

Commit f7a0bb0

Browse files
author
huanghongkai
committed
feat: add sort module to stdlib
1 parent 82b543f commit f7a0bb0

3 files changed

Lines changed: 120 additions & 0 deletions

File tree

stdlib/source_modules.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

stdlib/srcmod_sort.tengo

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
_sort := func(arr, left, right, less) {
2+
if right-left <= 0 {
3+
return arr
4+
}
5+
i := left
6+
7+
for j := left; j < right; j++ {
8+
if less(j, right) {
9+
if i != j {
10+
tmp := arr[i]
11+
arr[i] = arr[j]
12+
arr[j] = tmp
13+
}
14+
i++
15+
}
16+
}
17+
18+
if i != right {
19+
tmp := arr[i]
20+
arr[i] = arr[right]
21+
arr[right] = tmp
22+
}
23+
24+
_sort(arr, left, i-1, less)
25+
_sort(arr, i+1, right, less)
26+
return arr
27+
}
28+
29+
export {
30+
sort: func(arr, less) {
31+
return _sort(arr, 0, len(arr)-1, less)
32+
}
33+
}

stdlib/stdlib_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package stdlib_test
22

33
import (
4+
"encoding/json"
45
"fmt"
6+
"math/rand"
7+
"sort"
8+
"strings"
59
"testing"
610
"time"
711

@@ -72,6 +76,81 @@ if !is_error(cmd) {
7276

7377
}
7478

79+
func TestSortModule(t *testing.T) {
80+
// normal
81+
expect(t, `
82+
sort := import("sort")
83+
a := [4, 5, 3, 1, 2]
84+
a = sort.sort(a, func(i, j) {
85+
return a[i] < a[j]
86+
})
87+
out := import("json").encode(a)
88+
`, []byte("[1,2,3,4,5]"))
89+
90+
// generate random sequences for sorting
91+
rand.Seed(time.Now().UnixNano())
92+
generateRandomSequence := func() []int {
93+
length := 1 + rand.Intn(1000)
94+
arr := make([]int, length)
95+
for i := 0; i < length; i++ {
96+
arr[i] = rand.Intn(1000000)
97+
}
98+
return arr
99+
}
100+
for i := 0; i < 500; i++ {
101+
seq := generateRandomSequence()
102+
seqBytes, _ := json.Marshal(seq)
103+
sort.Ints(seq)
104+
sortResult, _ := json.Marshal(seq)
105+
expect(t, fmt.Sprintf(`
106+
sort := import("sort")
107+
a := %s
108+
a = sort.sort(a, func(i, j) {
109+
return a[i] < a[j]
110+
})
111+
out := import("json").encode(a)
112+
`, string(seqBytes)), sortResult)
113+
}
114+
115+
// less is not a function
116+
expectErr(t, `
117+
sort := import("sort")
118+
a := [4, 5, 3, 1, 2]
119+
a = sort.sort(a, 0)
120+
out := import("json").encode(a)`, "Runtime Error: not callable: int")
121+
122+
// arr is not an array
123+
expectErr(t, `
124+
sort := import("sort")
125+
a := 12345
126+
a = sort.sort(a, func(i, j) {
127+
return a[i] < a[j]
128+
})
129+
out := import("json").encode(a)`, "Runtime Error: invalid type for argument 'first' in call to 'builtin-function:len': expected array/s")
130+
131+
// empty array
132+
expect(t, `
133+
sort := import("sort")
134+
a := []
135+
a = sort.sort(a, func(i, j) {
136+
return a[i] < a[j]
137+
})
138+
out := import("json").encode(a)`, []byte("[]"))
139+
140+
// sort json
141+
expect(t, `
142+
sort := import("sort")
143+
a := [{"age": 12, "name": "A"}, {"age": 18, "name": "B"}, {"age": 9, "name": "C"}, {"age": 10, "name": "D"}, {"age": 21, "name": "E"}]
144+
a = sort.sort(a, func(i, j) {
145+
return a[i].age < a[j].age
146+
})
147+
out := []
148+
for item in a {
149+
out = append(out, item.name)
150+
}
151+
out = import("json").encode(out)`, []byte(`["C","D","A","B","E"]`))
152+
}
153+
75154
func TestGetModules(t *testing.T) {
76155
mods := stdlib.GetModuleMap()
77156
require.Equal(t, 0, mods.Len())
@@ -240,3 +319,10 @@ func expect(t *testing.T, input string, expected interface{}) {
240319
require.NotNil(t, v)
241320
require.Equal(t, expected, v.Value())
242321
}
322+
323+
func expectErr(t *testing.T, input string, errMsg string) {
324+
s := tengo.NewScript([]byte(input))
325+
s.SetImports(stdlib.GetModuleMap(stdlib.AllModuleNames()...))
326+
_, err := s.Run()
327+
require.True(t, strings.Contains(err.Error(), errMsg))
328+
}

0 commit comments

Comments
 (0)