Skip to content

Commit

Permalink
feat: add sort module to stdlib
Browse files Browse the repository at this point in the history
  • Loading branch information
huanghongkai committed Jun 26, 2023
1 parent 82b543f commit 85e1629
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 0 deletions.
1 change: 1 addition & 0 deletions stdlib/source_modules.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions stdlib/srcmod_sort.tengo
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
_sort := func(arr, left, right, less) {
if right-left <= 0 {
return arr
}
i := left

for j := left; j < right; j++ {
if less(j, right) {
if i != j {
tmp := arr[i]
arr[i] = arr[j]
arr[j] = tmp
}
i++
}
}

if i != right {
tmp := arr[i]
arr[i] = arr[right]
arr[right] = tmp
}

_sort(arr, left, i-1, less)
_sort(arr, i+1, right, less)
return arr
}

export {
sort: func(arr, less) {
return _sort(arr, 0, len(arr)-1, less)
}
}
86 changes: 86 additions & 0 deletions stdlib/stdlib_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package stdlib_test

import (
"encoding/json"
"fmt"
"math/rand"
"sort"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -72,6 +76,81 @@ if !is_error(cmd) {

}

func TestSortModule(t *testing.T) {
// normal
expect(t, `
sort := import("sort")
a := [4, 5, 3, 1, 2]
a = sort.sort(a, func(i, j) {
return a[i] < a[j]
})
out := import("json").encode(a)
`, []byte("[1,2,3,4,5]"))

// generator random sequence
rand.Seed(time.Now().UnixNano())
generateRandomSequence := func() []int {
length := 1 + rand.Intn(100)
arr := make([]int, length)
for i := 0; i < length; i++ {
arr[i] = rand.Intn(1000000)
}
return arr
}
for i := 0; i < 300; i++ {
seq := generateRandomSequence()
seqBytes, _ := json.Marshal(seq)
sort.Ints(seq)
sortResult, _ := json.Marshal(seq)
expect(t, fmt.Sprintf(`
sort := import("sort")
a := %s
a = sort.sort(a, func(i, j) {
return a[i] < a[j]
})
out := import("json").encode(a)
`, string(seqBytes)), sortResult)
}

// less is not a function
expectErr(t, `
sort := import("sort")
a := [4, 5, 3, 1, 2]
a = sort.sort(a, 0)
out := import("json").encode(a)`, "Runtime Error: not callable: int")

// arr is not an array
expectErr(t, `
sort := import("sort")
a := 12345
a = sort.sort(a, func(i, j) {
return a[i] < a[j]
})
out := import("json").encode(a)`, "Runtime Error: invalid type for argument 'first' in call to 'builtin-function:len': expected array/s")

// empty array
expect(t, `
sort := import("sort")
a := []
a = sort.sort(a, func(i, j) {
return a[i] < a[j]
})
out := import("json").encode(a)`, []byte("[]"))

// sort json
expect(t, `
sort := import("sort")
a := [{"age": 12, "name": "A"}, {"age": 18, "name": "B"}, {"age": 9, "name": "C"}, {"age": 10, "name": "D"}, {"age": 21, "name": "E"}]
a = sort.sort(a, func(i, j) {
return a[i].age < a[j].age
})
out := []
for item in a {
out = append(out, item.name)
}
out = import("json").encode(out)`, []byte(`["C","D","A","B","E"]`))
}

func TestGetModules(t *testing.T) {
mods := stdlib.GetModuleMap()
require.Equal(t, 0, mods.Len())
Expand Down Expand Up @@ -240,3 +319,10 @@ func expect(t *testing.T, input string, expected interface{}) {
require.NotNil(t, v)
require.Equal(t, expected, v.Value())
}

func expectErr(t *testing.T, input string, errMsg string) {
s := tengo.NewScript([]byte(input))
s.SetImports(stdlib.GetModuleMap(stdlib.AllModuleNames()...))
_, err := s.Run()
require.True(t, strings.Contains(err.Error(), errMsg))
}

0 comments on commit 85e1629

Please sign in to comment.