emqx_rule_funcs_SUITE.erl 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2020-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
  3. %%
  4. %% Licensed under the Apache License, Version 2.0 (the "License");
  5. %% you may not use this file except in compliance with the License.
  6. %% You may obtain a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing, software
  11. %% distributed under the License is distributed on an "AS IS" BASIS,
  12. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. %% See the License for the specific language governing permissions and
  14. %% limitations under the License.
  15. %%--------------------------------------------------------------------
  16. -module(emqx_rule_funcs_SUITE).
  17. -compile(export_all).
  18. -compile(nowarn_export_all).
  19. -include_lib("proper/include/proper.hrl").
  20. -include_lib("eunit/include/eunit.hrl").
  21. -include_lib("common_test/include/ct.hrl").
  22. -define(PROPTEST(F), ?assert(proper:quickcheck(F()))).
  23. %%-define(PROPTEST(F), ?assert(proper:quickcheck(F(), [{on_output, fun ct:print/2}]))).
  24. init_per_suite(Config) ->
  25. Apps = emqx_cth_suite:start(
  26. [
  27. emqx,
  28. emqx_conf,
  29. {emqx_rule_engine, "rule_engine {jq_function_default_timeout=10s}"}
  30. ],
  31. #{work_dir => emqx_cth_suite:work_dir(Config)}
  32. ),
  33. [{apps, Apps} | Config].
  34. end_per_suite(Config) ->
  35. Apps = ?config(apps, Config),
  36. emqx_cth_suite:stop(Apps),
  37. ok.
  38. eventmsg_publish(Msg) ->
  39. {Columns, _} = emqx_rule_events:eventmsg_publish(Msg),
  40. Columns.
  41. %%------------------------------------------------------------------------------
  42. %% Test cases for IoT Funcs
  43. %%------------------------------------------------------------------------------
  44. t_msgid(_) ->
  45. Msg = message(),
  46. ?assertEqual(undefined, apply_func(msgid, [], #{})),
  47. ?assertEqual(
  48. emqx_guid:to_hexstr(emqx_message:id(Msg)), apply_func(msgid, [], eventmsg_publish(Msg))
  49. ).
  50. t_qos(_) ->
  51. ?assertEqual(undefined, apply_func(qos, [], #{})),
  52. ?assertEqual(1, apply_func(qos, [], message())).
  53. t_flags(_) ->
  54. ?assertEqual(#{dup => false}, apply_func(flags, [], message())).
  55. t_flag(_) ->
  56. Msg = message(),
  57. Msg1 = emqx_message:set_flag(retain, Msg),
  58. ?assertNot(apply_func(flag, [dup], Msg)),
  59. ?assert(apply_func(flag, [retain], Msg1)).
  60. t_topic(_) ->
  61. Msg = message(),
  62. ?assertEqual(<<"topic/#">>, apply_func(topic, [], Msg)),
  63. ?assertEqual(<<"topic">>, apply_func(topic, [1], Msg)).
  64. t_clientid(_) ->
  65. Msg = message(),
  66. ?assertEqual(undefined, apply_func(clientid, [], #{})),
  67. ?assertEqual(<<"clientid">>, apply_func(clientid, [], Msg)).
  68. t_clientip(_) ->
  69. Msg = emqx_message:set_header(peerhost, {127, 0, 0, 1}, message()),
  70. ?assertEqual(undefined, apply_func(clientip, [], #{})),
  71. ?assertEqual(<<"127.0.0.1">>, apply_func(clientip, [], eventmsg_publish(Msg))).
  72. t_peerhost(_) ->
  73. Msg = emqx_message:set_header(peerhost, {127, 0, 0, 1}, message()),
  74. ?assertEqual(undefined, apply_func(peerhost, [], #{})),
  75. ?assertEqual(<<"127.0.0.1">>, apply_func(peerhost, [], eventmsg_publish(Msg))).
  76. t_username(_) ->
  77. Msg = emqx_message:set_header(username, <<"feng">>, message()),
  78. ?assertEqual(<<"feng">>, apply_func(username, [], eventmsg_publish(Msg))).
  79. t_payload(_) ->
  80. Input = emqx_message:to_map(message()),
  81. NestedMap = #{a => #{b => #{c => c}}},
  82. ?assertEqual(<<"hello">>, apply_func(payload, [], Input#{payload => <<"hello">>})),
  83. ?assertEqual(c, apply_func(payload, [<<"a.b.c">>], Input#{payload => NestedMap})).
  84. %%------------------------------------------------------------------------------
  85. %% Data Type Conversion Funcs
  86. %%------------------------------------------------------------------------------
  87. t_str(_) ->
  88. ?assertEqual(<<"abc">>, emqx_rule_funcs:str("abc")),
  89. ?assertEqual(<<"abc">>, emqx_rule_funcs:str(abc)),
  90. ?assertEqual(<<"{\"a\":1}">>, emqx_rule_funcs:str(#{a => 1})),
  91. ?assertEqual(<<"[{\"a\":1},{\"b\":1}]">>, emqx_rule_funcs:str([#{a => 1}, #{b => 1}])),
  92. ?assertEqual(<<"1">>, emqx_rule_funcs:str(1)),
  93. ?assertEqual(<<"2.0">>, emqx_rule_funcs:str(2.0)),
  94. ?assertEqual(<<"true">>, emqx_rule_funcs:str(true)),
  95. ?assertError(_, emqx_rule_funcs:str({a, v})),
  96. ?assertEqual(<<"abc">>, emqx_rule_funcs:str_utf8("abc")),
  97. ?assertEqual(<<"abc 你好"/utf8>>, emqx_rule_funcs:str_utf8("abc 你好")),
  98. ?assertEqual(<<"abc 你好"/utf8>>, emqx_rule_funcs:str_utf8(<<"abc 你好"/utf8>>)),
  99. ?assertEqual(<<"abc">>, emqx_rule_funcs:str_utf8(abc)),
  100. ?assertEqual(
  101. <<"{\"a\":\"abc 你好\"}"/utf8>>, emqx_rule_funcs:str_utf8(#{a => <<"abc 你好"/utf8>>})
  102. ),
  103. ?assertEqual(<<"1">>, emqx_rule_funcs:str_utf8(1)),
  104. ?assertEqual(<<"2.0">>, emqx_rule_funcs:str_utf8(2.0)),
  105. ?assertEqual(<<"true">>, emqx_rule_funcs:str_utf8(true)),
  106. ?assertError(_, emqx_rule_funcs:str_utf8({a, v})).
  107. t_int(_) ->
  108. ?assertEqual(1, emqx_rule_funcs:int("1")),
  109. ?assertEqual(1, emqx_rule_funcs:int(<<"1.0">>)),
  110. ?assertEqual(1, emqx_rule_funcs:int(1)),
  111. ?assertEqual(1, emqx_rule_funcs:int(1.9)),
  112. ?assertEqual(1, emqx_rule_funcs:int(1.0001)),
  113. ?assertEqual(1, emqx_rule_funcs:int(true)),
  114. ?assertEqual(0, emqx_rule_funcs:int(false)),
  115. ?assertError(badarg, emqx_rule_funcs:int({a, v})),
  116. ?assertError(_, emqx_rule_funcs:int("a")).
  117. t_float(_) ->
  118. ?assertEqual(1.0, emqx_rule_funcs:float("1.0")),
  119. ?assertEqual(1.0, emqx_rule_funcs:float(<<"1.0">>)),
  120. ?assertEqual(1.0, emqx_rule_funcs:float(1)),
  121. ?assertEqual(1.0, emqx_rule_funcs:float(1.0)),
  122. ?assertEqual(1.9, emqx_rule_funcs:float(1.9)),
  123. ?assertEqual(1.0001, emqx_rule_funcs:float(1.0001)),
  124. ?assertEqual(1.0000000001, emqx_rule_funcs:float(1.0000000001)),
  125. ?assertError(badarg, emqx_rule_funcs:float({a, v})),
  126. ?assertError(_, emqx_rule_funcs:float("a")).
  127. t_map(_) ->
  128. ?assertEqual(
  129. #{ver => <<"1.0">>, name => "emqx"}, emqx_rule_funcs:map([{ver, <<"1.0">>}, {name, "emqx"}])
  130. ),
  131. ?assertEqual(#{<<"a">> => 1}, emqx_rule_funcs:map(<<"{\"a\":1}">>)),
  132. ?assertError(_, emqx_rule_funcs:map(<<"a">>)),
  133. ?assertError(_, emqx_rule_funcs:map("a")),
  134. ?assertError(_, emqx_rule_funcs:map(1.0)).
  135. t_bool(_) ->
  136. ?assertEqual(true, emqx_rule_funcs:bool(1)),
  137. ?assertEqual(true, emqx_rule_funcs:bool(1.0)),
  138. ?assertEqual(false, emqx_rule_funcs:bool(0)),
  139. ?assertEqual(false, emqx_rule_funcs:bool(0.0)),
  140. ?assertEqual(true, emqx_rule_funcs:bool(true)),
  141. ?assertEqual(true, emqx_rule_funcs:bool(<<"true">>)),
  142. ?assertEqual(false, emqx_rule_funcs:bool(false)),
  143. ?assertEqual(false, emqx_rule_funcs:bool(<<"false">>)),
  144. ?assertError(badarg, emqx_rule_funcs:bool(3)).
  145. t_proc_dict_put_get_del(_) ->
  146. ?assertEqual(undefined, emqx_rule_funcs:proc_dict_get(<<"abc">>)),
  147. emqx_rule_funcs:proc_dict_put(<<"abc">>, 1),
  148. ?assertEqual(1, emqx_rule_funcs:proc_dict_get(<<"abc">>)),
  149. emqx_rule_funcs:proc_dict_del(<<"abc">>),
  150. ?assertEqual(undefined, emqx_rule_funcs:proc_dict_get(<<"abc">>)).
  151. t_term_encode(_) ->
  152. TestData = [<<"abc">>, #{a => 1}, #{<<"3">> => [1, 2, 4]}],
  153. lists:foreach(
  154. fun(Data) ->
  155. ?assertEqual(
  156. Data,
  157. emqx_rule_funcs:term_decode(
  158. emqx_rule_funcs:term_encode(Data)
  159. )
  160. )
  161. end,
  162. TestData
  163. ).
  164. t_float2str(_) ->
  165. ?assertEqual(<<"20.2">>, emqx_rule_funcs:float2str(20.2, 1)),
  166. ?assertEqual(<<"20.2">>, emqx_rule_funcs:float2str(20.2, 10)),
  167. ?assertEqual(<<"20.199999999999999">>, emqx_rule_funcs:float2str(20.2, 15)),
  168. ?assertEqual(<<"20.1999999999999993">>, emqx_rule_funcs:float2str(20.2, 16)).
  169. t_hexstr2bin(_) ->
  170. ?assertEqual(<<6, 54, 79>>, emqx_rule_funcs:hexstr2bin(<<"6364f">>)),
  171. ?assertEqual(<<10>>, emqx_rule_funcs:hexstr2bin(<<"a">>)),
  172. ?assertEqual(<<15>>, emqx_rule_funcs:hexstr2bin(<<"f">>)),
  173. ?assertEqual(<<5>>, emqx_rule_funcs:hexstr2bin(<<"5">>)),
  174. ?assertEqual(<<1, 2>>, emqx_rule_funcs:hexstr2bin(<<"0102">>)),
  175. ?assertEqual(<<17, 33>>, emqx_rule_funcs:hexstr2bin(<<"1121">>)).
  176. t_bin2hexstr(_) ->
  177. ?assertEqual(<<"0102">>, emqx_rule_funcs:bin2hexstr(<<1, 2>>)),
  178. ?assertEqual(<<"1121">>, emqx_rule_funcs:bin2hexstr(<<17, 33>>)).
  179. t_bin2hexstr_not_even_bytes(_) ->
  180. ?assertEqual(<<"0102">>, emqx_rule_funcs:bin2hexstr(<<1:5, 2>>)),
  181. ?assertEqual(<<"1002">>, emqx_rule_funcs:bin2hexstr(<<16:5, 2>>)),
  182. ?assertEqual(<<"1002">>, emqx_rule_funcs:bin2hexstr(<<16:8, 2>>)),
  183. ?assertEqual(<<"102">>, emqx_rule_funcs:bin2hexstr(<<1:4, 2>>)),
  184. ?assertEqual(<<"102">>, emqx_rule_funcs:bin2hexstr(<<1:3, 2>>)),
  185. ?assertEqual(<<"102">>, emqx_rule_funcs:bin2hexstr(<<1:1, 2>>)),
  186. ?assertEqual(<<"002">>, emqx_rule_funcs:bin2hexstr(<<2:1, 2>>)),
  187. ?assertEqual(<<"02">>, emqx_rule_funcs:bin2hexstr(<<2>>)),
  188. ?assertEqual(<<"2">>, emqx_rule_funcs:bin2hexstr(<<2:2>>)),
  189. ?assertEqual(<<"1121">>, emqx_rule_funcs:bin2hexstr(<<17, 33>>)),
  190. ?assertEqual(<<"01121">>, emqx_rule_funcs:bin2hexstr(<<17:9, 33>>)).
  191. t_hex_convert(_) ->
  192. ?PROPTEST(hex_convert).
  193. hex_convert() ->
  194. ?FORALL(
  195. L,
  196. list(range(0, 255)),
  197. begin
  198. AbitraryBin = list_to_binary(L),
  199. AbitraryBin ==
  200. emqx_rule_funcs:hexstr2bin(
  201. emqx_rule_funcs:bin2hexstr(AbitraryBin)
  202. )
  203. end
  204. ).
  205. t_is_null(_) ->
  206. ?assertEqual(false, emqx_rule_funcs:is_null(null)),
  207. ?assertEqual(true, emqx_rule_funcs:is_null(undefined)),
  208. ?assertEqual(false, emqx_rule_funcs:is_null(<<"undefined">>)),
  209. ?assertEqual(false, emqx_rule_funcs:is_null(a)),
  210. ?assertEqual(false, emqx_rule_funcs:is_null(<<>>)),
  211. ?assertEqual(false, emqx_rule_funcs:is_null(<<"a">>)).
  212. t_is_null_var(_) ->
  213. ?assertEqual(true, emqx_rule_funcs:is_null_var(null)),
  214. ?assertEqual(false, emqx_rule_funcs:is_null_var(<<"null">>)),
  215. ?assertEqual(true, emqx_rule_funcs:is_null_var(undefined)),
  216. ?assertEqual(false, emqx_rule_funcs:is_null_var(<<"undefined">>)),
  217. ?assertEqual(false, emqx_rule_funcs:is_null_var(a)),
  218. ?assertEqual(false, emqx_rule_funcs:is_null_var(<<>>)),
  219. ?assertEqual(false, emqx_rule_funcs:is_null_var(<<"a">>)).
  220. t_is_not_null(_) ->
  221. [
  222. ?assertEqual(emqx_rule_funcs:is_not_null(T), not emqx_rule_funcs:is_null(T))
  223. || T <- [undefined, <<"undefined">>, null, <<"null">>, a, <<"a">>, <<>>]
  224. ].
  225. t_is_not_null_var(_) ->
  226. [
  227. ?assertEqual(emqx_rule_funcs:is_not_null_var(T), not emqx_rule_funcs:is_null_var(T))
  228. || T <- [undefined, <<"undefined">>, null, <<"null">>, a, <<"a">>, <<>>]
  229. ].
  230. t_is_str(_) ->
  231. [
  232. ?assertEqual(true, emqx_rule_funcs:is_str(T))
  233. || T <- [<<"a">>, <<>>, <<"abc">>]
  234. ],
  235. [
  236. ?assertEqual(false, emqx_rule_funcs:is_str(T))
  237. || T <- ["a", a, 1]
  238. ].
  239. t_is_bool(_) ->
  240. [
  241. ?assertEqual(true, emqx_rule_funcs:is_bool(T))
  242. || T <- [true, false]
  243. ],
  244. [
  245. ?assertEqual(false, emqx_rule_funcs:is_bool(T))
  246. || T <- ["a", <<>>, a, 2]
  247. ].
  248. t_is_int(_) ->
  249. [
  250. ?assertEqual(true, emqx_rule_funcs:is_int(T))
  251. || T <- [1, 2, -1]
  252. ],
  253. [
  254. ?assertEqual(false, emqx_rule_funcs:is_int(T))
  255. || T <- [1.1, "a", a]
  256. ].
  257. t_is_float(_) ->
  258. [
  259. ?assertEqual(true, emqx_rule_funcs:is_float(T))
  260. || T <- [1.1, 2.0, -1.2]
  261. ],
  262. [
  263. ?assertEqual(false, emqx_rule_funcs:is_float(T))
  264. || T <- [1, "a", a, <<>>]
  265. ].
  266. t_is_num(_) ->
  267. [
  268. ?assertEqual(true, emqx_rule_funcs:is_num(T))
  269. || T <- [1.1, 2.0, -1.2, 1]
  270. ],
  271. [
  272. ?assertEqual(false, emqx_rule_funcs:is_num(T))
  273. || T <- ["a", a, <<>>]
  274. ].
  275. t_is_map(_) ->
  276. [
  277. ?assertEqual(true, emqx_rule_funcs:is_map(T))
  278. || T <- [#{}, #{a => 1}]
  279. ],
  280. [
  281. ?assertEqual(false, emqx_rule_funcs:is_map(T))
  282. || T <- ["a", a, <<>>]
  283. ].
  284. t_is_array(_) ->
  285. [
  286. ?assertEqual(true, emqx_rule_funcs:is_array(T))
  287. || T <- [[], [1, 2]]
  288. ],
  289. [
  290. ?assertEqual(false, emqx_rule_funcs:is_array(T))
  291. || T <- [<<>>, a]
  292. ].
  293. %%------------------------------------------------------------------------------
  294. %% Test cases for arith op
  295. %%------------------------------------------------------------------------------
  296. t_arith_op(_) ->
  297. ?PROPTEST(prop_arith_op).
  298. prop_arith_op() ->
  299. ?FORALL(
  300. {X, Y},
  301. {number(), number()},
  302. begin
  303. (X + Y) == apply_func('+', [X, Y]) andalso
  304. (X - Y) == apply_func('-', [X, Y]) andalso
  305. (X * Y) == apply_func('*', [X, Y]) andalso
  306. (if
  307. Y =/= 0 ->
  308. (X / Y) == apply_func('/', [X, Y]);
  309. true ->
  310. true
  311. end) andalso
  312. (case
  313. is_integer(X) andalso
  314. is_pos_integer(Y)
  315. of
  316. true ->
  317. (X rem Y) == apply_func('mod', [X, Y]);
  318. false ->
  319. true
  320. end)
  321. end
  322. ).
  323. is_pos_integer(X) ->
  324. is_integer(X) andalso X > 0.
  325. %%------------------------------------------------------------------------------
  326. %% Test cases for math fun
  327. %%------------------------------------------------------------------------------
  328. t_math_fun(_) ->
  329. ?PROPTEST(prop_math_fun).
  330. prop_math_fun() ->
  331. Excluded = [module_info, atanh, asin, acos],
  332. MathFuns = [
  333. {F, A}
  334. || {F, A} <- math:module_info(exports),
  335. not lists:member(F, Excluded),
  336. erlang:function_exported(emqx_rule_funcs, F, A)
  337. ],
  338. ?FORALL(
  339. {X, Y},
  340. {pos_integer(), pos_integer()},
  341. begin
  342. lists:foldl(
  343. fun
  344. ({F, 1}, True) ->
  345. True andalso comp_with_math(F, X);
  346. ({F = fmod, 2}, True) ->
  347. True andalso
  348. (if
  349. Y =/= 0 ->
  350. comp_with_math(F, X, Y);
  351. true ->
  352. true
  353. end);
  354. ({F, 2}, True) ->
  355. True andalso comp_with_math(F, X, Y)
  356. end,
  357. true,
  358. MathFuns
  359. )
  360. end
  361. ).
  362. comp_with_math(Fun, X) when
  363. Fun =:= exp;
  364. Fun =:= sinh;
  365. Fun =:= cosh
  366. ->
  367. if
  368. X < 710 -> math:Fun(X) == apply_func(Fun, [X]);
  369. true -> true
  370. end;
  371. comp_with_math(F, X) ->
  372. math:F(X) == apply_func(F, [X]).
  373. comp_with_math(F, X, Y) ->
  374. math:F(X, Y) == apply_func(F, [X, Y]).
  375. %%------------------------------------------------------------------------------
  376. %% Test cases for bits op
  377. %%------------------------------------------------------------------------------
  378. t_bits_op(_) ->
  379. ?PROPTEST(prop_bits_op).
  380. prop_bits_op() ->
  381. ?FORALL(
  382. {X, Y},
  383. {integer(), integer()},
  384. begin
  385. (bnot X) == apply_func(bitnot, [X]) andalso
  386. (X band Y) == apply_func(bitand, [X, Y]) andalso
  387. (X bor Y) == apply_func(bitor, [X, Y]) andalso
  388. (X bxor Y) == apply_func(bitxor, [X, Y]) andalso
  389. (X bsl Y) == apply_func(bitsl, [X, Y]) andalso
  390. (X bsr Y) == apply_func(bitsr, [X, Y])
  391. end
  392. ).
  393. %%------------------------------------------------------------------------------
  394. %% Test cases for string
  395. %%------------------------------------------------------------------------------
  396. t_lower_upper(_) ->
  397. ?assertEqual(<<"ABC4">>, apply_func(upper, [<<"abc4">>])),
  398. ?assertEqual(<<"0abc">>, apply_func(lower, [<<"0ABC">>])).
  399. t_reverse(_) ->
  400. ?assertEqual(<<"dcba">>, apply_func(reverse, [<<"abcd">>])),
  401. ?assertEqual(<<"4321">>, apply_func(reverse, [<<"1234">>])).
  402. t_strlen(_) ->
  403. ?assertEqual(4, apply_func(strlen, [<<"abcd">>])),
  404. ?assertEqual(2, apply_func(strlen, [<<"你好">>])).
  405. t_substr(_) ->
  406. ?assertEqual(<<"">>, apply_func(substr, [<<"">>, 1])),
  407. ?assertEqual(<<"bc">>, apply_func(substr, [<<"abc">>, 1])),
  408. ?assertEqual(<<"bc">>, apply_func(substr, [<<"abcd">>, 1, 2])).
  409. t_trim(_) ->
  410. ?assertEqual(<<>>, apply_func(trim, [<<>>])),
  411. ?assertEqual(<<>>, apply_func(ltrim, [<<>>])),
  412. ?assertEqual(<<>>, apply_func(rtrim, [<<>>])),
  413. ?assertEqual(<<"abc">>, apply_func(trim, [<<" abc ">>])),
  414. ?assertEqual(<<"abc ">>, apply_func(ltrim, [<<" abc ">>])),
  415. ?assertEqual(<<" abc">>, apply_func(rtrim, [<<" abc">>])).
  416. t_split_all(_) ->
  417. ?assertEqual([], apply_func(split, [<<>>, <<"/">>])),
  418. ?assertEqual([], apply_func(split, [<<"/">>, <<"/">>])),
  419. ?assertEqual([<<"a">>, <<"b">>, <<"c">>], apply_func(split, [<<"/a/b/c">>, <<"/">>])),
  420. ?assertEqual([<<"a">>, <<"b">>, <<"c">>], apply_func(split, [<<"/a/b//c/">>, <<"/">>])),
  421. ?assertEqual([<<"a">>, <<"b">>, <<"c">>], apply_func(split, [<<"a,b,c">>, <<",">>])),
  422. ?assertEqual([<<"a">>, <<" b ">>, <<"c">>], apply_func(split, [<<"a, b ,c">>, <<",">>])),
  423. ?assertEqual([<<"a">>, <<"b">>, <<"c\n">>], apply_func(split, [<<"a,b,c\n">>, <<",">>])),
  424. ?assertEqual([<<"a">>, <<"b">>, <<"c\r\n">>], apply_func(split, [<<"a,b,c\r\n">>, <<",">>])).
  425. t_split_notrim_all(_) ->
  426. ?assertEqual([<<>>], apply_func(split, [<<>>, <<"/">>, <<"notrim">>])),
  427. ?assertEqual([<<>>, <<>>], apply_func(split, [<<"/">>, <<"/">>, <<"notrim">>])),
  428. ?assertEqual(
  429. [<<>>, <<"a">>, <<"b">>, <<"c">>], apply_func(split, [<<"/a/b/c">>, <<"/">>, <<"notrim">>])
  430. ),
  431. ?assertEqual(
  432. [<<>>, <<"a">>, <<"b">>, <<>>, <<"c">>, <<>>],
  433. apply_func(split, [<<"/a/b//c/">>, <<"/">>, <<"notrim">>])
  434. ),
  435. ?assertEqual(
  436. [<<>>, <<"a">>, <<"b">>, <<"c\n">>],
  437. apply_func(split, [<<",a,b,c\n">>, <<",">>, <<"notrim">>])
  438. ),
  439. ?assertEqual(
  440. [<<"a">>, <<" b">>, <<"c\r\n">>],
  441. apply_func(split, [<<"a, b,c\r\n">>, <<",">>, <<"notrim">>])
  442. ),
  443. ?assertEqual(
  444. [<<"哈哈"/utf8>>, <<" 你好"/utf8>>, <<" 是的\r\n"/utf8>>],
  445. apply_func(split, [<<"哈哈, 你好, 是的\r\n"/utf8>>, <<",">>, <<"notrim">>])
  446. ).
  447. t_split_leading(_) ->
  448. ?assertEqual([], apply_func(split, [<<>>, <<"/">>, <<"leading">>])),
  449. ?assertEqual([], apply_func(split, [<<"/">>, <<"/">>, <<"leading">>])),
  450. ?assertEqual([<<"a/b/c">>], apply_func(split, [<<"/a/b/c">>, <<"/">>, <<"leading">>])),
  451. ?assertEqual(
  452. [<<"a">>, <<"b//c/">>], apply_func(split, [<<"a/b//c/">>, <<"/">>, <<"leading">>])
  453. ),
  454. ?assertEqual(
  455. [<<"a">>, <<"b,c\n">>], apply_func(split, [<<"a,b,c\n">>, <<",">>, <<"leading">>])
  456. ),
  457. ?assertEqual(
  458. [<<"a b">>, <<"c\r\n">>], apply_func(split, [<<"a b,c\r\n">>, <<",">>, <<"leading">>])
  459. ),
  460. ?assertEqual(
  461. [<<"哈哈"/utf8>>, <<" 你好, 是的\r\n"/utf8>>],
  462. apply_func(split, [<<"哈哈, 你好, 是的\r\n"/utf8>>, <<",">>, <<"leading">>])
  463. ).
  464. t_split_leading_notrim(_) ->
  465. ?assertEqual([<<>>], apply_func(split, [<<>>, <<"/">>, <<"leading_notrim">>])),
  466. ?assertEqual([<<>>, <<>>], apply_func(split, [<<"/">>, <<"/">>, <<"leading_notrim">>])),
  467. ?assertEqual(
  468. [<<>>, <<"a/b/c">>], apply_func(split, [<<"/a/b/c">>, <<"/">>, <<"leading_notrim">>])
  469. ),
  470. ?assertEqual(
  471. [<<"a">>, <<"b//c/">>], apply_func(split, [<<"a/b//c/">>, <<"/">>, <<"leading_notrim">>])
  472. ),
  473. ?assertEqual(
  474. [<<"a">>, <<"b,c\n">>], apply_func(split, [<<"a,b,c\n">>, <<",">>, <<"leading_notrim">>])
  475. ),
  476. ?assertEqual(
  477. [<<"a b">>, <<"c\r\n">>],
  478. apply_func(split, [<<"a b,c\r\n">>, <<",">>, <<"leading_notrim">>])
  479. ),
  480. ?assertEqual(
  481. [<<"哈哈"/utf8>>, <<" 你好, 是的\r\n"/utf8>>],
  482. apply_func(split, [<<"哈哈, 你好, 是的\r\n"/utf8>>, <<",">>, <<"leading_notrim">>])
  483. ).
  484. t_split_trailing(_) ->
  485. ?assertEqual([], apply_func(split, [<<>>, <<"/">>, <<"trailing">>])),
  486. ?assertEqual([], apply_func(split, [<<"/">>, <<"/">>, <<"trailing">>])),
  487. ?assertEqual([<<"/a/b">>, <<"c">>], apply_func(split, [<<"/a/b/c">>, <<"/">>, <<"trailing">>])),
  488. ?assertEqual([<<"a/b//c">>], apply_func(split, [<<"a/b//c/">>, <<"/">>, <<"trailing">>])),
  489. ?assertEqual(
  490. [<<"a,b">>, <<"c\n">>], apply_func(split, [<<"a,b,c\n">>, <<",">>, <<"trailing">>])
  491. ),
  492. ?assertEqual(
  493. [<<"a b">>, <<"c\r\n">>], apply_func(split, [<<"a b,c\r\n">>, <<",">>, <<"trailing">>])
  494. ),
  495. ?assertEqual(
  496. [<<"哈哈, 你好"/utf8>>, <<" 是的\r\n"/utf8>>],
  497. apply_func(split, [<<"哈哈, 你好, 是的\r\n"/utf8>>, <<",">>, <<"trailing">>])
  498. ).
  499. t_split_trailing_notrim(_) ->
  500. ?assertEqual([<<>>], apply_func(split, [<<>>, <<"/">>, <<"trailing_notrim">>])),
  501. ?assertEqual([<<>>, <<>>], apply_func(split, [<<"/">>, <<"/">>, <<"trailing_notrim">>])),
  502. ?assertEqual(
  503. [<<"/a/b">>, <<"c">>], apply_func(split, [<<"/a/b/c">>, <<"/">>, <<"trailing_notrim">>])
  504. ),
  505. ?assertEqual(
  506. [<<"a/b//c">>, <<>>], apply_func(split, [<<"a/b//c/">>, <<"/">>, <<"trailing_notrim">>])
  507. ),
  508. ?assertEqual(
  509. [<<"a,b">>, <<"c\n">>], apply_func(split, [<<"a,b,c\n">>, <<",">>, <<"trailing_notrim">>])
  510. ),
  511. ?assertEqual(
  512. [<<"a b">>, <<"c\r\n">>],
  513. apply_func(split, [<<"a b,c\r\n">>, <<",">>, <<"trailing_notrim">>])
  514. ),
  515. ?assertEqual(
  516. [<<"哈哈, 你好"/utf8>>, <<" 是的\r\n"/utf8>>],
  517. apply_func(split, [<<"哈哈, 你好, 是的\r\n"/utf8>>, <<",">>, <<"trailing_notrim">>])
  518. ).
  519. t_tokens(_) ->
  520. ?assertEqual([], apply_func(tokens, [<<>>, <<"/">>])),
  521. ?assertEqual([], apply_func(tokens, [<<"/">>, <<"/">>])),
  522. ?assertEqual([<<"a">>, <<"b">>, <<"c">>], apply_func(tokens, [<<"/a/b/c">>, <<"/">>])),
  523. ?assertEqual([<<"a">>, <<"b">>, <<"c">>], apply_func(tokens, [<<"/a/b//c/">>, <<"/">>])),
  524. ?assertEqual([<<"a">>, <<"b">>, <<"c">>], apply_func(tokens, [<<" /a/ b /c">>, <<" /">>])),
  525. ?assertEqual([<<"a">>, <<"\nb">>, <<"c\n">>], apply_func(tokens, [<<"a ,\nb,c\n">>, <<", ">>])),
  526. ?assertEqual([<<"a">>, <<"b">>, <<"c\r\n">>], apply_func(tokens, [<<"a ,b,c\r\n">>, <<", ">>])),
  527. ?assertEqual(
  528. [<<"a">>, <<"b">>, <<"c">>], apply_func(tokens, [<<"a,b, c\n">>, <<", ">>, <<"nocrlf">>])
  529. ),
  530. ?assertEqual(
  531. [<<"a">>, <<"b">>, <<"c">>], apply_func(tokens, [<<"a,b,c\r\n">>, <<",">>, <<"nocrlf">>])
  532. ),
  533. ?assertEqual(
  534. [<<"a">>, <<"b">>, <<"c">>], apply_func(tokens, [<<"a,b\r\n,c\n">>, <<",">>, <<"nocrlf">>])
  535. ),
  536. ?assertEqual([], apply_func(tokens, [<<"\r\n">>, <<",">>, <<"nocrlf">>])),
  537. ?assertEqual([], apply_func(tokens, [<<"\r\n">>, <<",">>, <<"nocrlf">>])),
  538. ?assertEqual(
  539. [<<"哈哈"/utf8>>, <<"你好"/utf8>>, <<"是的"/utf8>>],
  540. apply_func(tokens, [<<"哈哈, 你好, 是的\r\n"/utf8>>, <<", ">>, <<"nocrlf">>])
  541. ).
  542. t_concat(_) ->
  543. ?assertEqual(<<"ab">>, apply_func(concat, [<<"a">>, <<"b">>])),
  544. ?assertEqual(<<"ab">>, apply_func('+', [<<"a">>, <<"b">>])),
  545. ?assertEqual(<<"哈哈你好"/utf8>>, apply_func(concat, [<<"哈哈"/utf8>>, <<"你好"/utf8>>])),
  546. ?assertEqual(<<"abc">>, apply_func(concat, [apply_func(concat, [<<"a">>, <<"b">>]), <<"c">>])),
  547. ?assertEqual(<<"a">>, apply_func(concat, [<<"">>, <<"a">>])),
  548. ?assertEqual(<<"a">>, apply_func(concat, [<<"a">>, <<"">>])),
  549. ?assertEqual(<<>>, apply_func(concat, [<<"">>, <<"">>])).
  550. t_sprintf(_) ->
  551. ?assertEqual(<<"Hello Shawn!">>, apply_func(sprintf, [<<"Hello ~ts!">>, <<"Shawn">>])),
  552. ?assertEqual(
  553. <<"Name: ABC, Count: 2">>, apply_func(sprintf, [<<"Name: ~ts, Count: ~p">>, <<"ABC">>, 2])
  554. ),
  555. ?assertEqual(
  556. <<"Name: ABC, Count: 2, Status: {ok,running}">>,
  557. apply_func(sprintf, [<<"Name: ~ts, Count: ~p, Status: ~p">>, <<"ABC">>, 2, {ok, running}])
  558. ).
  559. t_pad(_) ->
  560. ?assertEqual(<<"abc ">>, apply_func(pad, [<<"abc">>, 5])),
  561. ?assertEqual(<<"abc">>, apply_func(pad, [<<"abc">>, 0])),
  562. ?assertEqual(<<"abc ">>, apply_func(pad, [<<"abc">>, 5, <<"trailing">>])),
  563. ?assertEqual(<<"abc">>, apply_func(pad, [<<"abc">>, 0, <<"trailing">>])),
  564. ?assertEqual(<<" abc ">>, apply_func(pad, [<<"abc">>, 5, <<"both">>])),
  565. ?assertEqual(<<"abc">>, apply_func(pad, [<<"abc">>, 0, <<"both">>])),
  566. ?assertEqual(<<" abc">>, apply_func(pad, [<<"abc">>, 5, <<"leading">>])),
  567. ?assertEqual(<<"abc">>, apply_func(pad, [<<"abc">>, 0, <<"leading">>])).
  568. t_pad_char(_) ->
  569. ?assertEqual(<<"abcee">>, apply_func(pad, [<<"abc">>, 5, <<"trailing">>, <<"e">>])),
  570. ?assertEqual(<<"abcexex">>, apply_func(pad, [<<"abc">>, 5, <<"trailing">>, <<"ex">>])),
  571. ?assertEqual(<<"eabce">>, apply_func(pad, [<<"abc">>, 5, <<"both">>, <<"e">>])),
  572. ?assertEqual(<<"exabcex">>, apply_func(pad, [<<"abc">>, 5, <<"both">>, <<"ex">>])),
  573. ?assertEqual(<<"eeabc">>, apply_func(pad, [<<"abc">>, 5, <<"leading">>, <<"e">>])),
  574. ?assertEqual(<<"exexabc">>, apply_func(pad, [<<"abc">>, 5, <<"leading">>, <<"ex">>])).
  575. t_replace(_) ->
  576. ?assertEqual(<<"ab-c--">>, apply_func(replace, [<<"ab c ">>, <<" ">>, <<"-">>])),
  577. ?assertEqual(<<"ab::c::::">>, apply_func(replace, [<<"ab c ">>, <<" ">>, <<"::">>])),
  578. ?assertEqual(<<"ab-c--">>, apply_func(replace, [<<"ab c ">>, <<" ">>, <<"-">>, <<"all">>])),
  579. ?assertEqual(
  580. <<"ab-c ">>, apply_func(replace, [<<"ab c ">>, <<" ">>, <<"-">>, <<"leading">>])
  581. ),
  582. ?assertEqual(
  583. <<"ab c -">>, apply_func(replace, [<<"ab c ">>, <<" ">>, <<"-">>, <<"trailing">>])
  584. ).
  585. t_ascii(_) ->
  586. ?assertEqual(97, apply_func(ascii, [<<"a">>])),
  587. ?assertEqual(97, apply_func(ascii, [<<"ab">>])).
  588. t_join_to_string(_) ->
  589. A = 1,
  590. B = a,
  591. C = <<"c">>,
  592. D = #{a => 1},
  593. E = [1, 2, 3],
  594. F = [#{<<"key">> => 1, <<"value">> => 2}],
  595. M = #{<<"a">> => a, <<"b">> => 1, <<"c">> => <<"c">>},
  596. J = <<"{\"a\":\"a\",\"b\":1,\"c\":\"c\"}">>,
  597. ?assertEqual(<<"a,b,c">>, apply_func(join_to_string, [<<",">>, [<<"a">>, <<"b">>, <<"c">>]])),
  598. ?assertEqual(<<"a b c">>, apply_func(join_to_string, [<<" ">>, [<<"a">>, <<"b">>, <<"c">>]])),
  599. ?assertEqual(
  600. <<"a, b, c">>, apply_func(join_to_string, [<<", ">>, [<<"a">>, <<"b">>, <<"c">>]])
  601. ),
  602. ?assertEqual(
  603. <<"1, a, c, {\"a\":1}, [1,2,3], [{\"value\":2,\"key\":1}]">>,
  604. apply_func(join_to_string, [<<", ">>, [A, B, C, D, E, F]])
  605. ),
  606. ?assertEqual(<<"a">>, apply_func(join_to_string, [<<",">>, [<<"a">>]])),
  607. ?assertEqual(<<"">>, apply_func(join_to_string, [<<",">>, []])),
  608. ?assertEqual(<<"a, b, c">>, apply_func(join_to_string, [emqx_rule_funcs:map_keys(M)])),
  609. ?assertEqual(<<"a, b, c">>, apply_func(join_to_string, [emqx_rule_funcs:map_keys(J)])),
  610. ?assertEqual(<<"a, 1, c">>, apply_func(join_to_string, [emqx_rule_funcs:map_values(M)])),
  611. ?assertEqual(<<"a, 1, c">>, apply_func(join_to_string, [emqx_rule_funcs:map_values(J)])).
  612. t_join_to_sql_values_string(_) ->
  613. A = 1,
  614. B = a,
  615. C = <<"c">>,
  616. D = #{a => 1},
  617. E = [1, 2, 3],
  618. E1 = [97, 98],
  619. F = [#{<<"key">> => 1, <<"value">> => 2}],
  620. M = #{<<"a">> => a, <<"b">> => 1, <<"c">> => <<"c">>},
  621. J = <<"{\"a\":\"a\",\"b\":1,\"c\":\"c\"}">>,
  622. ?assertEqual(
  623. <<"'a', 'b', 'c'">>, apply_func(join_to_sql_values_string, [[<<"a">>, <<"b">>, <<"c">>]])
  624. ),
  625. ?assertEqual(
  626. <<"1, 'a', 'c', '{\"a\":1}', '[1,2,3]', '[97,98]', '[{\"value\":2,\"key\":1}]'">>,
  627. apply_func(join_to_sql_values_string, [[A, B, C, D, E, E1, F]])
  628. ),
  629. ?assertEqual(<<"'a'">>, apply_func(join_to_sql_values_string, [[<<"a">>]])),
  630. ?assertEqual(<<"">>, apply_func(join_to_sql_values_string, [[]])),
  631. ?assertEqual(
  632. <<"'a', 'b', 'c'">>, apply_func(join_to_sql_values_string, [emqx_rule_funcs:map_keys(M)])
  633. ),
  634. ?assertEqual(
  635. <<"'a', 'b', 'c'">>, apply_func(join_to_sql_values_string, [emqx_rule_funcs:map_keys(J)])
  636. ),
  637. ?assertEqual(
  638. <<"'a', 1, 'c'">>, apply_func(join_to_sql_values_string, [emqx_rule_funcs:map_values(M)])
  639. ),
  640. ?assertEqual(
  641. <<"'a', 1, 'c'">>, apply_func(join_to_sql_values_string, [emqx_rule_funcs:map_values(J)])
  642. ).
  643. t_find(_) ->
  644. ?assertEqual(<<"cbcd">>, apply_func(find, [<<"acbcd">>, <<"c">>])),
  645. ?assertEqual(<<"cbcd">>, apply_func(find, [<<"acbcd">>, <<"c">>, <<"leading">>])),
  646. ?assertEqual(<<"">>, apply_func(find, [<<"acbcd">>, <<"e">>])),
  647. ?assertEqual(<<"">>, apply_func(find, [<<"">>, <<"c">>])),
  648. ?assertEqual(<<"">>, apply_func(find, [<<"">>, <<"">>])).
  649. t_find_trailing(_) ->
  650. ?assertEqual(<<"cd">>, apply_func(find, [<<"acbcd">>, <<"c">>, <<"trailing">>])),
  651. ?assertEqual(<<"">>, apply_func(find, [<<"acbcd">>, <<"e">>, <<"trailing">>])),
  652. ?assertEqual(<<"">>, apply_func(find, [<<"">>, <<"c">>, <<"trailing">>])),
  653. ?assertEqual(<<"">>, apply_func(find, [<<"">>, <<"">>, <<"trailing">>])).
  654. t_regex_match(_) ->
  655. ?assertEqual(true, apply_func(regex_match, [<<"acbcd">>, <<"c">>])),
  656. ?assertEqual(true, apply_func(regex_match, [<<"acbcd">>, <<"(ac)+">>])),
  657. ?assertEqual(false, apply_func(regex_match, [<<"bcd">>, <<"(ac)+">>])),
  658. ?assertEqual(true, apply_func(regex_match, [<<>>, <<".*">>])),
  659. ?assertEqual(false, apply_func(regex_match, [<<>>, <<"[a-z]+">>])),
  660. ?assertEqual(true, apply_func(regex_match, [<<"exebd">>, <<"^[a-z]+$">>])),
  661. ?assertEqual(false, apply_func(regex_match, [<<"e2xebd">>, <<"^[a-z]+$">>])).
  662. t_regex_replace(_) ->
  663. ?assertEqual(<<>>, apply_func(regex_replace, [<<>>, <<"c.*">>, <<"e">>])),
  664. ?assertEqual(<<"aebed">>, apply_func(regex_replace, [<<"accbcd">>, <<"c+">>, <<"e">>])),
  665. ?assertEqual(<<"a[cc]b[c]d">>, apply_func(regex_replace, [<<"accbcd">>, <<"c+">>, <<"[&]">>])).
  666. t_unescape(_) ->
  667. ?assertEqual(<<"\n">> = <<10>>, emqx_rule_funcs:unescape(<<"\\n">>)),
  668. ?assertEqual(<<"\t">> = <<9>>, emqx_rule_funcs:unescape(<<"\\t">>)),
  669. ?assertEqual(<<"\r">> = <<13>>, emqx_rule_funcs:unescape(<<"\\r">>)),
  670. ?assertEqual(<<"\b">> = <<8>>, emqx_rule_funcs:unescape(<<"\\b">>)),
  671. ?assertEqual(<<"\f">> = <<12>>, emqx_rule_funcs:unescape(<<"\\f">>)),
  672. ?assertEqual(<<"\v">> = <<11>>, emqx_rule_funcs:unescape(<<"\\v">>)),
  673. ?assertEqual(<<"'">> = <<39>>, emqx_rule_funcs:unescape(<<"\\'">>)),
  674. ?assertEqual(<<"\"">> = <<34>>, emqx_rule_funcs:unescape(<<"\\\"">>)),
  675. ?assertEqual(<<"?">> = <<63>>, emqx_rule_funcs:unescape(<<"\\?">>)),
  676. ?assertEqual(<<7>>, emqx_rule_funcs:unescape(<<"\\a">>)),
  677. % Test escaping backslash itself
  678. ?assertEqual(<<"\\">> = <<92>>, emqx_rule_funcs:unescape(<<"\\\\">>)),
  679. % Test a string without any escape sequences
  680. ?assertEqual(<<"Hello, World!">>, emqx_rule_funcs:unescape(<<"Hello, World!">>)),
  681. % Test a string with escape sequences
  682. ?assertEqual(<<"Hello,\t World\n!">>, emqx_rule_funcs:unescape(<<"Hello,\\t World\\n!">>)),
  683. % Test unrecognized escape sequence (should throw an error)
  684. ?assertException(
  685. throw, {unrecognized_escape_sequence, <<$\\, $L>>}, emqx_rule_funcs:unescape(<<"\\L">>)
  686. ),
  687. % Test hexadecimal escape sequences
  688. % Newline
  689. ?assertEqual(<<"\n">>, emqx_rule_funcs:unescape(<<"\\x0A">>)),
  690. % Newline
  691. ?assertEqual(<<"hej\n">>, emqx_rule_funcs:unescape(<<"hej\\x0A">>)),
  692. % Newline
  693. ?assertEqual(<<"\nhej">>, emqx_rule_funcs:unescape(<<"\\x0Ahej">>)),
  694. % Newline
  695. ?assertEqual(<<"hej\nhej">>, emqx_rule_funcs:unescape(<<"hej\\x0Ahej">>)),
  696. % "ABC"
  697. ?assertEqual(<<"ABC">>, emqx_rule_funcs:unescape(<<"\\x41\\x42\\x43">>)),
  698. % "\xFF" = 255 in decimal
  699. ?assertEqual(<<"\xFF"/utf8>>, emqx_rule_funcs:unescape(<<"\\xFF">>)),
  700. % "W" = \x57
  701. ?assertEqual(<<"Hello, World!">>, emqx_rule_funcs:unescape(<<"Hello, \\x57orld!">>)).
  702. t_unescape_hex(_) ->
  703. ?assertEqual(<<"A"/utf8>>, emqx_rule_funcs:unescape(<<"\\x41">>)),
  704. ?assertEqual(<<"Hello"/utf8>>, emqx_rule_funcs:unescape(<<"\\x48\\x65\\x6c\\x6c\\x6f">>)),
  705. ?assertEqual(<<"A"/utf8>>, emqx_rule_funcs:unescape(<<"\\x0041">>)),
  706. ?assertEqual(<<"€"/utf8>>, emqx_rule_funcs:unescape(<<"\\x20AC">>)),
  707. ?assertEqual(<<"❤"/utf8>>, emqx_rule_funcs:unescape(<<"\\x2764">>)),
  708. ?assertException(
  709. throw, {unrecognized_escape_sequence, <<"\\x">>}, emqx_rule_funcs:unescape(<<"\\xG1">>)
  710. ),
  711. ?assertException(
  712. throw, {invalid_unicode_character, _}, emqx_rule_funcs:unescape(<<"\\x11000000">>)
  713. ),
  714. ?assertEqual(
  715. <<"Hello, 世界"/utf8>>, emqx_rule_funcs:unescape(<<"Hello, \\x00004E16\\x0000754C">>)
  716. ).
  717. jq_1_elm_res(JSONString) ->
  718. Bin = list_to_binary(JSONString),
  719. [apply_func(json_decode, [Bin])].
  720. t_jq(_) ->
  721. ?assertEqual(
  722. jq_1_elm_res("{\"b\":2}"),
  723. apply_func(jq, [<<".">>, apply_func(json_decode, [<<"{\"b\": 2}">>])])
  724. ),
  725. ?assertEqual(
  726. jq_1_elm_res("6"),
  727. apply_func(jq, [<<".+1">>, apply_func(json_decode, [<<"5">>])])
  728. ),
  729. ?assertEqual(
  730. jq_1_elm_res("{\"b\":2}"),
  731. apply_func(jq, [<<".">>, <<"{\"b\": 2}">>])
  732. ),
  733. %% Expicitly set timeout
  734. ?assertEqual(
  735. jq_1_elm_res("{\"b\":2}"),
  736. apply_func(jq, [<<".">>, <<"{\"b\": 2}">>, 10000])
  737. ),
  738. TOProgram = erlang:iolist_to_binary(
  739. "def while(cond; update):"
  740. " def _while:"
  741. " if cond then (update | _while) else . end;"
  742. " _while;"
  743. "while(. < 42; . * 2)"
  744. ),
  745. got_timeout =
  746. try
  747. apply_func(jq, [TOProgram, <<"-2">>, 10])
  748. catch
  749. throw:{jq_exception, {timeout, _}} ->
  750. %% Got timeout as expected
  751. got_timeout
  752. end,
  753. ?assertThrow(
  754. {jq_exception, {timeout, _}},
  755. apply_func(jq, [TOProgram, <<"-2">>])
  756. ).
  757. ascii_string() -> list(range(0, 127)).
  758. bin(S) -> iolist_to_binary(S).
  759. %%------------------------------------------------------------------------------
  760. %% Test cases for array funcs
  761. %%------------------------------------------------------------------------------
  762. t_nth(_) ->
  763. ?assertEqual(2, apply_func(nth, [2, [1, 2, 3, 4]])),
  764. ?assertEqual(4, apply_func(nth, [4, [1, 2, 3, 4]])).
  765. t_length(_) ->
  766. ?assertEqual(4, apply_func(length, [[1, 2, 3, 4]])),
  767. ?assertEqual(0, apply_func(length, [[]])).
  768. t_slice(_) ->
  769. ?assertEqual([1, 2, 3, 4], apply_func(sublist, [4, [1, 2, 3, 4]])),
  770. ?assertEqual([1, 2], apply_func(sublist, [2, [1, 2, 3, 4]])),
  771. ?assertEqual([4], apply_func(sublist, [4, 1, [1, 2, 3, 4]])),
  772. ?assertEqual([4], apply_func(sublist, [4, 2, [1, 2, 3, 4]])),
  773. ?assertEqual([], apply_func(sublist, [5, 2, [1, 2, 3, 4]])),
  774. ?assertEqual([2, 3], apply_func(sublist, [2, 2, [1, 2, 3, 4]])),
  775. ?assertEqual([1], apply_func(sublist, [1, 1, [1, 2, 3, 4]])).
  776. t_first_last(_) ->
  777. ?assertEqual(1, apply_func(first, [[1, 2, 3, 4]])),
  778. ?assertEqual(4, apply_func(last, [[1, 2, 3, 4]])).
  779. t_contains(_) ->
  780. ?assertEqual(true, apply_func(contains, [1, [1, 2, 3, 4]])),
  781. ?assertEqual(true, apply_func(contains, [3, [1, 2, 3, 4]])),
  782. ?assertEqual(true, apply_func(contains, [<<"a">>, [<<>>, <<"ab">>, 3, <<"a">>]])),
  783. ?assertEqual(true, apply_func(contains, [#{a => b}, [#{a => 1}, #{a => b}]])),
  784. ?assertEqual(false, apply_func(contains, [#{a => b}, [#{a => 1}]])),
  785. ?assertEqual(false, apply_func(contains, [3, [1, 2]])),
  786. ?assertEqual(false, apply_func(contains, [<<"c">>, [<<>>, <<"ab">>, 3, <<"a">>]])).
  787. t_map_get(_) ->
  788. ?assertEqual(1, apply_func(map_get, [<<"a">>, #{a => 1}])),
  789. ?assertEqual(undefined, apply_func(map_get, [<<"a">>, #{}])),
  790. ?assertEqual(1, apply_func(map_get, [<<"a.b">>, #{a => #{b => 1}}])),
  791. ?assertEqual(undefined, apply_func(map_get, [<<"a.c">>, #{a => #{b => 1}}])),
  792. ?assertEqual(undefined, apply_func(map_get, [<<"a">>, #{}])).
  793. t_map_put(_) ->
  794. ?assertEqual(#{<<"a">> => 1}, apply_func(map_put, [<<"a">>, 1, #{}])),
  795. ?assertEqual(#{a => 2}, apply_func(map_put, [<<"a">>, 2, #{a => 1}])),
  796. ?assertEqual(#{<<"a">> => #{<<"b">> => 1}}, apply_func(map_put, [<<"a.b">>, 1, #{}])),
  797. ?assertEqual(
  798. #{a => #{b => 1, <<"c">> => 1}}, apply_func(map_put, [<<"a.c">>, 1, #{a => #{b => 1}}])
  799. ),
  800. ?assertEqual(#{a => 2}, apply_func(map_put, [<<"a">>, 2, #{a => 1}])).
  801. t_mget(_) ->
  802. ?assertEqual(1, apply_func(mget, [<<"a">>, #{a => 1}])),
  803. ?assertEqual(1, apply_func(mget, [<<"a">>, <<"{\"a\" : 1}">>])),
  804. ?assertEqual(1, apply_func(mget, [<<"a">>, #{<<"a">> => 1}])),
  805. ?assertEqual(1, apply_func(mget, [<<"a.b">>, #{<<"a.b">> => 1}])),
  806. ?assertEqual(undefined, apply_func(mget, [<<"a">>, #{}])).
  807. t_mput(_) ->
  808. ?assertEqual(#{<<"a">> => 1}, apply_func(mput, [<<"a">>, 1, #{}])),
  809. ?assertEqual(#{<<"a">> => 2}, apply_func(mput, [<<"a">>, 2, #{<<"a">> => 1}])),
  810. ?assertEqual(#{<<"a">> => 2}, apply_func(mput, [<<"a">>, 2, <<"{\"a\" : 1}">>])),
  811. ?assertEqual(#{<<"a.b">> => 2}, apply_func(mput, [<<"a.b">>, 2, #{<<"a.b">> => 1}])),
  812. ?assertEqual(#{a => 2}, apply_func(mput, [<<"a">>, 2, #{a => 1}])).
  813. t_map_to_entries(_) ->
  814. ?assertEqual([], apply_func(map_to_entries, [#{}])),
  815. M = #{a => 1, b => <<"b">>},
  816. J = <<"{\"a\":1,\"b\":\"b\"}">>,
  817. ?assertEqual(
  818. [
  819. #{key => a, value => 1},
  820. #{key => b, value => <<"b">>}
  821. ],
  822. apply_func(map_to_entries, [M])
  823. ),
  824. ?assertEqual(
  825. [
  826. #{key => <<"a">>, value => 1},
  827. #{key => <<"b">>, value => <<"b">>}
  828. ],
  829. apply_func(map_to_entries, [J])
  830. ).
  831. t_bitsize(_) ->
  832. ?assertEqual(8, apply_func(bitsize, [<<"a">>])),
  833. ?assertEqual(4, apply_func(bitsize, [<<15:4>>])).
  834. t_bytesize(_) ->
  835. ?assertEqual(1, apply_func(bytesize, [<<"a">>])),
  836. ?assertEqual(0, apply_func(bytesize, [<<>>])).
  837. t_subbits(_) ->
  838. ?assertEqual(1, apply_func(subbits, [<<255:8>>, 1])),
  839. ?assertEqual(3, apply_func(subbits, [<<255:8>>, 2])),
  840. ?assertEqual(7, apply_func(subbits, [<<255:8>>, 3])),
  841. ?assertEqual(15, apply_func(subbits, [<<255:8>>, 4])),
  842. ?assertEqual(31, apply_func(subbits, [<<255:8>>, 5])),
  843. ?assertEqual(63, apply_func(subbits, [<<255:8>>, 6])),
  844. ?assertEqual(127, apply_func(subbits, [<<255:8>>, 7])),
  845. ?assertEqual(255, apply_func(subbits, [<<255:8>>, 8])).
  846. t_subbits2(_) ->
  847. ?assertEqual(1, apply_func(subbits, [<<255:8>>, 1, 1])),
  848. ?assertEqual(3, apply_func(subbits, [<<255:8>>, 1, 2])),
  849. ?assertEqual(7, apply_func(subbits, [<<255:8>>, 1, 3])),
  850. ?assertEqual(15, apply_func(subbits, [<<255:8>>, 1, 4])),
  851. ?assertEqual(31, apply_func(subbits, [<<255:8>>, 1, 5])),
  852. ?assertEqual(63, apply_func(subbits, [<<255:8>>, 1, 6])),
  853. ?assertEqual(127, apply_func(subbits, [<<255:8>>, 1, 7])),
  854. ?assertEqual(255, apply_func(subbits, [<<255:8>>, 1, 8])).
  855. t_subbits2_1(_) ->
  856. ?assertEqual(1, apply_func(subbits, [<<255:8>>, 2, 1])),
  857. ?assertEqual(3, apply_func(subbits, [<<255:8>>, 2, 2])),
  858. ?assertEqual(7, apply_func(subbits, [<<255:8>>, 2, 3])),
  859. ?assertEqual(15, apply_func(subbits, [<<255:8>>, 2, 4])),
  860. ?assertEqual(31, apply_func(subbits, [<<255:8>>, 2, 5])),
  861. ?assertEqual(63, apply_func(subbits, [<<255:8>>, 2, 6])),
  862. ?assertEqual(127, apply_func(subbits, [<<255:8>>, 2, 7])),
  863. ?assertEqual(127, apply_func(subbits, [<<255:8>>, 2, 8])).
  864. t_subbits2_integer(_) ->
  865. ?assertEqual(
  866. 456,
  867. apply_func(subbits, [<<456:32/integer>>, 1, 32, <<"integer">>, <<"signed">>, <<"big">>])
  868. ),
  869. ?assertEqual(
  870. -456,
  871. apply_func(subbits, [<<-456:32/integer>>, 1, 32, <<"integer">>, <<"signed">>, <<"big">>])
  872. ).
  873. t_subbits2_float(_) ->
  874. R = apply_func(subbits, [<<5.3:64/float>>, 1, 64, <<"float">>, <<"unsigned">>, <<"big">>]),
  875. RL = (5.3 - R),
  876. ct:pal(";;;;~p", [R]),
  877. ?assert((RL >= 0 andalso RL < 0.0001) orelse (RL =< 0 andalso RL > -0.0001)),
  878. R2 = apply_func(subbits, [<<-5.3:64/float>>, 1, 64, <<"float">>, <<"signed">>, <<"big">>]),
  879. RL2 = (5.3 + R2),
  880. ct:pal(";;;;~p", [R2]),
  881. ?assert((RL2 >= 0 andalso RL2 < 0.0001) orelse (RL2 =< 0 andalso RL2 > -0.0001)).
  882. t_subbits_4_args(_) ->
  883. R = apply_func(subbits, [<<5.3:64/float>>, 1, 64, <<"float">>]),
  884. RL = (5.3 - R),
  885. ?assert((RL >= 0 andalso RL < 0.0001) orelse (RL =< 0 andalso RL > -0.0001)).
  886. t_subbits_5_args(_) ->
  887. ?assertEqual(
  888. 456,
  889. apply_func(subbits, [<<456:32/integer>>, 1, 32, <<"integer">>, <<"unsigned">>])
  890. ).
  891. t_subbits_not_even_bytes(_) ->
  892. InputBin = apply_func(hexstr2bin, [<<"9F4E58">>]),
  893. SubbitsRes = apply_func(subbits, [InputBin, 1, 6, <<"bits">>, <<"unsigned">>, <<"big">>]),
  894. ?assertEqual(<<"27">>, apply_func(bin2hexstr, [SubbitsRes])).
  895. %%------------------------------------------------------------------------------
  896. %% Test cases for Hash funcs
  897. %%------------------------------------------------------------------------------
  898. t_hash_funcs(_) ->
  899. ?PROPTEST(prop_hash_fun).
  900. prop_hash_fun() ->
  901. ?FORALL(
  902. S,
  903. binary(),
  904. begin
  905. (32 == byte_size(apply_func(md5, [S]))) andalso
  906. (40 == byte_size(apply_func(sha, [S]))) andalso
  907. (64 == byte_size(apply_func(sha256, [S])))
  908. end
  909. ).
  910. %%------------------------------------------------------------------------------
  911. %% Test cases for zip funcs
  912. %%------------------------------------------------------------------------------
  913. t_zip_funcs(_) ->
  914. ?PROPTEST(prop_zip_fun).
  915. prop_zip_fun() ->
  916. ?FORALL(
  917. S,
  918. binary(),
  919. S == apply_func(unzip, [apply_func(zip, [S])])
  920. ).
  921. %%------------------------------------------------------------------------------
  922. %% Test cases for gzip funcs
  923. %%------------------------------------------------------------------------------
  924. t_gzip_funcs(_) ->
  925. ?PROPTEST(prop_gzip_fun).
  926. prop_gzip_fun() ->
  927. ?FORALL(
  928. S,
  929. binary(),
  930. S == apply_func(gunzip, [apply_func(gzip, [S])])
  931. ).
  932. %%------------------------------------------------------------------------------
  933. %% Test cases for zip funcs
  934. %%------------------------------------------------------------------------------
  935. t_zip_compress_funcs(_) ->
  936. ?PROPTEST(prop_zip_compress_fun).
  937. prop_zip_compress_fun() ->
  938. ?FORALL(
  939. S,
  940. binary(),
  941. S == apply_func(zip_uncompress, [apply_func(zip_compress, [S])])
  942. ).
  943. %%------------------------------------------------------------------------------
  944. %% Test cases for base64
  945. %%------------------------------------------------------------------------------
  946. t_base64_encode(_) ->
  947. ?PROPTEST(prop_base64_encode).
  948. prop_base64_encode() ->
  949. ?FORALL(
  950. S,
  951. list(range(0, 255)),
  952. begin
  953. Bin = iolist_to_binary(S),
  954. Bin == base64:decode(apply_func(base64_encode, [Bin]))
  955. end
  956. ).
  957. %%--------------------------------------------------------------------
  958. %% Date functions
  959. %%--------------------------------------------------------------------
  960. t_now_rfc3339(_) ->
  961. ?assert(
  962. is_integer(
  963. calendar:rfc3339_to_system_time(
  964. binary_to_list(apply_func(now_rfc3339, []))
  965. )
  966. )
  967. ).
  968. t_now_rfc3339_1(_) ->
  969. [
  970. ?assert(
  971. is_integer(
  972. calendar:rfc3339_to_system_time(
  973. binary_to_list(apply_func(now_rfc3339, [atom_to_binary(Unit, utf8)])),
  974. [{unit, Unit}]
  975. )
  976. )
  977. )
  978. || Unit <- [second, millisecond, microsecond, nanosecond]
  979. ].
  980. t_now_timestamp(_) ->
  981. ?assert(is_integer(apply_func(now_timestamp, []))).
  982. t_now_timestamp_1(_) ->
  983. [
  984. ?assert(
  985. is_integer(
  986. apply_func(now_timestamp, [atom_to_binary(Unit, utf8)])
  987. )
  988. )
  989. || Unit <- [second, millisecond, microsecond, nanosecond]
  990. ].
  991. t_unix_ts_to_rfc3339(_) ->
  992. [
  993. begin
  994. BUnit = atom_to_binary(Unit, utf8),
  995. Epoch = apply_func(now_timestamp, [BUnit]),
  996. DateTime = apply_func(unix_ts_to_rfc3339, [Epoch, BUnit]),
  997. ?assertEqual(
  998. Epoch,
  999. calendar:rfc3339_to_system_time(binary_to_list(DateTime), [{unit, Unit}])
  1000. )
  1001. end
  1002. || Unit <- [second, millisecond, microsecond, nanosecond]
  1003. ].
  1004. t_rfc3339_to_unix_ts(_) ->
  1005. [
  1006. begin
  1007. BUnit = atom_to_binary(Unit, utf8),
  1008. Epoch = apply_func(now_timestamp, [BUnit]),
  1009. DateTime = apply_func(unix_ts_to_rfc3339, [Epoch, BUnit]),
  1010. ?assertEqual(Epoch, emqx_rule_funcs:rfc3339_to_unix_ts(DateTime, BUnit))
  1011. end
  1012. || Unit <- [second, millisecond, microsecond, nanosecond]
  1013. ].
  1014. t_format_date_funcs(_) ->
  1015. ?PROPTEST(prop_format_date_fun).
  1016. prop_format_date_fun() ->
  1017. Args1 = [<<"second">>, <<"+07:00">>, <<"%m--%d--%Y---%H:%M:%S%z">>],
  1018. ?FORALL(
  1019. S,
  1020. erlang:system_time(second),
  1021. S ==
  1022. apply_func(
  1023. date_to_unix_ts,
  1024. Args1 ++
  1025. [
  1026. apply_func(
  1027. format_date,
  1028. Args1 ++ [S]
  1029. )
  1030. ]
  1031. )
  1032. ),
  1033. Args2 = [<<"millisecond">>, <<"+04:00">>, <<"--%m--%d--%Y---%H:%M:%S:%3N%z">>],
  1034. Args2DTUS = [<<"millisecond">>, <<"--%m--%d--%Y---%H:%M:%S:%3N%z">>],
  1035. ?FORALL(
  1036. S,
  1037. erlang:system_time(millisecond),
  1038. S ==
  1039. apply_func(
  1040. date_to_unix_ts,
  1041. Args2DTUS ++
  1042. [
  1043. apply_func(
  1044. format_date,
  1045. Args2 ++ [S]
  1046. )
  1047. ]
  1048. )
  1049. ),
  1050. Args = [<<"second">>, <<"+08:00">>, <<"%Y-%m-%d-%H:%M:%S%z">>],
  1051. ArgsDTUS = [<<"second">>, <<"%Y-%m-%d-%H:%M:%S%z">>],
  1052. ?FORALL(
  1053. S,
  1054. erlang:system_time(second),
  1055. S ==
  1056. apply_func(
  1057. date_to_unix_ts,
  1058. ArgsDTUS ++
  1059. [
  1060. apply_func(
  1061. format_date,
  1062. Args ++ [S]
  1063. )
  1064. ]
  1065. )
  1066. ),
  1067. % no offset in format string. force add offset
  1068. Second = erlang:system_time(second),
  1069. Args3 = [<<"second">>, <<"+04:00">>, <<"--%m--%d--%Y---%H:%M:%S">>, Second],
  1070. Formatters3 = apply_func(format_date, Args3),
  1071. Args3DTUS = [<<"second">>, <<"+04:00">>, <<"--%m--%d--%Y---%H:%M:%S">>, Formatters3],
  1072. Second == apply_func(date_to_unix_ts, Args3DTUS).
  1073. t_timezone_to_offset_seconds(_) ->
  1074. timezone_to_offset_seconds_helper(timezone_to_offset_seconds),
  1075. %% The timezone_to_second function is kept for compatibility with 4.X.
  1076. timezone_to_offset_seconds_helper(timezone_to_second).
  1077. timezone_to_offset_seconds_helper(FunctionName) ->
  1078. ?assertEqual(120 * 60, apply_func(FunctionName, [<<"+02:00:00">>])),
  1079. ?assertEqual(-120 * 60, apply_func(FunctionName, [<<"-02:00:00">>])),
  1080. ?assertEqual(102, apply_func(FunctionName, [<<"+00:01:42">>])),
  1081. ?assertEqual(0, apply_func(FunctionName, [<<"z">>])),
  1082. ?assertEqual(0, apply_func(FunctionName, [<<"Z">>])),
  1083. ?assertEqual(42, apply_func(FunctionName, [42])),
  1084. ?assertEqual(0, apply_func(FunctionName, [undefined])),
  1085. %% Check that the following does not crash
  1086. apply_func(FunctionName, [<<"local">>]),
  1087. apply_func(FunctionName, ["local"]),
  1088. apply_func(FunctionName, [local]),
  1089. ok.
  1090. t_date_to_unix_ts(_) ->
  1091. TestTab = [
  1092. {{"2024-03-01T10:30:38+08:00", second}, [
  1093. <<"second">>, <<"+08:00">>, <<"%Y-%m-%d %H-%M-%S">>, <<"2024-03-01 10:30:38">>
  1094. ]},
  1095. {{"2024-03-01T10:30:38.333+08:00", second}, [
  1096. <<"second">>, <<"+08:00">>, <<"%Y-%m-%d %H-%M-%S.%3N">>, <<"2024-03-01 10:30:38.333">>
  1097. ]},
  1098. {{"2024-03-01T10:30:38.333+08:00", millisecond}, [
  1099. <<"millisecond">>,
  1100. <<"+08:00">>,
  1101. <<"%Y-%m-%d %H-%M-%S.%3N">>,
  1102. <<"2024-03-01 10:30:38.333">>
  1103. ]},
  1104. {{"2024-03-01T10:30:38.333+08:00", microsecond}, [
  1105. <<"microsecond">>,
  1106. <<"+08:00">>,
  1107. <<"%Y-%m-%d %H-%M-%S.%3N">>,
  1108. <<"2024-03-01 10:30:38.333">>
  1109. ]},
  1110. {{"2024-03-01T10:30:38.333+08:00", nanosecond}, [
  1111. <<"nanosecond">>,
  1112. <<"+08:00">>,
  1113. <<"%Y-%m-%d %H-%M-%S.%3N">>,
  1114. <<"2024-03-01 10:30:38.333">>
  1115. ]},
  1116. {{"2024-03-01T10:30:38.333444+08:00", microsecond}, [
  1117. <<"microsecond">>,
  1118. <<"+08:00">>,
  1119. <<"%Y-%m-%d %H-%M-%S.%6N">>,
  1120. <<"2024-03-01 10:30:38.333444">>
  1121. ]}
  1122. ],
  1123. lists:foreach(
  1124. fun({{DateTime3339, Unit}, DateToTsArgs}) ->
  1125. ?assertEqual(
  1126. calendar:rfc3339_to_system_time(DateTime3339, [{unit, Unit}]),
  1127. apply_func(date_to_unix_ts, DateToTsArgs),
  1128. "Failed on test: " ++ DateTime3339 ++ "/" ++ atom_to_list(Unit)
  1129. )
  1130. end,
  1131. TestTab
  1132. ).
  1133. t_parse_date_errors(_) ->
  1134. ?assertError(
  1135. bad_formatter_or_date,
  1136. emqx_rule_funcs:date_to_unix_ts(
  1137. second, <<"%Y-%m-%d %H:%M:%S">>, <<"2022-059999-26 10:40:12">>
  1138. )
  1139. ),
  1140. ?assertError(
  1141. bad_formatter_or_date,
  1142. emqx_rule_funcs:date_to_unix_ts(second, <<"%y-%m-%d %H:%M:%S">>, <<"2022-05-26 10:40:12">>)
  1143. ),
  1144. %% invalid formats
  1145. ?assertThrow(
  1146. {missing_date_part, month},
  1147. emqx_rule_funcs:date_to_unix_ts(
  1148. second, <<"%Y-%d %H:%M:%S">>, <<"2022-32 10:40:12">>
  1149. )
  1150. ),
  1151. ?assertThrow(
  1152. {missing_date_part, year},
  1153. emqx_rule_funcs:date_to_unix_ts(
  1154. second, <<"%H:%M:%S">>, <<"10:40:12">>
  1155. )
  1156. ),
  1157. ?assertError(
  1158. _,
  1159. emqx_rule_funcs:date_to_unix_ts(
  1160. second, <<"%Y-%m-%d %H:%M:%S">>, <<"2022-05-32 10:40:12">>
  1161. )
  1162. ),
  1163. ?assertError(
  1164. _,
  1165. emqx_rule_funcs:date_to_unix_ts(
  1166. second, <<"%Y-%m-%d %H:%M:%S">>, <<"2023-02-29 10:40:12">>
  1167. )
  1168. ),
  1169. ?assertError(
  1170. _,
  1171. emqx_rule_funcs:date_to_unix_ts(
  1172. second, <<"%Y-%m-%d %H:%M:%S">>, <<"2024-02-30 10:40:12">>
  1173. )
  1174. ),
  1175. %% Compatibility test
  1176. %% UTC+0
  1177. UnixTs = 1653561612,
  1178. ?assertEqual(
  1179. UnixTs,
  1180. emqx_rule_funcs:date_to_unix_ts(second, <<"%Y-%m-%d %H:%M:%S">>, <<"2022-05-26 10:40:12">>)
  1181. ),
  1182. ?assertEqual(
  1183. UnixTs,
  1184. emqx_rule_funcs:date_to_unix_ts(second, <<"%Y-%m-%d %H-%M-%S">>, <<"2022-05-26 10:40:12">>)
  1185. ),
  1186. ?assertEqual(
  1187. UnixTs,
  1188. emqx_rule_funcs:date_to_unix_ts(second, <<"%Y-%m-%d %H:%M:%S">>, <<"2022-05-26 10-40-12">>)
  1189. ),
  1190. %% leap year checks
  1191. ?assertEqual(
  1192. %% UTC+0
  1193. 1709217100,
  1194. emqx_rule_funcs:date_to_unix_ts(second, <<"%Y-%m-%d %H:%M:%S">>, <<"2024-02-29 14:31:40">>)
  1195. ),
  1196. ?assertEqual(
  1197. %% UTC+0
  1198. 1709297071,
  1199. emqx_rule_funcs:date_to_unix_ts(second, <<"%Y-%m-%d %H:%M:%S">>, <<"2024-03-01 12:44:31">>)
  1200. ),
  1201. ?assertEqual(
  1202. %% UTC+0
  1203. 4107588271,
  1204. emqx_rule_funcs:date_to_unix_ts(second, <<"%Y-%m-%d %H:%M:%S">>, <<"2100-03-01 12:44:31">>)
  1205. ),
  1206. ?assertEqual(
  1207. %% UTC+8
  1208. 1709188300,
  1209. emqx_rule_funcs:date_to_unix_ts(
  1210. second, <<"+08:00">>, <<"%Y-%m-%d %H:%M:%S">>, <<"2024-02-29 14:31:40">>
  1211. )
  1212. ),
  1213. ?assertEqual(
  1214. %% UTC+8
  1215. 1709268271,
  1216. emqx_rule_funcs:date_to_unix_ts(
  1217. second, <<"+08:00">>, <<"%Y-%m-%d %H:%M:%S">>, <<"2024-03-01 12:44:31">>
  1218. )
  1219. ),
  1220. ?assertEqual(
  1221. %% UTC+8
  1222. 4107559471,
  1223. emqx_rule_funcs:date_to_unix_ts(
  1224. second, <<"+08:00">>, <<"%Y-%m-%d %H:%M:%S">>, <<"2100-03-01 12:44:31">>
  1225. )
  1226. ),
  1227. %% None zero zone shift with millisecond level precision
  1228. Tz1 = calendar:rfc3339_to_system_time("2024-02-23T15:00:00.123+08:00", [{unit, second}]),
  1229. ?assertEqual(
  1230. Tz1,
  1231. emqx_rule_funcs:date_to_unix_ts(
  1232. second, <<"%Y-%m-%d %H:%M:%S.%3N%:z">>, <<"2024-02-23 15:00:00.123+08:00">>
  1233. )
  1234. ),
  1235. ok.
  1236. %%------------------------------------------------------------------------------
  1237. %% Utility functions
  1238. %%------------------------------------------------------------------------------
  1239. apply_func(Name, Args) when is_atom(Name) ->
  1240. erlang:apply(emqx_rule_funcs, Name, Args);
  1241. apply_func(Fun, Args) when is_function(Fun) ->
  1242. erlang:apply(Fun, Args).
  1243. apply_func(Name, Args, Input) when is_map(Input) ->
  1244. apply_func(apply_func(Name, Args), [Input]);
  1245. apply_func(Name, Args, Msg) ->
  1246. apply_func(Name, Args, emqx_message:to_map(Msg)).
  1247. message() ->
  1248. emqx_message:set_flags(
  1249. #{dup => false},
  1250. emqx_message:make(<<"clientid">>, 1, <<"topic/#">>, <<"payload">>)
  1251. ).
  1252. % t_contains_topic(_) ->
  1253. % error('TODO').
  1254. % t_contains_topic_match(_) ->
  1255. % error('TODO').
  1256. % t_div(_) ->
  1257. % error('TODO').
  1258. % t_mod(_) ->
  1259. % error('TODO').
  1260. % t_abs(_) ->
  1261. % error('TODO').
  1262. % t_acos(_) ->
  1263. % error('TODO').
  1264. % t_acosh(_) ->
  1265. % error('TODO').
  1266. % t_asin(_) ->
  1267. % error('TODO').
  1268. % t_asinh(_) ->
  1269. % error('TODO').
  1270. % t_atan(_) ->
  1271. % error('TODO').
  1272. % t_atanh(_) ->
  1273. % error('TODO').
  1274. % t_ceil(_) ->
  1275. % error('TODO').
  1276. % t_cos(_) ->
  1277. % error('TODO').
  1278. % t_cosh(_) ->
  1279. % error('TODO').
  1280. % t_exp(_) ->
  1281. % error('TODO').
  1282. % t_floor(_) ->
  1283. % error('TODO').
  1284. % t_fmod(_) ->
  1285. % error('TODO').
  1286. % t_log(_) ->
  1287. % error('TODO').
  1288. % t_log10(_) ->
  1289. % error('TODO').
  1290. % t_log2(_) ->
  1291. % error('TODO').
  1292. % t_power(_) ->
  1293. % error('TODO').
  1294. % t_round(_) ->
  1295. % error('TODO').
  1296. % t_sin(_) ->
  1297. % error('TODO').
  1298. % t_sinh(_) ->
  1299. % error('TODO').
  1300. % t_sqrt(_) ->
  1301. % error('TODO').
  1302. % t_tan(_) ->
  1303. % error('TODO').
  1304. % t_tanh(_) ->
  1305. % error('TODO').
  1306. % t_bitnot(_) ->
  1307. % error('TODO').
  1308. % t_bitand(_) ->
  1309. % error('TODO').
  1310. % t_bitor(_) ->
  1311. % error('TODO').
  1312. % t_bitxor(_) ->
  1313. % error('TODO').
  1314. % t_bitsl(_) ->
  1315. % error('TODO').
  1316. % t_bitsr(_) ->
  1317. % error('TODO').
  1318. % t_lower(_) ->
  1319. % error('TODO').
  1320. % t_ltrim(_) ->
  1321. % error('TODO').
  1322. % t_rtrim(_) ->
  1323. % error('TODO').
  1324. % t_upper(_) ->
  1325. % error('TODO').
  1326. % t_split(_) ->
  1327. % error('TODO').
  1328. % t_md5(_) ->
  1329. % error('TODO').
  1330. % t_sha(_) ->
  1331. % error('TODO').
  1332. % t_sha256(_) ->
  1333. % error('TODO').
  1334. % t_json_encode(_) ->
  1335. % error('TODO').
  1336. % t_json_decode(_) ->
  1337. % error('TODO').
  1338. %%------------------------------------------------------------------------------
  1339. %% CT functions
  1340. %%------------------------------------------------------------------------------
  1341. all() ->
  1342. IsTestCase = fun
  1343. ("t_" ++ _) -> true;
  1344. (_) -> false
  1345. end,
  1346. [F || {F, _A} <- module_info(exports), IsTestCase(atom_to_list(F))].
  1347. suite() ->
  1348. [{ct_hooks, [cth_surefire]}, {timetrap, {seconds, 30}}].