diff --git a/test/004-strings.t b/test/004-strings.t index ec5f568..2135a3c 100755 --- a/test/004-strings.t +++ b/test/004-strings.t @@ -4,9 +4,12 @@ main([]) -> code:add_pathz("ebin"), code:add_pathz("test"), - etap:plan(21), + etap:plan(75), util:test_good(good()), util:test_errors(errors()), + + test_utf8(utf8_cases()), + etap:end_tests(). good() -> @@ -32,5 +35,65 @@ errors() -> <<"\"\\uFFFF\"">>, <<"\"\\uD834foo\\uDD1E\"">>, % CouchDB-345 - <<"\"",78,69,73,77,69,78,32,70,216,82,82,32,70,65,69,78,33,"\"">> + <<34,78,69,73,77,69,78,32,70,216,82,82,32,70,65,69,78,33,34>> + ]. + +test_utf8([]) -> + ok; +test_utf8([Case | Rest]) -> + etap:fun_is( + fun({error, invalid_string}) -> true; (Else) -> Else end, + jiffy:encode(Case), + lists:flatten(io_lib:format("Invalid utf-8: ~p", [Case])) + ), + Case2 = <<34, Case/binary, 34>>, + etap:fun_is( + fun({error, {_, invalid_string}}) -> true; (Else) -> Else end, + jiffy:decode(Case2), + lists:flatten(io_lib:format("Invalid utf-8: ~p", [Case2])) + ), + test_utf8(Rest). + +utf8_cases() -> + [ + % Stray continuation byte + <<16#C2, 16#81, 16#80>>, + <<"foo", 16#80, "bar">>, + + % Not enough extension bytes + <<16#C0>>, + + <<16#E0>>, + <<16#E0, 16#80>>, + + <<16#F0>>, + <<16#F0, 16#80>>, + <<16#F0, 16#80, 16#80>>, + + <<16#F8>>, + <<16#F8, 16#80>>, + <<16#F8, 16#80, 16#80>>, + <<16#F8, 16#80, 16#80, 16#80>>, + + <<16#FC>>, + <<16#FC, 16#80>>, + <<16#FC, 16#80, 16#80>>, + <<16#FC, 16#80, 16#80, 16#80>>, + <<16#FC, 16#80, 16#80, 16#80, 16#80>>, + + % No data in high bits. + <<16#C0, 16#80>>, + <<16#C1, 16#80>>, + + <<16#E0, 16#80, 16#80>>, + <<16#E0, 16#90, 16#80>>, + + <<16#F0, 16#80, 16#80, 16#80>>, + <<16#F0, 16#88, 16#80, 16#80>>, + + <<16#F8, 16#80, 16#80, 16#80, 16#80>>, + <<16#F8, 16#84, 16#80, 16#80, 16#80>>, + + <<16#FC, 16#80, 16#80, 16#80, 16#80, 16#80>>, + <<16#FC, 16#82, 16#80, 16#80, 16#80, 16#80>> ]. diff --git a/test/util.erl b/test/util.erl index 0a9fa36..767f72f 100644 --- a/test/util.erl +++ b/test/util.erl @@ -27,9 +27,16 @@ check_good({J, E, J2}) -> etap:is(jiffy:decode(J), {ok, E}, ok_dec(J, E)), etap:is(do_encode(E), {ok, J2}, ok_enc(E, J2)). +check_error({J, E}) -> + etap:fun_is( + fun({error, E1}) when E1 == E -> true; (E1) -> E1 end, + jiffy:decode(J), + error_mesg(J) + ); check_error(J) -> etap:fun_is( - fun({error, _}) -> true; (_) -> false end, + fun({error, _}) -> true; (Else) -> Else end, jiffy:decode(J), error_mesg(J) ). +