func_provider_test.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /*
  2. * ECAL
  3. *
  4. * Copyright 2020 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package interpreter
  11. import (
  12. "fmt"
  13. "reflect"
  14. "strings"
  15. "testing"
  16. "time"
  17. "devt.de/krotik/ecal/stdlib"
  18. )
  19. func TestStdlib(t *testing.T) {
  20. stdlib.AddStdlibPkg("fmt", "fmt package")
  21. stdlib.AddStdlibFunc("fmt", "Sprint",
  22. stdlib.NewECALFunctionAdapter(reflect.ValueOf(fmt.Sprint), "foo"))
  23. res, err := UnitTestEvalAndAST(
  24. `fmt.Sprint([1,2,3])`, nil,
  25. `
  26. identifier: fmt
  27. identifier: Sprint
  28. funccall
  29. list
  30. number: 1
  31. number: 2
  32. number: 3
  33. `[1:])
  34. if err != nil || res != "[1 2 3]" {
  35. t.Error("Unexpected result: ", res, err)
  36. return
  37. }
  38. res, err = UnitTestEvalAndAST(
  39. `fmt.Sprint(math.Pi)`, nil,
  40. `
  41. identifier: fmt
  42. identifier: Sprint
  43. funccall
  44. identifier: math
  45. identifier: Pi
  46. `[1:])
  47. if err != nil || res != "3.141592653589793" {
  48. t.Error("Unexpected result: ", res, err)
  49. return
  50. }
  51. // Negative case
  52. res, err = UnitTestEvalAndAST(
  53. `a.fmtSprint([1,2,3])`, nil,
  54. `
  55. identifier: a
  56. identifier: fmtSprint
  57. funccall
  58. list
  59. number: 1
  60. number: 2
  61. number: 3
  62. `[1:])
  63. if err == nil ||
  64. err.Error() != "ECAL error in ECALTestRuntime: Unknown construct (Unknown function: fmtSprint) (Line:1 Pos:3)" {
  65. t.Error("Unexpected result: ", res, err)
  66. return
  67. }
  68. }
  69. func TestSimpleFunctions(t *testing.T) {
  70. res, err := UnitTestEvalAndAST(
  71. `len([1,2,3])`, nil,
  72. `
  73. identifier: len
  74. funccall
  75. list
  76. number: 1
  77. number: 2
  78. number: 3
  79. `[1:])
  80. if err != nil || res != 3. {
  81. t.Error("Unexpected result: ", res, err)
  82. return
  83. }
  84. res, err = UnitTestEvalAndAST(
  85. `len({"a":1, 2:"b"})`, nil,
  86. `
  87. identifier: len
  88. funccall
  89. map
  90. kvp
  91. string: 'a'
  92. number: 1
  93. kvp
  94. number: 2
  95. string: 'b'
  96. `[1:])
  97. if err != nil || res != 2. {
  98. t.Error("Unexpected result: ", res, err)
  99. return
  100. }
  101. res, err = UnitTestEvalAndAST(
  102. `del([1,2,3], 1)`, nil,
  103. `
  104. identifier: del
  105. funccall
  106. list
  107. number: 1
  108. number: 2
  109. number: 3
  110. number: 1
  111. `[1:])
  112. if err != nil || fmt.Sprint(res) != "[1 3]" {
  113. t.Error("Unexpected result: ", res, err)
  114. return
  115. }
  116. res, err = UnitTestEvalAndAST(
  117. `del({
  118. "a" : 1
  119. "b" : 2
  120. "c" : 3
  121. }, "b")`, nil,
  122. `
  123. identifier: del
  124. funccall
  125. map
  126. kvp
  127. string: 'a'
  128. number: 1
  129. kvp
  130. string: 'b'
  131. number: 2
  132. kvp
  133. string: 'c'
  134. number: 3
  135. string: 'b'
  136. `[1:])
  137. if err != nil || fmt.Sprint(res) != "map[a:1 c:3]" {
  138. t.Error("Unexpected result: ", res, err)
  139. return
  140. }
  141. res, err = UnitTestEvalAndAST(
  142. `add([1,2,3], 4)`, nil,
  143. `
  144. identifier: add
  145. funccall
  146. list
  147. number: 1
  148. number: 2
  149. number: 3
  150. number: 4
  151. `[1:])
  152. if err != nil || fmt.Sprint(res) != "[1 2 3 4]" {
  153. t.Error("Unexpected result: ", res, err)
  154. return
  155. }
  156. res, err = UnitTestEvalAndAST(
  157. `add([1,2,3], 4, 0)`, nil,
  158. `
  159. identifier: add
  160. funccall
  161. list
  162. number: 1
  163. number: 2
  164. number: 3
  165. number: 4
  166. number: 0
  167. `[1:])
  168. if err != nil || fmt.Sprint(res) != "[4 1 2 3]" {
  169. t.Error("Unexpected result: ", res, err)
  170. return
  171. }
  172. res, err = UnitTestEvalAndAST(
  173. `add([1,2,3], 4, 1)`, nil,
  174. `
  175. identifier: add
  176. funccall
  177. list
  178. number: 1
  179. number: 2
  180. number: 3
  181. number: 4
  182. number: 1
  183. `[1:])
  184. if err != nil || fmt.Sprint(res) != "[1 4 2 3]" {
  185. t.Error("Unexpected result: ", res, err)
  186. return
  187. }
  188. res, err = UnitTestEvalAndAST(
  189. `concat([1,2,3], [4,5,6], [7,8,9])`, nil,
  190. `
  191. identifier: concat
  192. funccall
  193. list
  194. number: 1
  195. number: 2
  196. number: 3
  197. list
  198. number: 4
  199. number: 5
  200. number: 6
  201. list
  202. number: 7
  203. number: 8
  204. number: 9
  205. `[1:])
  206. if err != nil || fmt.Sprint(res) != "[1 2 3 4 5 6 7 8 9]" {
  207. t.Error("Unexpected result: ", res, err)
  208. return
  209. }
  210. res, err = UnitTestEvalAndAST(
  211. `dumpenv()`, nil,
  212. `
  213. identifier: dumpenv
  214. funccall
  215. `[1:])
  216. if err != nil || fmt.Sprint(res) != `GlobalScope {
  217. }` {
  218. t.Error("Unexpected result: ", res, err)
  219. return
  220. }
  221. res, err = UnitTestEval(
  222. `
  223. func foo() {
  224. log("hello")
  225. }
  226. doc(foo)`, nil)
  227. if err != nil || fmt.Sprint(res) != `Declared function: foo (Line 2, Pos 1)` {
  228. t.Error("Unexpected result: ", res, err)
  229. return
  230. }
  231. res, err = UnitTestEval(
  232. `doc(len)`, nil)
  233. if err != nil || fmt.Sprint(res) != `Len returns the size of a list or map.` {
  234. t.Error("Unexpected result: ", res, err)
  235. return
  236. }
  237. stdlib.AddStdlibPkg("fmt", "fmt package")
  238. stdlib.AddStdlibFunc("fmt", "Println",
  239. stdlib.NewECALFunctionAdapter(reflect.ValueOf(fmt.Sprint), "foo"))
  240. res, err = UnitTestEval(
  241. `doc(fmt.Println)`, nil)
  242. if err != nil || res != "foo" {
  243. t.Error("Unexpected result: ", res, err)
  244. return
  245. }
  246. res, err = UnitTestEval(
  247. `
  248. /*
  249. Foo is my custom function.
  250. */
  251. func foo() {
  252. log("hello")
  253. }
  254. doc(foo)`, nil)
  255. if err != nil || fmt.Sprint(res) != `Foo is my custom function.` {
  256. t.Error("Unexpected result: ", res, err)
  257. return
  258. }
  259. // Negative case
  260. res, err = UnitTestEvalAndAST(
  261. `a.len([1,2,3])`, nil,
  262. `
  263. identifier: a
  264. identifier: len
  265. funccall
  266. list
  267. number: 1
  268. number: 2
  269. number: 3
  270. `[1:])
  271. if err == nil ||
  272. err.Error() != "ECAL error in ECALTestRuntime: Unknown construct (Unknown function: len) (Line:1 Pos:3)" {
  273. t.Error("Unexpected result: ", res, err)
  274. return
  275. }
  276. _, err = UnitTestEval(`sleep(10)`, nil)
  277. if err != nil {
  278. t.Error("Unexpected result: ", err)
  279. return
  280. }
  281. }
  282. func TestCronTrigger(t *testing.T) {
  283. res, err := UnitTestEval(
  284. `setCronTrigger("1 * * * *", "foo", "bar")`, nil)
  285. if err == nil ||
  286. err.Error() != "ECAL error in ECALTestRuntime: Runtime error (Cron spec must have 6 entries separated by space) (Line:1 Pos:1)" {
  287. t.Error("Unexpected result: ", res, err)
  288. return
  289. }
  290. res, err = UnitTestEval(
  291. `
  292. sink test
  293. kindmatch [ "foo.*" ],
  294. {
  295. log("test rule - Handling request: ", event)
  296. }
  297. log("Cron:", setCronTrigger("1 1 *%10 * * *", "cronevent", "foo.bar"))
  298. `, nil)
  299. if err != nil {
  300. t.Error("Unexpected result:", err)
  301. return
  302. }
  303. testcron.Start()
  304. time.Sleep(200 * time.Millisecond)
  305. if testlogger.String() != `
  306. Cron:at second 1 of minute 1 of every 10th hour every day
  307. test rule - Handling request: {
  308. "kind": "foo.bar",
  309. "name": "cronevent",
  310. "state": {
  311. "tick": 1,
  312. "time": "2000-01-01T00:01:01Z",
  313. "timestamp": "946684861000"
  314. }
  315. }
  316. test rule - Handling request: {
  317. "kind": "foo.bar",
  318. "name": "cronevent",
  319. "state": {
  320. "tick": 2,
  321. "time": "2000-01-01T10:01:01Z",
  322. "timestamp": "946720861000"
  323. }
  324. }
  325. test rule - Handling request: {
  326. "kind": "foo.bar",
  327. "name": "cronevent",
  328. "state": {
  329. "tick": 3,
  330. "time": "2000-01-01T20:01:01Z",
  331. "timestamp": "946756861000"
  332. }
  333. }`[1:] {
  334. t.Error("Unexpected result:", testlogger.String())
  335. return
  336. }
  337. }
  338. func TestPulseTrigger(t *testing.T) {
  339. res, err := UnitTestEval(
  340. `setPulseTrigger("test", "foo", "bar")`, nil)
  341. if err == nil ||
  342. err.Error() != "ECAL error in ECALTestRuntime: Runtime error (Parameter 1 should be a number) (Line:1 Pos:1)" {
  343. t.Error("Unexpected result: ", res, err)
  344. return
  345. }
  346. res, err = UnitTestEval(
  347. `
  348. sink test
  349. kindmatch [ "foo.*" ],
  350. {
  351. log("test rule - Handling request: ", event)
  352. log("Duration: ", event.state.currentMicros - event.state.lastMicros," us (microsecond)")
  353. }
  354. setPulseTrigger(100, "pulseevent", "foo.bar")
  355. `, nil)
  356. if err != nil {
  357. t.Error("Unexpected result:", err)
  358. return
  359. }
  360. time.Sleep(100 * time.Millisecond)
  361. testprocessor.Finish()
  362. if !strings.Contains(testlogger.String(), "Handling request") {
  363. t.Error("Unexpected result:", testlogger.String())
  364. return
  365. }
  366. }
  367. func TestDocstrings(t *testing.T) {
  368. for k, v := range InbuildFuncMap {
  369. if res, _ := v.DocString(); res == "" {
  370. t.Error("Docstring missing for ", k)
  371. return
  372. }
  373. }
  374. }
  375. func TestErrorConditions(t *testing.T) {
  376. ib := &inbuildBaseFunc{}
  377. if _, err := ib.AssertNumParam(1, "bob"); err == nil || err.Error() != "Parameter 1 should be a number" {
  378. t.Error("Unexpected result:", err)
  379. return
  380. }
  381. if _, err := ib.AssertMapParam(1, "bob"); err == nil || err.Error() != "Parameter 1 should be a map" {
  382. t.Error("Unexpected result:", err)
  383. return
  384. }
  385. if _, err := ib.AssertListParam(1, "bob"); err == nil || err.Error() != "Parameter 1 should be a list" {
  386. t.Error("Unexpected result:", err)
  387. return
  388. }
  389. rf := &rangeFunc{&inbuildBaseFunc{}}
  390. if _, err := rf.Run("", nil, nil, 0, nil); err == nil || err.Error() != "Need at least an end range as first parameter" {
  391. t.Error("Unexpected result:", err)
  392. return
  393. }
  394. if _, err := rf.Run("", nil, nil, 0, []interface{}{"bob"}); err == nil || err.Error() != "Parameter 1 should be a number" {
  395. t.Error("Unexpected result:", err)
  396. return
  397. }
  398. }