Skip to content

Commit de7428d

Browse files
authored
Merge pull request #267 from emqx/unsafe-atom-key
feat: add unsafe atom conversion to `hocon_tconf:check_plain`
2 parents da68d12 + 6bfb68c commit de7428d

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

src/hocon_maps.erl

+2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ maybe_atom(#{atom_key := true}, Name) when is_binary(Name) ->
9696
_:_ ->
9797
error({non_existing_atom, Name})
9898
end;
99+
maybe_atom(#{atom_key := {true, unsafe}}, Name) when is_binary(Name) ->
100+
binary_to_atom(Name, utf8);
99101
maybe_atom(_Opts, Name) ->
100102
Name.
101103

test/hocon_tconf_tests.erl

+110
Original file line numberDiff line numberDiff line change
@@ -2321,3 +2321,113 @@ convert_map_test() ->
23212321
{ok, Map} = hocon:binary("root = {name1 = foo1}", #{format => map}),
23222322
Res = hocon_tconf:check_plain(Sc, Map),
23232323
?assertEqual(#{<<"root">> => #{<<"name1">> => "foo2"}}, Res).
2324+
2325+
map_atom_keys_test_() ->
2326+
Sc = #{
2327+
roots => [
2328+
{"root", hoconsc:mk(hoconsc:map(name, hoconsc:ref(foo)), #{})}
2329+
],
2330+
fields =>
2331+
#{foo => [{foo, hoconsc:mk(map(), #{})}]}
2332+
},
2333+
Map0 = #{
2334+
<<"root">> =>
2335+
#{
2336+
<<"name1">> =>
2337+
#{
2338+
<<"foo">> =>
2339+
#{
2340+
<<"key1">> => <<"value">>,
2341+
<<"key2">> => 10,
2342+
<<"key3">> =>
2343+
#{
2344+
<<"deep">> => <<"map">>,
2345+
<<"deeper">> => [#{<<"struct">> => true}]
2346+
}
2347+
}
2348+
}
2349+
}
2350+
},
2351+
RandomKey0 = random_key(),
2352+
RandomKey1 = random_key(),
2353+
Map1 = #{
2354+
<<"root">> =>
2355+
#{
2356+
RandomKey0 =>
2357+
#{<<"foo">> => #{}}
2358+
}
2359+
},
2360+
Map2 = #{
2361+
<<"root">> =>
2362+
#{
2363+
RandomKey1 =>
2364+
#{
2365+
<<"foo">> => #{
2366+
<<"key1">> => true,
2367+
<<"key2">> => #{
2368+
<<"deep">> => <<"map">>,
2369+
<<"deeper">> => [#{<<"struct">> => true}]
2370+
}
2371+
}
2372+
}
2373+
}
2374+
},
2375+
%% ensure atoms exist before checking
2376+
_ = [name1],
2377+
[
2378+
?_assertEqual(
2379+
#{
2380+
root =>
2381+
#{
2382+
name1 =>
2383+
#{
2384+
foo => #{
2385+
<<"key1">> => <<"value">>,
2386+
<<"key2">> => 10,
2387+
<<"key3">> => #{
2388+
<<"deep">> => <<"map">>,
2389+
<<"deeper">> => [#{<<"struct">> => true}]
2390+
}
2391+
}
2392+
}
2393+
}
2394+
},
2395+
hocon_tconf:check_plain(Sc, Map0, #{atom_key => true})
2396+
),
2397+
{"nonexistent atom",
2398+
?_assertError(
2399+
#{exception := {non_existing_atom, _}},
2400+
hocon_tconf:check_plain(Sc, Map1, #{atom_key => true})
2401+
)},
2402+
%% this one doesn't need the atom to exist prior to checking
2403+
{"nonexistent atom key + unsafe",
2404+
?_test(begin
2405+
Res = hocon_tconf:check_plain(
2406+
Sc,
2407+
Map2,
2408+
#{atom_key => {true, unsafe}}
2409+
),
2410+
?assertMatch(#{root := #{}}, Res),
2411+
#{root := M} = Res,
2412+
[{K, V}] = maps:to_list(M),
2413+
?assert(is_atom(K)),
2414+
?assertEqual(RandomKey1, atom_to_binary(K, utf8)),
2415+
?assertEqual(
2416+
#{
2417+
foo => #{
2418+
<<"key1">> => true,
2419+
<<"key2">> => #{
2420+
<<"deep">> => <<"map">>,
2421+
<<"deeper">> => [#{<<"struct">> => true}]
2422+
}
2423+
}
2424+
},
2425+
V
2426+
)
2427+
end)}
2428+
].
2429+
2430+
random_key() ->
2431+
Bytes = crypto:strong_rand_bytes(10),
2432+
Key0 = base64:encode(Bytes),
2433+
iolist_to_binary(re:replace(Key0, <<"[^-a-zA-Z0-9_]">>, <<>>, [global])).

0 commit comments

Comments
 (0)