func_provider_test.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  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. `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 = UnitTestEval(
  266. `
  267. func foo() {
  268. log("hello")
  269. }
  270. doc(foo)`, nil)
  271. errorutil.AssertOk(err)
  272. if fmt.Sprint(res) != `Declared function: foo (Line 2, Pos 1)` {
  273. t.Error("Unexpected result: ", res, err)
  274. return
  275. }
  276. res, err = UnitTestEval(
  277. `doc(len)`, nil)
  278. errorutil.AssertOk(err)
  279. if fmt.Sprint(res) != `Len returns the size of a list or map.` {
  280. t.Error("Unexpected result: ", res, err)
  281. return
  282. }
  283. stdlib.AddStdlibPkg("fmt", "fmt package")
  284. stdlib.AddStdlibFunc("fmt", "Println",
  285. stdlib.NewECALFunctionAdapter(reflect.ValueOf(fmt.Sprint), "foo"))
  286. res, err = UnitTestEval(
  287. `doc(fmt.Println)`, nil)
  288. errorutil.AssertOk(err)
  289. if res != "foo" {
  290. t.Error("Unexpected result: ", res, err)
  291. return
  292. }
  293. res, err = UnitTestEval(
  294. `
  295. /*
  296. Foo is my custom function.
  297. */
  298. func foo() {
  299. log("hello")
  300. }
  301. doc(foo)`, nil)
  302. if err != nil || fmt.Sprint(res) != `Foo is my custom function.` {
  303. t.Error("Unexpected result: ", res, err)
  304. return
  305. }
  306. // Negative case
  307. res, err = UnitTestEvalAndAST(
  308. `a.len([1,2,3])`, nil,
  309. `
  310. identifier: a
  311. identifier: len
  312. funccall
  313. list
  314. number: 1
  315. number: 2
  316. number: 3
  317. `[1:])
  318. if err == nil ||
  319. err.Error() != "ECAL error in ECALTestRuntime: Unknown construct (Unknown function: len) (Line:1 Pos:3)" {
  320. t.Error("Unexpected result: ", res, err)
  321. return
  322. }
  323. _, err = UnitTestEval(`sleep(10)`, nil)
  324. if err != nil {
  325. t.Error("Unexpected result: ", err)
  326. return
  327. }
  328. }
  329. func TestCronTrigger(t *testing.T) {
  330. res, err := UnitTestEval(
  331. `setCronTrigger("1 * * * *", "foo", "bar")`, nil)
  332. if err == nil ||
  333. err.Error() != "ECAL error in ECALTestRuntime: Runtime error (Cron spec must have 6 entries separated by space) (Line:1 Pos:1)" {
  334. t.Error("Unexpected result: ", res, err)
  335. return
  336. }
  337. _, err = UnitTestEval(
  338. `
  339. sink test
  340. kindmatch [ "foo.*" ],
  341. {
  342. log("test rule - Handling request: ", event)
  343. }
  344. log("Cron:", setCronTrigger("1 1 *%10 * * *", "cronevent", "foo.bar"))
  345. `, nil)
  346. if err != nil {
  347. t.Error("Unexpected result:", err)
  348. return
  349. }
  350. testcron.Start()
  351. timeutil.WaitTestingCron(testcron)
  352. if testlogger.String() != `
  353. Cron:at second 1 of minute 1 of every 10th hour every day
  354. test rule - Handling request: {
  355. "kind": "foo.bar",
  356. "name": "cronevent",
  357. "state": {
  358. "tick": 1,
  359. "time": "2000-01-01T00:01:01Z",
  360. "timestamp": "946684861000"
  361. }
  362. }
  363. test rule - Handling request: {
  364. "kind": "foo.bar",
  365. "name": "cronevent",
  366. "state": {
  367. "tick": 2,
  368. "time": "2000-01-01T10:01:01Z",
  369. "timestamp": "946720861000"
  370. }
  371. }
  372. test rule - Handling request: {
  373. "kind": "foo.bar",
  374. "name": "cronevent",
  375. "state": {
  376. "tick": 3,
  377. "time": "2000-01-01T20:01:01Z",
  378. "timestamp": "946756861000"
  379. }
  380. }`[1:] {
  381. t.Error("Unexpected result:", testlogger.String())
  382. return
  383. }
  384. }
  385. func TestPulseTrigger(t *testing.T) {
  386. res, err := UnitTestEval(
  387. `setPulseTrigger("test", "foo", "bar")`, nil)
  388. if err == nil ||
  389. err.Error() != "ECAL error in ECALTestRuntime: Runtime error (Parameter 1 should be a number) (Line:1 Pos:1)" {
  390. t.Error("Unexpected result: ", res, err)
  391. return
  392. }
  393. _, err = UnitTestEval(
  394. `
  395. sink test
  396. kindmatch [ "foo.*" ],
  397. {
  398. log("test rule - Handling request: ", event)
  399. log("Duration: ", event.state.currentMicros - event.state.lastMicros," us (microsecond)")
  400. }
  401. setPulseTrigger(100, "pulseevent", "foo.bar")
  402. `, nil)
  403. if err != nil {
  404. t.Error("Unexpected result:", err)
  405. return
  406. }
  407. time.Sleep(100 * time.Millisecond)
  408. testprocessor.Finish()
  409. if !strings.Contains(testlogger.String(), "Handling request") {
  410. t.Error("Unexpected result:", testlogger.String())
  411. return
  412. }
  413. }
  414. func TestDocstrings(t *testing.T) {
  415. for k, v := range InbuildFuncMap {
  416. if res, _ := v.DocString(); res == "" {
  417. t.Error("Docstring missing for ", k)
  418. return
  419. }
  420. }
  421. }
  422. func TestErrorConditions(t *testing.T) {
  423. ib := &inbuildBaseFunc{}
  424. if _, err := ib.AssertNumParam(1, "bob"); err == nil || err.Error() != "Parameter 1 should be a number" {
  425. t.Error("Unexpected result:", err)
  426. return
  427. }
  428. if _, err := ib.AssertMapParam(1, "bob"); err == nil || err.Error() != "Parameter 1 should be a map" {
  429. t.Error("Unexpected result:", err)
  430. return
  431. }
  432. if _, err := ib.AssertListParam(1, "bob"); err == nil || err.Error() != "Parameter 1 should be a list" {
  433. t.Error("Unexpected result:", err)
  434. return
  435. }
  436. rf := &rangeFunc{&inbuildBaseFunc{}}
  437. if _, err := rf.Run("", nil, nil, 0, nil); err == nil || err.Error() != "Need at least an end range as first parameter" {
  438. t.Error("Unexpected result:", err)
  439. return
  440. }
  441. if _, err := rf.Run("", nil, nil, 0, []interface{}{"bob"}); err == nil || err.Error() != "Parameter 1 should be a number" {
  442. t.Error("Unexpected result:", err)
  443. return
  444. }
  445. }