func_provider_test.go 9.2 KB

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