Skip to content

Commit

Permalink
Merge pull request #75 from esl/type_improvements
Browse files Browse the repository at this point in the history
Type improvements
  • Loading branch information
DenysGonchar authored Jan 27, 2025
2 parents f4d0755 + 9123113 commit 2668811
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 28 deletions.
16 changes: 10 additions & 6 deletions c_src/exml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,9 +583,10 @@ static ERL_NIF_TERM parse_next(ErlNifEnv *env, int argc,
}

if (error_msg) {
return enif_make_tuple2(
env, atom_error,
enif_make_string(env, error_msg, ERL_NIF_LATIN1));
ERL_NIF_TERM error_message =
to_subbinary(ctx, (const unsigned char *)error_msg, strlen(error_msg));

return enif_make_tuple2(env, atom_error, error_message);
}

return enif_make_tuple3(
Expand All @@ -608,9 +609,12 @@ static ERL_NIF_TERM parse(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_tuple2(env, atom_ok, element);
}

return enif_make_tuple2(
env, atom_error,
enif_make_string(env, result.error_message.c_str(), ERL_NIF_LATIN1));
ERL_NIF_TERM error_message =
to_subbinary(ctx,
(const unsigned char *)result.error_message.c_str(),
result.error_message.size());

return enif_make_tuple2(env, atom_error, error_message);
}

static ERL_NIF_TERM escape_cdata(ErlNifEnv *env, int argc,
Expand Down
2 changes: 1 addition & 1 deletion include/exml.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

-record(xmlel, {name :: binary(),
attrs = #{} :: exml:attrs(),
children = [] :: [exml:element() | exml:cdata()]}).
children = [] :: [exml:child()]}).

%% Implementation of the exmlAssertEqual/2 macro is a modification of
%% https://github.com/erszcz/rxml/commit/e8483408663f0bc2af7896e786c1cdea2e86e43d#diff-2cb5d18741df32f4ead70c21fdd221d1
Expand Down
11 changes: 4 additions & 7 deletions src/exml.erl
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,12 @@
remove_attr/2,
xml_sort/1]).

