You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by kx...@apache.org on 2015/07/29 00:42:46 UTC

[21/54] jiffy commit: updated refs/heads/master to ef77de4

Improved encoder errors

This updates encoder errors to report the actual Erlang value that
caused the error. This should make it easier to debug errors when
generating JSON.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/commit/f9095c52
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/tree/f9095c52
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/diff/f9095c52

Branch: refs/heads/master
Commit: f9095c52581867938e1ea1eb695235994f585e89
Parents: 5eb499d
Author: Paul J. Davis <pa...@gmail.com>
Authored: Sat Aug 23 05:47:59 2014 -0500
Committer: Paul J. Davis <pa...@gmail.com>
Committed: Sat Aug 23 06:41:25 2014 -0500

----------------------------------------------------------------------
 c_src/encoder.c                | 30 ++++++++-----
 c_src/jiffy.h                  |  2 +
 c_src/util.c                   |  8 ++++
 src/jiffy.erl                  |  6 ++-
 test/jiffy_04_string_tests.erl |  2 +-
 test/jiffy_12_error_tests.erl  | 87 +++++++++++++++++++++++++++++++++++++
 6 files changed, 120 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/f9095c52/c_src/encoder.c
----------------------------------------------------------------------
diff --git a/c_src/encoder.c b/c_src/encoder.c
index 992b5d5..ac4935d 100644
--- a/c_src/encoder.c
+++ b/c_src/encoder.c
@@ -122,6 +122,12 @@ enc_error(Encoder* e, const char* msg)
     return make_error(e->atoms, e->env, msg);
 }
 
