anchor.diff:              Precommit == IndexHook
       end.
   
  +run_mod_fun_extract_test() ->
  +    %% Try the anonymous function
  +    TestObj = conflict_test_object(),
  +    Extractor = validate_extractor({{modfun, ?MODULE, run_mod_fun_extract_test_fun}, undefined}),
  +    ?assertEqual([{"data",<<"some data">>}],
  +                 run_extract(TestObj, Extractor)).
  + 
  +run_mod_fun_extract_test_fun(O, _Args) ->
  +    StrVals = [binary_to_list(B) || B <- riak_object:get_values(O)],
  +    Data = string:join(StrVals, " "),
  +    [{"data", list_to_binary(Data)}].
  +
  +run_qfun_extract_test() ->
  +    %% Try the anonymous function
  +    TestObj = conflict_test_object(),
  +    Fun1 = fun(O, _Args) ->
  +                   StrVals = [binary_to_list(B) || B <- riak_object:get_values(O)],
  +                   Data = string:join(StrVals, " "),
  +                   [{"data", list_to_binary(Data)}]
  +           end,
  +    Extractor = validate_extractor({{qfun, Fun1}, undefined}),
  +    ?assertEqual([{"data",<<"some data">>}],
  +                 run_extract(TestObj, Extractor)).
  + 
  +    
  +
  +anon_js_extract_test() ->
  +    maybe_start_app(sasl),
  +    maybe_start_app(erlang_js),
  +    {ok, JsSup} = riak_kv_js_sup:start_link(),
  +    {ok, JsMgr} = riak_kv_js_manager:start_link(2),
  +
  +    %% Anonymous JSON function with default argument
  +    %% Join together all the values in a search field
  +    %% called "data" and the argument as "arg"
  +    JustObjectSource = "function(o) {
  +                var vals = [];
  +                for (var i = 0; i < o.values.length; i++) {
  +                  vals.push(o.values[i].data);
  +                }
  +                data = vals.join(\" \");
  +                return {\"data\":data};
  +              }",
  +    ObjectArgSource = "function(o,a) {
  +                var vals = [];
  +                for (var i = 0; i < o.values.length; i++) {
  +                  vals.push(o.values[i].data);
  +                }
  +                data = vals.join(\" \");
  +                return {\"data\":data, \"arg\":a.f};
  +              }",
  + 
  +    %% Try the anonymous function
  +    O = conflict_test_object(),
  +    Extractor1 = validate_extractor({{jsanon, JustObjectSource}, undefined}),
  +    ?assertEqual([{"data",<<"some data">>}],
  +                 run_extract(O, Extractor1)),
  +                 
  +    %% Anonymous JSON function with provided argument
  +    %% Arg = {struct [{<<"f">>,<<"v">>}]},
  +    Arg = {struct, [{<<"f">>,<<"v">>}]},
  +    Extractor2 = validate_extractor({{jsanon, ObjectArgSource}, Arg}),
  +    ?assertEqual([{"data",<<"some data">>}, 
  +                  {"arg", <<"v">>}],
  +                 run_extract(O, Extractor2)),
  +
  +    stop_pid(JsMgr),
  +    stop_pid(JsSup),
  +    application:stop(erlang_js).
  +
  +conflict_test_object() ->
  +    O0 = riak_object:new(<<"b">>,<<"k">>,<<"v">>),
  +    riak_object:set_contents(O0, [{dict:new(), <<"some">>},
  +                                  {dict:new(), <<"data">>}]).
  +    
  +
  +maybe_start_app(App) ->
  +    case application:start(App) of
  +        {error, {already_started, App}} ->
  +            ok;
  +        ok ->
  +            ok
  +    end.
  +
  +stop_pid(Pid) ->
  +    unlink(Pid),
  +    exit(Pid, kill).
  +
   -endif. % TEST
       
  
positive.code: %% Run the extraction function against the RiakObject to get a list of
  %% search fields and data
  -spec run_extract(riak_object(), extractdef()) -> search_fields().
  run_extract(RiakObject, {{modfun, Mod, Fun}, Args}) ->
      Mod:Fun(RiakObject, Args);
  run_extract(_, _) ->
      throw({error, not_implemented}).
  
  -ifdef(TEST).
  
  
negative.code:          precommit/1]).
  -ifdef(TEST).
  -include_lib("eunit/include/eunit.hrl").
  -export([run_mod_fun_extract_test_fun/2]).
  -endif.
  
  -define(DEFAULT_EXTRACTOR, {modfun, riak_search_kv_extractor, extract}).
  