stdlib_test.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. package stdlib_test
  2. import (
  3. "fmt"
  4. "testing"
  5. "time"
  6. "github.com/d5/tengo/v2"
  7. "github.com/d5/tengo/v2/require"
  8. "github.com/d5/tengo/v2/stdlib"
  9. )
  10. type ARR = []interface{}
  11. type MAP = map[string]interface{}
  12. type IARR []interface{}
  13. type IMAP map[string]interface{}
  14. func TestAllModuleNames(t *testing.T) {
  15. names := stdlib.AllModuleNames()
  16. require.Equal(t,
  17. len(stdlib.BuiltinModules)+len(stdlib.SourceModules),
  18. len(names))
  19. }
  20. func TestModulesRun(t *testing.T) {
  21. // os.File
  22. expect(t, `
  23. os := import("os")
  24. out := ""
  25. write_file := func(filename, data) {
  26. file := os.create(filename)
  27. if !file { return file }
  28. if res := file.write(bytes(data)); is_error(res) {
  29. return res
  30. }
  31. return file.close()
  32. }
  33. read_file := func(filename) {
  34. file := os.open(filename)
  35. if !file { return file }
  36. data := bytes(100)
  37. cnt := file.read(data)
  38. if is_error(cnt) {
  39. return cnt
  40. }
  41. file.close()
  42. return data[:cnt]
  43. }
  44. if write_file("./temp", "foobar") {
  45. out = string(read_file("./temp"))
  46. }
  47. os.remove("./temp")
  48. `, "foobar")
  49. // exec.command
  50. expect(t, `
  51. out := ""
  52. os := import("os")
  53. cmd := os.exec("echo", "foo", "bar")
  54. if !is_error(cmd) {
  55. out = cmd.output()
  56. }
  57. `, []byte("foo bar\n"))
  58. }
  59. func TestGetModules(t *testing.T) {
  60. mods := stdlib.GetModuleMap()
  61. require.Equal(t, 0, mods.Len())
  62. mods = stdlib.GetModuleMap("os")
  63. require.Equal(t, 1, mods.Len())
  64. require.NotNil(t, mods.Get("os"))
  65. mods = stdlib.GetModuleMap("os", "rand")
  66. require.Equal(t, 2, mods.Len())
  67. require.NotNil(t, mods.Get("os"))
  68. require.NotNil(t, mods.Get("rand"))
  69. mods = stdlib.GetModuleMap("text", "text")
  70. require.Equal(t, 1, mods.Len())
  71. require.NotNil(t, mods.Get("text"))
  72. mods = stdlib.GetModuleMap("nonexisting", "text")
  73. require.Equal(t, 1, mods.Len())
  74. require.NotNil(t, mods.Get("text"))
  75. }
  76. type callres struct {
  77. t *testing.T
  78. o interface{}
  79. e error
  80. }
  81. func (c callres) call(funcName string, args ...interface{}) callres {
  82. if c.e != nil {
  83. return c
  84. }
  85. var oargs []tengo.Object
  86. for _, v := range args {
  87. oargs = append(oargs, object(v))
  88. }
  89. switch o := c.o.(type) {
  90. case *tengo.BuiltinModule:
  91. m, ok := o.Attrs[funcName]
  92. if !ok {
  93. return callres{t: c.t, e: fmt.Errorf(
  94. "function not found: %s", funcName)}
  95. }
  96. f, ok := m.(*tengo.UserFunction)
  97. if !ok {
  98. return callres{t: c.t, e: fmt.Errorf(
  99. "non-callable: %s", funcName)}
  100. }
  101. res, err := f.Value(oargs...)
  102. return callres{t: c.t, o: res, e: err}
  103. case *tengo.UserFunction:
  104. res, err := o.Value(oargs...)
  105. return callres{t: c.t, o: res, e: err}
  106. case *tengo.ImmutableMap:
  107. m, ok := o.Value[funcName]
  108. if !ok {
  109. return callres{t: c.t, e: fmt.Errorf("function not found: %s", funcName)}
  110. }
  111. f, ok := m.(*tengo.UserFunction)
  112. if !ok {
  113. return callres{t: c.t, e: fmt.Errorf("non-callable: %s", funcName)}
  114. }
  115. res, err := f.Value(oargs...)
  116. return callres{t: c.t, o: res, e: err}
  117. default:
  118. panic(fmt.Errorf("unexpected object: %v (%T)", o, o))
  119. }
  120. }
  121. func (c callres) expect(expected interface{}, msgAndArgs ...interface{}) {
  122. require.NoError(c.t, c.e, msgAndArgs...)
  123. require.Equal(c.t, object(expected), c.o, msgAndArgs...)
  124. }
  125. func (c callres) expectError() {
  126. require.Error(c.t, c.e)
  127. }
  128. func module(t *testing.T, moduleName string) callres {
  129. mod := stdlib.GetModuleMap(moduleName).GetBuiltinModule(moduleName)
  130. if mod == nil {
  131. return callres{t: t, e: fmt.Errorf("module not found: %s", moduleName)}
  132. }
  133. return callres{t: t, o: mod}
  134. }
  135. func object(v interface{}) tengo.Object {
  136. switch v := v.(type) {
  137. case tengo.Object:
  138. return v
  139. case string:
  140. return &tengo.String{Value: v}
  141. case int64:
  142. return tengo.Int{Value: v}
  143. case int: // for convenience
  144. return tengo.Int{Value: int64(v)}
  145. case bool:
  146. if v {
  147. return tengo.TrueValue
  148. }
  149. return tengo.FalseValue
  150. case rune:
  151. return tengo.Char{Value: v}
  152. case byte: // for convenience
  153. return tengo.Char{Value: rune(v)}
  154. case float64:
  155. return tengo.Float{Value: v}
  156. case []byte:
  157. return &tengo.Bytes{Value: v}
  158. case MAP:
  159. objs := make(map[string]tengo.Object)
  160. for k, v := range v {
  161. objs[k] = object(v)
  162. }
  163. return &tengo.Map{Value: objs}
  164. case ARR:
  165. var objs []tengo.Object
  166. for _, e := range v {
  167. objs = append(objs, object(e))
  168. }
  169. return &tengo.Array{Value: objs}
  170. case IMAP:
  171. objs := make(map[string]tengo.Object)
  172. for k, v := range v {
  173. objs[k] = object(v)
  174. }
  175. return &tengo.ImmutableMap{Value: objs}
  176. case IARR:
  177. var objs []tengo.Object
  178. for _, e := range v {
  179. objs = append(objs, object(e))
  180. }
  181. return &tengo.ImmutableArray{Value: objs}
  182. case time.Time:
  183. return &tengo.Time{Value: v}
  184. case []int:
  185. var objs []tengo.Object
  186. for _, e := range v {
  187. objs = append(objs, tengo.Int{Value: int64(e)})
  188. }
  189. return &tengo.Array{Value: objs}
  190. }
  191. panic(fmt.Errorf("unknown type: %T", v))
  192. }
  193. func expect(t *testing.T, input string, expected interface{}) {
  194. s := tengo.NewScript([]byte(input))
  195. s.SetImports(stdlib.GetModuleMap(stdlib.AllModuleNames()...))
  196. c, err := s.Run()
  197. require.NoError(t, err)
  198. require.NotNil(t, c)
  199. v := c.Get("out")
  200. require.NotNil(t, v)
  201. require.Equal(t, expected, v.Value())
  202. }