emqx/apps/emqx_rule_engine/test/emqx_rule_maps_SUITE.erl

176 lines
9.7 KiB
Erlang

%%--------------------------------------------------------------------
%% Copyright (c) 2020-2021 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(emqx_rule_maps_SUITE).
-include_lib("eunit/include/eunit.hrl").
-include_lib("common_test/include/ct.hrl").
-compile(export_all).
-compile(nowarn_export_all).
-import(emqx_rule_maps,
[ nested_get/2
, nested_get/3
, nested_put/3
, atom_key_map/1
]).
-define(path(Path), {path,
[case K of
{ic, Key} -> {index, {const, Key}};
{iv, Key} -> {index, {var, Key}};
{i, Path1} -> {index, Path1};
_ -> {key, K}
end || K <- Path]}).
-define(PROPTEST(Prop), true = proper:quickcheck(Prop)).
t_nested_put_map(_) ->
?assertEqual(#{a => 1}, nested_put(?path([a]), 1, #{})),
?assertEqual(#{a => a}, nested_put(?path([a]), a, #{})),
?assertEqual(#{a => 1}, nested_put(?path([a]), 1, not_map)),
?assertEqual(#{a => #{b => b}}, nested_put(?path([a,b]), b, #{})),
?assertEqual(#{a => #{b => #{c => c}}}, nested_put(?path([a,b,c]), c, #{})),
?assertEqual(#{<<"k">> => v1}, nested_put(?path([k]), v1, #{<<"k">> => v0})),
?assertEqual(#{k => v1}, nested_put(?path([k]), v1, #{k => v0})),
?assertEqual(#{<<"k">> => v1, a => b}, nested_put(?path([k]), v1, #{<<"k">> => v0, a => b})),
?assertEqual(#{<<"k">> => v1}, nested_put(?path([k]), v1, #{<<"k">> => v0})),
?assertEqual(#{k => v1}, nested_put(?path([k]), v1, #{k => v0})),
?assertEqual(#{k => v1, a => b}, nested_put(?path([k]), v1, #{k => v0, a => b})),
?assertEqual(#{<<"k">> => v1, a => b}, nested_put(?path([k]), v1, #{<<"k">> => v0, a => b})),
?assertEqual(#{<<"k">> => #{<<"t">> => v1}}, nested_put(?path([k,t]), v1, #{<<"k">> => #{<<"t">> => v0}})),
?assertEqual(#{<<"k">> => #{t => v1}}, nested_put(?path([k,t]), v1, #{<<"k">> => #{t => v0}})),
?assertEqual(#{k => #{<<"t">> => #{a => v1}}}, nested_put(?path([k,t,a]), v1, #{k => #{<<"t">> => v0}})),
?assertEqual(#{k => #{<<"t">> => #{<<"a">> => v1}}}, nested_put(?path([k,t,<<"a">>]), v1, #{k => #{<<"t">> => v0}})).
t_nested_put_index(_) ->
?assertEqual([1,a,3], nested_put(?path([{ic,2}]), a, [1,2,3])),
?assertEqual([1,2,3], nested_put(?path([{ic,0}]), a, [1,2,3])),
?assertEqual([1,2,3], nested_put(?path([{ic,4}]), a, [1,2,3])),
?assertEqual([1,[a],3], nested_put(?path([{ic,2}, {ic,1}]), a, [1,[2],3])),
?assertEqual([1,[[a]],3], nested_put(?path([{ic,2}, {ic,1}, {ic,1}]), a, [1,[[2]],3])),
?assertEqual([1,[[2]],3], nested_put(?path([{ic,2}, {ic,1}, {ic,2}]), a, [1,[[2]],3])),
?assertEqual([1,[a],1], nested_put(?path([{ic,2}, {i,?path([{ic,3}])}]), a, [1,[2],1])),
%% nested_put to the first or tail of a list:
?assertEqual([a], nested_put(?path([{ic,head}]), a, not_list)),
?assertEqual([a], nested_put(?path([{ic,head}]), a, [])),
?assertEqual([a,1,2,3], nested_put(?path([{ic,head}]), a, [1,2,3])),
?assertEqual([a], nested_put(?path([{ic,tail}]), a, not_list)),
?assertEqual([a], nested_put(?path([{ic,tail}]), a, [])),
?assertEqual([1,2,3,a], nested_put(?path([{ic,tail}]), a, [1,2,3])).
t_nested_put_negative_index(_) ->
?assertEqual([1,2,a], nested_put(?path([{ic,-1}]), a, [1,2,3])),
?assertEqual([1,a,3], nested_put(?path([{ic,-2}]), a, [1,2,3])),
?assertEqual([a,2,3], nested_put(?path([{ic,-3}]), a, [1,2,3])),
?assertEqual([1,2,3], nested_put(?path([{ic,-4}]), a, [1,2,3])).
t_nested_put_mix_map_index(_) ->
?assertEqual(#{a => [a]}, nested_put(?path([a, {ic,2}]), a, #{})),
?assertEqual(#{a => [#{b => 0}]}, nested_put(?path([a, {ic,2}, b]), 0, #{})),
?assertEqual(#{a => [1,a,3]}, nested_put(?path([a, {ic,2}]), a, #{a => [1,2,3]})),
?assertEqual([1,#{a => c},3], nested_put(?path([{ic,2}, a]), c, [1,#{a => b},3])),
?assertEqual([1,#{a => [c]},3], nested_put(?path([{ic,2}, a, {ic, 1}]), c, [1,#{a => [b]},3])),
?assertEqual(#{a => [1,a,3], b => 2}, nested_put(?path([a, {iv,b}]), a, #{a => [1,2,3], b => 2})),
?assertEqual(#{a => [1,2,3], b => 2}, nested_put(?path([a, {iv,c}]), a, #{a => [1,2,3], b => 2})),
?assertEqual(#{a => [#{c => a},1,2,3]}, nested_put(?path([a, {ic,head}, c]), a, #{a => [1,2,3]})).
t_nested_get_map(_) ->
?assertEqual(undefined, nested_get(?path([a]), not_map)),
?assertEqual(#{a => 1}, nested_get(?path([]), #{a => 1})),
?assertEqual(#{b => c}, nested_get(?path([a]), #{a => #{b => c}})),
?assertEqual(undefined, nested_get(?path([a,b,c]), not_map)),
?assertEqual(undefined, nested_get(?path([a,b,c]), #{})),
?assertEqual(undefined, nested_get(?path([a,b,c]), #{a => #{}})),
?assertEqual(undefined, nested_get(?path([a,b,c]), #{a => #{b => #{}}})),
?assertEqual(v1, nested_get(?path([p,x]), #{p => #{x => v1}})),
?assertEqual(v1, nested_get(?path([<<"p">>,<<"x">>]), #{p => #{x => v1}})),
?assertEqual(c, nested_get(?path([a,b,c]), #{a => #{b => #{c => c}}})).
t_nested_get_map_1(_) ->
?assertEqual(1, nested_get(?path([a]), <<"{\"a\": 1}">>)),
?assertEqual(<<"{\"b\": 1}">>, nested_get(?path([a]), #{a => <<"{\"b\": 1}">>})),
?assertEqual(1, nested_get(?path([a,b]), #{a => <<"{\"b\": 1}">>})).
t_nested_get_index(_) ->
%% single index get
?assertEqual(1, nested_get(?path([{ic,1}]), [1,2,3])),
?assertEqual(2, nested_get(?path([{ic,2}]), [1,2,3])),
?assertEqual(3, nested_get(?path([{ic,3}]), [1,2,3])),
?assertEqual(undefined, nested_get(?path([{ic,0}]), [1,2,3])),
?assertEqual("not_found", nested_get(?path([{ic,0}]), [1,2,3], "not_found")),
?assertEqual(undefined, nested_get(?path([{ic,4}]), [1,2,3])),
?assertEqual("not_found", nested_get(?path([{ic,4}]), [1,2,3], "not_found")),
%% multiple index get
?assertEqual(c, nested_get(?path([{ic,2}, {ic,3}]), [1,[a,b,c],3])),
?assertEqual("I", nested_get(?path([{ic,2}, {ic,3}, {ic,1}]), [1,[a,b,["I","II","III"]],3])),
?assertEqual(undefined, nested_get(?path([{ic,2}, {ic,1}, {ic,1}]), [1,[a,b,["I","II","III"]],3])),
?assertEqual(default, nested_get(?path([{ic,2}, {ic,1}, {ic,1}]), [1,[a,b,["I","II","III"]],3], default)).
t_nested_get_negative_index(_) ->
?assertEqual(3, nested_get(?path([{ic,-1}]), [1,2,3])),
?assertEqual(2, nested_get(?path([{ic,-2}]), [1,2,3])),
?assertEqual(1, nested_get(?path([{ic,-3}]), [1,2,3])),
?assertEqual(undefined, nested_get(?path([{ic,-4}]), [1,2,3])).
t_nested_get_mix_map_index(_) ->
%% index const
?assertEqual(1, nested_get(?path([a, {ic,1}]), #{a => [1,2,3]})),
?assertEqual(2, nested_get(?path([{ic,2}, a]), [1,#{a => 2},3])),
?assertEqual(undefined, nested_get(?path([a, {ic,0}]), #{a => [1,2,3]})),
?assertEqual("not_found", nested_get(?path([a, {ic,0}]), #{a => [1,2,3]}, "not_found")),
?assertEqual("not_found", nested_get(?path([b, {ic,1}]), #{a => [1,2,3]}, "not_found")),
?assertEqual(undefined, nested_get(?path([{ic,4}, a]), [1,2,3,4])),
?assertEqual("not_found", nested_get(?path([{ic,4}, a]), [1,2,3,4], "not_found")),
?assertEqual(c, nested_get(?path([a, {ic,2}, {ic,3}]), #{a => [1,[a,b,c],3]})),
?assertEqual("I", nested_get(?path([{ic,2}, c, {ic,1}]), [1,#{a => a, b => b, c => ["I","II","III"]},3])),
?assertEqual("I", nested_get(?path([{ic,2}, c, d]), [1,#{a => a, b => b, c => #{d => "I"}},3])),
?assertEqual(undefined, nested_get(?path([{ic,2}, c, e]), [1,#{a => a, b => b, c => #{d => "I"}},3])),
?assertEqual(default, nested_get(?path([{ic,2}, c, e]), [1,#{a => a, b => b, c => #{d => "I"}},3], default)),
%% index var
?assertEqual(1, nested_get(?path([a, {iv,<<"b">>}]), #{a => [1,2,3], b => 1})),
?assertEqual(1, nested_get(?path([a, {iv,b}]), #{a => [1,2,3], b => 1})),
?assertEqual(undefined, nested_get(?path([a, {iv,c}]), #{a => [1,2,3], b => 1})),
?assertEqual(undefined, nested_get(?path([a, {iv,b}]), #{a => [1,2,3], b => 4})),
?assertEqual("I", nested_get(?path([{i,?path([{ic, 3}])}, c, d]),
[1,#{a => a, b => b, c => #{d => "I"}},2], default)),
?assertEqual(3, nested_get(?path([a, {i,?path([b,{ic,1},c])}]),
#{a => [1,2,3], b => [#{c => 3}]})),
?assertEqual(3, nested_get(?path([a, {i,?path([b,{ic,1},c])}]),
#{a => [1,2,3], b => [#{c => 3}]}, default)),
?assertEqual(default, nested_get(?path([a, {i,?path([b,{ic,1},c])}]),
#{a => [1,2,3], b => [#{c => 4}]}, default)),
?assertEqual(default, nested_get(?path([a, {i,?path([b,{ic,2},c])}]),
#{a => [1,2,3], b => [#{c => 3}]}, default)).
t_atom_key_map(_) ->
?assertEqual(#{a => 1}, atom_key_map(#{<<"a">> => 1})),
?assertEqual(#{a => 1, b => #{a => 2}},
atom_key_map(#{<<"a">> => 1, <<"b">> => #{<<"a">> => 2}})),
?assertEqual([#{a => 1}, #{b => #{a => 2}}],
atom_key_map([#{<<"a">> => 1}, #{<<"b">> => #{<<"a">> => 2}}])),
?assertEqual(#{a => 1, b => [#{a => 2}, #{c => 2}]},
atom_key_map(#{<<"a">> => 1, <<"b">> => [#{<<"a">> => 2}, #{<<"c">> => 2}]})).
all() ->
IsTestCase = fun("t_" ++ _) -> true; (_) -> false end,
[F || {F, _A} <- module_info(exports), IsTestCase(atom_to_list(F))].
suite() ->
[{ct_hooks, [cth_surefire]}, {timetrap, {seconds, 30}}].