func_provider_test.go 9.9 KB

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