Repository: couchdb-couch Updated Branches: refs/heads/master 04fb14055 -> 71a6a99de
Add couch_util:validate_callback_exists COUCHDB-2585 Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/ef96fd92 Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/ef96fd92 Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/ef96fd92 Branch: refs/heads/master Commit: ef96fd92b5db14cec26e0daf1fc4042425235985 Parents: d0e8d14 Author: ILYA Khlopotov <[email protected]> Authored: Tue Feb 24 13:06:29 2015 -0800 Committer: ILYA Khlopotov <[email protected]> Committed: Thu Feb 26 15:04:49 2015 -0800 ---------------------------------------------------------------------- src/couch_util.erl | 32 ++++++++++++++++++++++++++++++++ test/couch_util_tests.erl | 26 ++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/ef96fd92/src/couch_util.erl ---------------------------------------------------------------------- diff --git a/src/couch_util.erl b/src/couch_util.erl index 7dd09b7..7e16866 100644 --- a/src/couch_util.erl +++ b/src/couch_util.erl @@ -32,6 +32,7 @@ -export([rfc1123_date/0, rfc1123_date/1]). -export([integer_to_boolean/1, boolean_to_integer/1]). -export([find_in_binary/2]). +-export([callback_exists/3, validate_callback_exists/3]). -include_lib("couch/include/couch_db.hrl"). @@ -537,3 +538,34 @@ match_rest_of_prefix([{Pos, _Len} | Rest], Prefix, Data, PrefixLength, N) -> {_Pos, _Len1} -> {partial, N + Pos} end. + +callback_exists(Module, Function, Arity) -> + case ensure_loaded(Module) of + true -> + InfoList = Module:module_info(exports), + lists:member({Function, Arity}, InfoList); + false -> + false + end. + +validate_callback_exists(Module, Function, Arity) -> + case callback_exists(Module, Function, Arity) of + true -> + ok; + false -> + CallbackStr = lists:flatten( + io_lib:format("~w:~w/~w", [Module, Function, Arity])), + throw({error, + {undefined_callback, CallbackStr, {Module, Function, Arity}}}) + end. + +ensure_loaded(Module) when is_atom(Module) -> + case code:ensure_loaded(Module) of + {module, Module} -> + true; + {error, embedded} -> + true; + {error, _} -> + false + end; +ensure_loaded(_Module) -> false. http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/ef96fd92/test/couch_util_tests.erl ---------------------------------------------------------------------- diff --git a/test/couch_util_tests.erl b/test/couch_util_tests.erl index 4c313a2..5611c07 100644 --- a/test/couch_util_tests.erl +++ b/test/couch_util_tests.erl @@ -50,6 +50,15 @@ collation_test_() -> ] }. +validate_callback_exists_test_() -> + { + "validate_callback_exists tests", + [ + fun should_succeed_for_existent_cb/0, + should_fail_for_missing_cb() + ] + }. + should_collate_ascii() -> ?_assertEqual(1, couch_util:collate(<<"foo">>, <<"bar">>)). @@ -134,3 +143,20 @@ find_in_binary_test_() -> {Msg, ?_assertMatch(Result, couch_util:find_in_binary(Needle, Haystack))} end, Cases). + +should_succeed_for_existent_cb() -> + ?_assert(couch_util:validate_callback_exists(lists, any, 2)). + +should_fail_for_missing_cb() -> + Cases = [ + {unknown_module, any, 1}, + {erlang, unknown_function, 1}, + {erlang, whereis, 100} + ], + lists:map( + fun({M, F, A} = MFA) -> + Name = lists:flatten(io_lib:format("~w:~w/~w", [M, F, A])), + {Name, ?_assertThrow( + {error, {undefined_callback, Name, MFA}}, + couch_util:validate_callback_exists(M, F, A))} + end, Cases).