-export_type([attr/0,
attrs/0,
-export_type([attrs/0,
cdata/0,
element/0,
child/0,
item/0]).

-type attr() :: {binary(), binary()}.
-type attrs() :: #{binary() => binary()}.
-type cdata() :: #xmlcdata{}.
%% CDATA record. Printing escaping rules defaults to escaping character-wise.
Expand All @@ -45,7 +44,8 @@
%% <li>`cdata': wraps the entire string into a `<![CDATA[]]>' section.</li>
%% </ul>
-type element() :: #xmlel{}.
-type item() :: element() | attr() | cdata() | exml_stream:start() | exml_stream:stop().
-type item() :: element() | cdata() | exml_stream:start() | exml_stream:stop().
-type child() :: element() | cdata().
-type prettify() :: pretty | not_pretty.
%% Printing indentation rule, see `to_iolist/2'.

Expand Down Expand Up @@ -87,7 +87,6 @@ xml_size({Key, Value}) when is_binary(Key) ->
%% https://github.com/erszcz/rxml/commit/e8483408663f0bc2af7896e786c1cdea2e86e43d
-spec xml_sort([item()]) -> [item()];
(element()) -> element();
(attr()) -> attr();
(cdata()) -> cdata();
(exml_stream:start()) -> exml_stream:start();
(exml_stream:stop()) -> exml_stream:stop().
Expand All @@ -101,8 +100,6 @@ xml_sort(#xmlstreamstart{} = StreamStart) ->
StreamStart;
xml_sort(#xmlstreamend{} = StreamEnd) ->
StreamEnd;
xml_sort({Key, Value}) ->
{Key, Value};
xml_sort(Elements) when is_list(Elements) ->
lists:sort([ xml_sort(E) || E <- Elements ]).

Expand Down
4 changes: 2 additions & 2 deletions src/exml_stream.erl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
%% `#xmlstreamend{}' record.
-type parser() :: #parser{}.
%% `#parser{}' record. Keeps track of unparsed buffers.
-type element() :: exml:element() | exml_stream:start() | exml_stream:stop().
-type element() :: exml:element() | start() | stop().
%% One of `t:exml:element/0', `t:start/0', or `t:stop/0'.

-type parser_opt() :: {infinite_stream, boolean()} | {max_element_size, non_neg_integer()}.
Expand Down Expand Up @@ -69,7 +69,7 @@ new_parser(Opts)->
%%
%% If successful, returns parsed elements and a new parser with updated buffers.
-spec parse(parser(), binary()) ->
{ok, parser(), [exml_stream:element()]} | {error, Reason :: any()}.
{ok, parser(), [element()]} | {error, Reason :: binary()}.
parse(Parser, Input) when is_binary(Input) ->
#parser{event_parser = EventParser, buffer = OldBuf} = Parser,
Buffer = OldBuf ++ [Input],
Expand Down
14 changes: 7 additions & 7 deletions test/exml_stream_tests.erl
Original file line number Diff line number Diff line change
Expand Up @@ -188,45 +188,45 @@ stream_max_opening_tag_size_test() ->
?assertMatch({ok, _Parser1, [#xmlstreamstart{},
#xmlel{}]}, exml_stream:parse(Parser0, <<"<stream89><a></a>">>)),
{ok, Parser2} = exml_stream:new_parser([{max_element_size, 9}]),
?assertEqual({error, "element too big"}, exml_stream:parse(Parser2, <<"<stream89><a></a>">>)).
?assertEqual({error, <<"element too big">>}, exml_stream:parse(Parser2, <<"<stream89><a></a>">>)).

stream_max_element_size_test() ->
{ok, Parser0} = exml_stream:new_parser([{max_element_size, 10}]),
{ok, Parser1, Elements0} = exml_stream:parse(Parser0, <<"<stream><a></a>">>),
?assertMatch([#xmlstreamstart{}, #xmlel{}], Elements0),
?assertEqual({error, "element too big"}, exml_stream:parse(Parser1, <<"<c><d/></c>">>)).
?assertEqual({error, <<"element too big">>}, exml_stream:parse(Parser1, <<"<c><d/></c>">>)).

stream_max_text_element_size_test() ->
{ok, Parser0} = exml_stream:new_parser([{max_element_size, 10}]),
{ok, Parser1, Elements0} = exml_stream:parse(Parser0, <<"<stream><a>123</a><b>123</b>">>),
?assertMatch([#xmlstreamstart{}, #xmlel{}, #xmlel{}], Elements0),
?assertEqual({error, "element too big"}, exml_stream:parse(Parser1, <<"<c>1234</c>">>)).
?assertEqual({error, <<"element too big">>}, exml_stream:parse(Parser1, <<"<c>1234</c>">>)).

stream_max_incomplete_element_size_test() ->
{ok, Parser0} = exml_stream:new_parser([{max_element_size, 10}]),
{ok, Parser1, Elements0} = exml_stream:parse(Parser0, <<"<stream><a>123</a><b>123</b>">>),
?assertMatch([#xmlstreamstart{}, #xmlel{}, #xmlel{}], Elements0),
%% Element <c> has 10 characters, but it's incomplete, so it would be too big
?assertEqual({error, "element too big"}, exml_stream:parse(Parser1, <<"<c>1234</c">>)).
?assertEqual({error, <<"element too big">>}, exml_stream:parse(Parser1, <<"<c>1234</c">>)).

stream_max_chunked_element_size_test() ->
{ok, Parser0} = exml_stream:new_parser([{max_element_size, 10}]),
{ok, Parser1, Elements0} = exml_stream:parse(Parser0, <<"<stream><a><b/>">>),
?assertMatch([#xmlstreamstart{}], Elements0),
?assertEqual({error, "element too big"}, exml_stream:parse(Parser1, <<" ">>)).
?assertEqual({error, <<"element too big">>}, exml_stream:parse(Parser1, <<" ">>)).

stream_max_root_element_size_test() ->
{ok, Parser0} = exml_stream:new_parser([{max_element_size, 10}, {infinite_stream, true}]),
{ok, Parser1, Elements0} = exml_stream:parse(Parser0, <<"<a>123</a><b>123</b>">>),
?assertMatch([#xmlel{}, #xmlel{}], Elements0),
?assertEqual({error, "element too big"}, exml_stream:parse(Parser1, <<"<c><d/></c>">>)).
?assertEqual({error, <<"element too big">>}, exml_stream:parse(Parser1, <<"<c><d/></c>">>)).

stream_max_incomplete_root_element_size_test() ->
{ok, Parser0} = exml_stream:new_parser([{max_element_size, 10}, {infinite_stream, true}]),
{ok, Parser1, Elements0} = exml_stream:parse(Parser0, <<"<a>123</a><b>123</b>">>),
?assertMatch([#xmlel{}, #xmlel{}], Elements0),
%% Element <c> has 10 characters, but it will have at least one more character
?assertEqual({error, "element too big"}, exml_stream:parse(Parser1, <<"<c>1234</c">>)).
?assertEqual({error, <<"element too big">>}, exml_stream:parse(Parser1, <<"<c>1234</c">>)).

infinite_stream_partial_chunk_test() ->
{ok, Parser0} = exml_stream:new_parser([{infinite_stream, true}]),
Expand Down
5 changes: 0 additions & 5 deletions test/exml_tests.erl
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,6 @@ sort_xmlel_identity_test() ->
},
?assertEqual(El, exml:xml_sort(El)).

sort_xmlel_attributes_test() ->
Attrs = [{<<"attr1">>, <<"foo">>}, {<<"attr2">>, <<"bar">>}],
ToOrder = [{<<"attr2">>, <<"bar">>}, {<<"attr1">>, <<"foo">>}],
?assertEqual(Attrs, exml:xml_sort(ToOrder)).

remove_cdata_test() ->
Attrs = #{<<"attr1">> => <<"foo">>, <<"attr2">> => <<"bar">>},
Child1 = #xmlel{name = <<"el1">>, attrs = Attrs},
Expand Down

0 comments on commit 2668811

Please sign in to comment.