+ERL_NIF_TERM
+enc_obj_error(Encoder* e, const char* msg, ERL_NIF_TERM obj)
+{
+    return make_obj_error(e->atoms, e->env, msg, obj);
+}
+
 static inline int
 enc_ensure(Encoder* e, size_t req)
 {
@@ -667,11 +673,11 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
                 goto done;
             }
             if(!enif_get_tuple(env, item, &arity, &tuple)) {
-                ret = enc_error(e, "invalid_object_pair");
+                ret = enc_obj_error(e, "invalid_object_member", item);
                 goto done;
             }
             if(arity != 2) {
-                ret = enc_error(e, "invalid_object_pair");
+                ret = enc_obj_error(e, "invalid_object_member_arity", item);
                 goto done;
             }
             if(!enc_comma(e)) {
@@ -679,7 +685,7 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
                 goto done;
             }
             if(!enc_string(e, tuple[0])) {
-                ret = enc_error(e, "invalid_object_key");
+                ret = enc_obj_error(e, "invalid_object_member_key", tuple[0]);
                 goto done;
             }
             if(!enc_colon(e)) {
@@ -712,12 +718,12 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
             stack = enif_make_list_cell(env, curr, stack);
             stack = enif_make_list_cell(env, e->atoms->ref_array, stack);
             stack = enif_make_list_cell(env, item, stack);
-        } else if(enif_compare(curr, e->atoms->atom_null) == 0 
+        } else if(enif_compare(curr, e->atoms->atom_null) == 0) {
             if(!enc_literal(e, "null", 4)) {
                 ret = enc_error(e, "null");
                 goto done;
             }
-        } else if(e->use_nil && enif_compare(curr, e->atoms->atom_nil) == 0)) {
+        } else if(e->use_nil && enif_compare(curr, e->atoms->atom_nil) == 0) {
             if(!enc_literal(e, "null", 4)) {
                 ret = enc_error(e, "null");
                 goto done;
@@ -734,12 +740,12 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
             }
         } else if(enif_is_binary(env, curr)) {
             if(!enc_string(e, curr)) {
-                ret = enc_error(e, "invalid_string");
+                ret = enc_obj_error(e, "invalid_string", curr);
                 goto done;
             }
         } else if(enif_is_atom(env, curr)) {
             if(!enc_string(e, curr)) {
-                ret = enc_error(e, "invalid_string");
+                ret = enc_obj_error(e, "invalid_string", curr);
                 goto done;
             }
         } else if(enif_get_int64(env, curr, &lval)) {
@@ -754,11 +760,11 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
             }
         } else if(enif_get_tuple(env, curr, &arity, &tuple)) {
             if(arity != 1) {
-                ret = enc_error(e, "invalid_ejson");
+                ret = enc_obj_error(e, "invalid_ejson", curr);
                 goto done;
             }
             if(!enif_is_list(env, tuple[0])) {
-                ret = enc_error(e, "invalid_object");
+                ret = enc_obj_error(e, "invalid_object", curr);
                 goto done;
             }
             if(!enc_start_object(e)) {
@@ -777,15 +783,15 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
                 goto done;
             }
             if(!enif_get_tuple(env, item, &arity, &tuple)) {
-                ret = enc_error(e, "invalid_object_member");
+                ret = enc_obj_error(e, "invalid_object_member", item);
                 goto done;
             }
             if(arity != 2) {
-                ret = enc_error(e, "invalid_object_member_arity");
+                ret = enc_obj_error(e, "invalid_object_member_arity", item);
                 goto done;
             }
             if(!enc_string(e, tuple[0])) {
-                ret = enc_error(e, "invalid_object_member_key");
+                ret = enc_obj_error(e, "invalid_object_member_key", tuple[0]);
                 goto done;
             }
             if(!enc_colon(e)) {

http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/f9095c52/c_src/jiffy.h
----------------------------------------------------------------------
diff --git a/c_src/jiffy.h b/c_src/jiffy.h
index 34dff75..6d869a5 100644
--- a/c_src/jiffy.h
+++ b/c_src/jiffy.h
@@ -41,6 +41,8 @@ typedef struct {
 ERL_NIF_TERM make_atom(ErlNifEnv* env, const char* name);
 ERL_NIF_TERM make_ok(jiffy_st* st, ErlNifEnv* env, ERL_NIF_TERM data);
 ERL_NIF_TERM make_error(jiffy_st* st, ErlNifEnv* env, const char* error);
+ERL_NIF_TERM make_obj_error(jiffy_st* st, ErlNifEnv* env, const char* error,
+        ERL_NIF_TERM obj);
 int get_bytes_per_iter(ErlNifEnv* env, ERL_NIF_TERM val, size_t* bpi);
 int should_yield(size_t used, size_t limit);
 int consume_timeslice(ErlNifEnv* env, size_t used, size_t limit);

http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/f9095c52/c_src/util.c
----------------------------------------------------------------------
diff --git a/c_src/util.c b/c_src/util.c
index 7436add..c30a6d7 100644
--- a/c_src/util.c
+++ b/c_src/util.c
@@ -25,6 +25,14 @@ make_error(jiffy_st* st, ErlNifEnv* env, const char* error)
     return enif_make_tuple2(env, st->atom_error, make_atom(env, error));
 }
 
+ERL_NIF_TERM
+make_obj_error(jiffy_st* st, ErlNifEnv* env,
+        const char* error, ERL_NIF_TERM obj)
+{
+    ERL_NIF_TERM reason = enif_make_tuple2(env, make_atom(env, error), obj);
+    return enif_make_tuple2(env, st->atom_error, reason);
+}
+
 int
 get_bytes_per_iter(ErlNifEnv* env, ERL_NIF_TERM val, size_t* bpi)
 {

http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/f9095c52/src/jiffy.erl
----------------------------------------------------------------------
diff --git a/src/jiffy.erl b/src/jiffy.erl
index 8903831..9642b25 100644
--- a/src/jiffy.erl
+++ b/src/jiffy.erl
@@ -34,7 +34,7 @@ encode(Data) ->
 encode(Data, Options) ->
     ForceUTF8 = lists:member(force_utf8, Options),
     case nif_encode_init(Data, Options) of
-        {error, invalid_string} when ForceUTF8 == true ->
+        {error, {invalid_string, _}} when ForceUTF8 == true ->
             FixedData = jiffy_utf8:fix(Data),
             encode(FixedData, Options -- [force_utf8]);
         {error, _} = Error ->
@@ -102,6 +102,8 @@ finish_encode([<<_/binary>>=B | Rest], Acc) ->
 finish_encode([Val | Rest], Acc) when is_integer(Val) ->
     Bin = list_to_binary(integer_to_list(Val)),
     finish_encode(Rest, [Bin | Acc]);
+finish_encode([InvalidEjson | _], _) ->
+    throw({error, {invalid_ejson, InvalidEjson}});
 finish_encode(_, _) ->
     throw({error, invalid_ejson}).
 
@@ -134,7 +136,7 @@ decode_loop(Data, Decoder, Objs, Curr) ->
 encode_loop(Data, Options, Encoder, Stack, IOBuf) ->
     ForceUTF8 = lists:member(force_utf8, Options),
     case nif_encode_iter(Encoder, Stack, IOBuf) of
-        {error, invalid_string} when ForceUTF8 == true ->
+        {error, {invalid_string, _}} when ForceUTF8 == true ->
             FixedData = jiffy_utf8:fix(Data),
             encode(FixedData, Options -- [force_utf8]);
         {error, _} = Error ->

http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/f9095c52/test/jiffy_04_string_tests.erl
----------------------------------------------------------------------
diff --git a/test/jiffy_04_string_tests.erl b/test/jiffy_04_string_tests.erl
index 46f15ff..7238f7c 100644
--- a/test/jiffy_04_string_tests.erl
+++ b/test/jiffy_04_string_tests.erl
@@ -48,7 +48,7 @@ gen(utf8, {Case, Fixed}) ->
     Case2 = <<34, Case/binary, 34>>,
     Fixed2 = <<34, Fixed/binary, 34>>,
     {msg("UTF-8: ~s", [hex(Case)]), [
-        ?_assertThrow({error, invalid_string}, jiffy:encode(Case)),
+        ?_assertThrow({error, {invalid_string, _}}, jiffy:encode(Case)),
         ?_assertEqual(Fixed2, jiffy:encode(Case, [force_utf8])),
         ?_assertThrow({error, {_, invalid_string}}, jiffy:decode(Case2))
     ]}.

http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/f9095c52/test/jiffy_12_error_tests.erl
----------------------------------------------------------------------
diff --git a/test/jiffy_12_error_tests.erl b/test/jiffy_12_error_tests.erl
new file mode 100644
index 0000000..a7d4ed6
--- /dev/null
+++ b/test/jiffy_12_error_tests.erl
@@ -0,0 +1,87 @@
+% This file is part of Jiffy released under the MIT license.
+% See the LICENSE file for more information.
+
+-module(jiffy_12_error_tests).
+
+-include_lib("eunit/include/eunit.hrl").
+
+
+enc_invalid_ejson_test_() ->
+    Type = invalid_ejson,
+    Ref = make_ref(),
+    {"invalid_ejson", [
+        {"Basic", enc_error(Type, Ref, Ref)},
+        {"Nested", enc_error(Type, {Ref, Ref}, {Ref, Ref})}
+    ]}.
+
+
+enc_invalid_string_test_() ->
+    Type = invalid_string,
+    {"invalid_string", [
+        {"Bare strign", enc_error(Type, <<143>>, <<143>>)},
+        {"List element", enc_error(Type, <<143>>, [<<143>>])},
+        {"Bad obj value", enc_error(Type, <<143>>, {[{foo, <<143>>}]})}
+    ]}.
+
+enc_invalid_object_test_() ->
+    Type = invalid_object,
+    Ref = make_ref(),
+    {"invalid_object", [
+        {"Number", enc_error(Type, {1}, {1})},
+        {"Ref", enc_error(Type, {Ref}, {Ref})},
+        {"Tuple", enc_error(Type, {{[]}}, {{[]}})},
+        {"Atom", enc_error(Type, {foo}, {foo})}
+    ]}.
+
+
+enc_invalid_object_member_test_() ->
+    Type = invalid_object_member,
+    {"invalid_object_member", [
+        {"Basic", enc_error(Type, foo, {[foo]})},
+        {"Basic", enc_error(Type, foo, {[{bar, baz}, foo]})},
+        {"Nested", enc_error(Type, foo, {[{bar,{[foo]}}]})},
+        {"Nested", enc_error(Type, foo, {[{bar,{[{baz, 1}, foo]}}]})},
+        {"In List", enc_error(Type, foo, [{[foo]}])},
+        {"In List", enc_error(Type, foo, [{[{bang, true}, foo]}])}
+    ]}.
+
+
+enc_invalid_object_member_arity_test_() ->
+    Type = invalid_object_member_arity,
+    E1 = {foo},
+    E2 = {x, y, z},
+    {"invalid_object_member", [
+        {"Basic", enc_error(Type, E1, {[E1]})},
+        {"Basic", enc_error(Type, E2, {[E2]})},
+        {"Basic", enc_error(Type, E1, {[{bar, baz}, E1]})},
+        {"Basic", enc_error(Type, E2, {[{bar, baz}, E2]})},
+        {"Nested", enc_error(Type, E1, {[{bar,{[E1]}}]})},
+        {"Nested", enc_error(Type, E2, {[{bar,{[E2]}}]})},
+        {"Nested", enc_error(Type, E1, {[{bar,{[{baz, 1}, E1]}}]})},
+        {"Nested", enc_error(Type, E2, {[{bar,{[{baz, 1}, E2]}}]})},
+        {"In List", enc_error(Type, E1, [{[E1]}])},
+        {"In List", enc_error(Type, E2, [{[E2]}])},
+        {"In List", enc_error(Type, E1, [{[{bang, true}, E1]}])},
+        {"In List", enc_error(Type, E2, [{[{bang, true}, E2]}])}
+    ]}.
+
+
+enc_invalid_object_member_key_test_() ->
+    Type = invalid_object_member_key,
+    E1 = {1, true},
+    {"invalid_object_member_key", [
+        {"Bad string", enc_error(Type, <<143>>, {[{<<143>>, true}]})},
+        {"Basic", enc_error(Type, 1, {[{1, true}]})},
+        {"Basic", enc_error(Type, [1], {[{[1], true}]})},
+        {"Basic", enc_error(Type, {[{foo,bar}]}, {[{{[{foo,bar}]}, true}]})},
+        {"Second", enc_error(Type, 1, {[{bar, baz}, E1]})},
+        {"Nested", enc_error(Type, 1, {[{bar,{[E1]}}]})},
+        {"Nested", enc_error(Type, 1, {[{bar,{[{baz, 1}, E1]}}]})},
+        {"In List", enc_error(Type, 1, [{[E1]}])},
+        {"In List", enc_error(Type, 1, [{[{bang, true}, E1]}])}
+    ]}.
+
+
+
+enc_error(Type, Obj, Case) ->
+    ?_assertEqual({error, {Type, Obj}}, (catch jiffy:encode(Case))).