Commits

Yuriy Netesov committed 8d5debd Draft

+meck module

  • Participants
  • Parent commits d38dd39

Comments (0)

Files changed (75)

File apps/kissbang/src/proxy_srv.erl

 %% @end
 %%--------------------------------------------------------------------
 register_origin(Guid, Origin) ->
-    gen_server:call(?SERVER, {reigster_origin, Guid, Origin}).
+    gen_server:call(?SERVER, {register_origin, Guid, Origin}).
 
 
 %%--------------------------------------------------------------------
                             {ok, UserOrigin#user_origin.origin}
                         end
             end,
-    {atomic, Result} = mnesia:activity(Trans),
+    {atomic, Result} = mnesia:transaction(Trans),
     case Result of
         {ok, Origin} ->
-            gateway_str:disconnect_origin(Origin),
+            gateway_srv:disconnect_origin(Origin),
             ok;
         Other ->
             Other

File apps/kissbang/test/guid_srv_tests.erl

 %%==================================================
 %% Testing setup
 %%==================================================
-guid_srv_tests_() ->
+guid_srv_test_() ->
     {setup, fun setup/0,
-     {inorder, [
-                fun should_create_guid/0
-               ]}}.
+     [
+      fun should_create_guid/0,
+      fun should_create_multiply_guids/0
+     ]}.
 
 setup() ->
     guid_srv:start_link().
 %%==================================================
 should_create_guid() ->
     ?assertMatch({ok, _Guid}, guid_srv:create()).
+
+should_create_multiply_guids() ->
+    lists:foreach(fun (X) -> 
+                          ?assertMatch({ok, _Guid}, guid_srv:create()) 
+                  end, lists:seq(0, 10000)).

File apps/kissbang/test/proxy_srv_tests.erl

 -include_lib("eunit/include/eunit.hrl").
 -include("../src/origin.hrl").
 -compile(export_all).
+-import(meck).
 
 %%==================================================
 %% Testing setup
 %%==================================================
-proxy_srv_tests_() ->
-    {foreach, fun foreach_setup/0, 
+proxy_srv_test_() ->
+    {setup, fun setup/0, 
      {inorder, [
                 fun should_register_origin/0,
-                fun should_get_origin/0
+                fun should_get_origin/0,
+                fun should_get_non_existant_origin/0,
+                fun should_route_to_origin/0,
+                fun should_drop_origin/0
                ]}}.
 
-foreach_setup() ->
+setup() ->
     mock_patch(),
+    guid_srv:start_link(),
     auth_srv:start_link(),
     proxy_srv:start_link(),
     proxy_srv:drop_all().
 
 mock_patch() ->
+    %% patching for gateway server
+    meck:new(gateway_srv),
+    meck:expect(gateway_srv, disconnect_origin, fun(Origin) -> ok end),
+    meck:expect(gateway_srv, route_messages, fun(Origin, Messages) -> ok end),
     ok.
 
 %%==================================================
 should_get_origin() ->
     {ok, Guid} = get_test_guid(),
     ?assert(ok == proxy_srv:register_origin(Guid, get_test_origin())),
-    ?assertEqual({ok, get_test_origin()}, auth_srv:get_origin(Guid)).
+    ?assertEqual({ok, get_test_origin()}, proxy_srv:get_origin(Guid)).
 
 should_get_non_existant_origin() ->
     {ok, Guid} = get_test_guid(),

File extern/meck/.eunit/cover.log

+Analysis includes data from imported files
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module.coverdata",
+ "/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module_meck_original.coverdata"]
+Analysis includes data from imported files
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/cover_test_module.coverdata"]
+WARNING: Deleting data for module cover_test_module imported from
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/cover_test_module.coverdata"]
+Analysis includes data from imported files
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/cover_test_module.coverdata",
+ "/mnt/work/dev/home/kissbang/extern/meck/.eunit/cover_test_module_meck_original.coverdata"]
+WARNING: Deleting data for module meck_test_module imported from
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module.coverdata",
+ "/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module_meck_original.coverdata"]
+Analysis includes data from imported files
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module.coverdata"]
+WARNING: Deleting data for module meck_test_module imported from
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module.coverdata"]
+Analysis includes data from imported files
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module.coverdata",
+ "/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module_meck_original.coverdata"]
+Export includes data from imported files
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module.coverdata",
+ "/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module_meck_original.coverdata"]
+WARNING: Deleting data for module meck_test_module imported from
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module.coverdata",
+ "/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module_meck_original.coverdata"]
+WARNING: Deleting data for module meck_test_module imported from
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module.coverdata",
+ "/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module_meck_original.coverdata"]
+WARNING: remote cover_server received
+{<12827.45.0>,{is_compiled,meck_test_module}}
+Export includes data from imported files
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_parametrized_module.coverdata",
+ "/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_parametrized_module_meck_original.coverdata"]
+WARNING: Deleting data for module meck_test_parametrized_module imported from
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_parametrized_module.coverdata",
+ "/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_parametrized_module_meck_original.coverdata"]
+Analysis includes data from imported files
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_parametrized_module.coverdata",
+ "/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_parametrized_module_meck_original.coverdata"]
+Analysis includes data from imported files
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module.coverdata",
+ "/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module_meck_original.coverdata"]
+Analysis includes data from imported files
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_parametrized_module.coverdata",
+ "/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_parametrized_module_meck_original.coverdata"]
+Analysis includes data from imported files
+["/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module.coverdata",
+ "/mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_test_module_meck_original.coverdata"]

File extern/meck/.eunit/index.html

+<html><head><title>Coverage Summary</title></head>
+<body><h1>Source Summary</h1>
+<h3>Total: 97%</h3>
+<table><tr><th>Module</th><th>Coverage %</th></tr>
+<tr><td><a href='meck.COVER.html'>meck</a></td><td>98%</td>
+<tr><td><a href='meck_cover.COVER.html'>meck_cover</a></td><td>100%</td>
+<tr><td><a href='meck_mod.COVER.html'>meck_mod</a></td><td>85%</td>
+</table>
+<body><h1>Test Summary</h1>
+<h3>Total: 10%</h3>
+<table><tr><th>Module</th><th>Coverage %</th></tr>
+<tr><td><a href='meck_performance_test.COVER.html'>meck_performance_test</a></td><td>0%</td>
+<tr><td><a href='meck_test_module.COVER.html'>meck_test_module</a></td><td>100%</td>
+<tr><td><a href='meck_test_parametrized_module.COVER.html'>meck_test_parametrized_module</a></td><td>33%</td>
+</table>
+</body></html>

File extern/meck/.eunit/meck.COVER.html

+<html>
+<head><title>.eunit/meck.COVER.html</title></head><body bgcolor=white text=black>
+<pre>
+File generated from /mnt/work/dev/home/kissbang/extern/meck/.eunit/meck.erl by COVER 2012-05-30 at 17:17:55
+
+****************************************************************************
+
+        |  %%==============================================================================
+        |  %% Copyright 2011 Adam Lindberg & Erlang Solutions Ltd.
+        |  %%
+        |  %% Licensed under the Apache License, Version 2.0 (the "License");
+        |  %% you may not use this file except in compliance with the License.
+        |  %% You may obtain a copy of the License at
+        |  %%
+        |  %% http://www.apache.org/licenses/LICENSE-2.0
+        |  %%
+        |  %% Unless required by applicable law or agreed to in writing, software
+        |  %% distributed under the License is distributed on an "AS IS" BASIS,
+        |  %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        |  %% See the License for the specific language governing permissions and
+        |  %% limitations under the License.
+        |  %%==============================================================================
+        |  
+        |  %% @author Adam Lindberg &lt;eproxus@gmail.com&gt;
+        |  %% @copyright 2011, Adam Lindberg & Erlang Solutions Ltd
+        |  %% @doc Module mocking library for Erlang.
+        |  
+        |  -module(meck).
+        |  -behaviour(gen_server).
+        |  
+        |  %% Interface exports
+        |  -export([new/1]).
+        |  -export([new/2]).
+        |  -export([expect/3]).
+        |  -export([expect/4]).
+        |  -export([sequence/4]).
+        |  -export([loop/4]).
+        |  -export([delete/3]).
+        |  -export([exception/2]).
+        |  -export([passthrough/1]).
+        |  -export([history/1]).
+        |  -export([history/2]).
+        |  -export([validate/1]).
+        |  -export([unload/0]).
+        |  -export([unload/1]).
+        |  -export([called/3]).
+        |  -export([called/4]).
+        |  -export([num_calls/3]).
+        |  -export([num_calls/4]).
+        |  
+        |  %% Callback exports
+        |  -export([init/1]).
+        |  -export([handle_call/3]).
+        |  -export([handle_cast/2]).
+        |  -export([handle_info/2]).
+        |  -export([terminate/2]).
+        |  -export([code_change/3]).
+        |  -export([exec/5]).
+        |  
+        |  %% Types
+        |  %% @type meck_mfa() = {Mod::atom(), Func::atom(), Args::list(term())}.
+        |  %% Module, function and arguments that the mock module got called with.
+        |  -type meck_mfa() :: {Mod::atom(), Func::atom(), Args::[term()]}.
+        |  
+        |  %% @type history() = [{pid(), meck_mfa(), Result::term()}
+        |  %%                     | {pid(), meck_mfa(), Class:: exit | error | throw,
+        |  %%                        Reason::term(), Stacktrace::list(mfa())}].
+        |  %% History is a list of either successful function calls with a returned
+        |  %% result or function calls that resulted in an exception with a type,
+        |  %% reason and a stack trace. Each tuple begins with the pid of the process
+        |  %% that made the call to the function.
+        |  -type history() :: [{pid(), meck_mfa(), Result::term()}
+        |                      | {pid(), meck_mfa(), Class:: exit | error | throw,
+        |                         Reason::term(), Stacktrace::[mfa()]}].
+        |  
+        |  %% Records
+        |  -record(state, {mod :: atom(),
+        |                  expects :: dict(),
+        |                  valid = true :: boolean(),
+        |                  history = [] :: history(),
+        |                  original :: term(),
+        |                  was_sticky :: boolean()}).
+        |  
+        |  %% Includes
+        |  -include("meck_abstract.hrl").
+        |  
+        |  %%==============================================================================
+        |  %% Interface exports
+        |  %%==============================================================================
+        |  
+        |  %% @spec new(Mod:: atom() | list(atom())) -&gt; ok
+        |  %% @equiv new(Mod, [])
+        |  -spec new(Mod:: atom() | [atom()]) -&gt; ok.
+    84..|  new(Mod) when is_atom(Mod) -&gt; new(Mod, []);
+     5..|  new(Mod) when is_list(Mod) -&gt; lists:foreach(fun new/1, Mod), ok.
+        |  
+        |  %% @spec new(Mod:: atom() | list(atom()), Options::list(term())) -&gt; ok
+        |  %% @doc Creates new mocked module(s).
+        |  %%
+        |  %% This replaces the current version (if any) of the modules in `Mod'
+        |  %% with an empty module.
+        |  %%
+        |  %% Since this library is intended to use from test code, this
+        |  %% function links a process for each mock to the calling process.
+        |  %%
+        |  %% The valid options are:
+        |  %% &lt;dl&gt;
+        |  %%   &lt;dt&gt;`passthrough'&lt;/dt&gt;&lt;dd&gt;Retains the original functions, if not
+        |  %%                             mocked by meck.&lt;/dd&gt;
+        |  %%   &lt;dt&gt;`no_link'&lt;/dt&gt;    &lt;dd&gt;Does not link the meck process to the caller
+        |  %%                             process (needed for using meck in rpc calls).
+        |  %%                         &lt;/dd&gt;
+        |  %%   &lt;dt&gt;`unstick'&lt;/dt&gt;    &lt;dd&gt;Unstick the module to be mocked (e.g. needed
+        |  %%                             for using meck with kernel and stdlib modules).
+        |  %%                         &lt;/dd&gt;
+        |  %%   &lt;dt&gt;`no_passthrough_cover'&lt;/dt&gt;&lt;dd&gt;If cover is enabled on the module to be
+        |  %%                                      mocked then meck will continue to
+        |  %%                                      capture coverage on passthrough calls.
+        |  %%                                      This option allows you to disable that
+        |  %%                                      feature if it causes problems.
+        |  %%                                  &lt;/dd&gt;
+        |  %% &lt;/dl&gt;
+        |  -spec new(Mod:: atom() | [atom()], Options::[term()]) -&gt; ok.
+        |  new(Mod, Options) when is_atom(Mod), is_list(Options) -&gt;
+   102..|      case start(Mod, Options) of
+   100..|          {ok, _Pid} -&gt; ok;
+     2..|          {error, Reason} -&gt; erlang:error(Reason, [Mod, Options])
+        |      end;
+        |  new(Mod, Options) when is_list(Mod) -&gt;
+     1..|      lists:foreach(fun(M) -&gt; new(M, Options) end, Mod),
+     1..|      ok.
+        |  
+        |  %% @spec expect(Mod:: atom() | list(atom()), Func::atom(), Expect::fun()) -&gt; ok
+        |  %% @doc Add expectation for a function `Func' to the mocked modules `Mod'.
+        |  %%
+        |  %% An expectation is a fun that is executed whenever the function
+        |  %% `Func' is called.
+        |  %%
+        |  %% It affects the validation status of the mocked module(s). If an
+        |  %% expectation is called with the wrong number of arguments or invalid
+        |  %% arguments the mock module(s) is invalidated. It is also invalidated if
+        |  %% an unexpected exception occurs.
+        |  -spec expect(Mod:: atom() | [atom()], Func::atom(), Expect::fun()) -&gt; ok.
+        |  expect(Mod, Func, Expect)
+        |    when is_atom(Mod), is_atom(Func), is_function(Expect) -&gt;
+    61..|      call(Mod, {expect, Func, Expect});
+        |  expect(Mod, Func, Expect) when is_list(Mod) -&gt;
+     3..|      lists:foreach(fun(M) -&gt; expect(M, Func, Expect) end, Mod),
+     3..|      ok.
+        |  
+        |  %% @spec expect(Mod:: atom() | list(atom()), Func::atom(),
+        |  %%              Arity::pos_integer(), Result::term()) -&gt; ok
+        |  %% @doc Adds an expectation with the supplied arity and return value.
+        |  %%
+        |  %% This creates an expectation which takes `Arity' number of functions
+        |  %% and always returns `Result'.
+        |  %%
+        |  %% @see expect/3.
+        |  -spec expect(Mod:: atom() | [atom()], Func::atom(),
+        |               Arity::pos_integer(), Result::term()) -&gt; ok.
+        |  expect(Mod, Func, Arity, Result)
+        |    when is_atom(Mod), is_atom(Func), is_integer(Arity), Arity &gt;= 0 -&gt;
+    32..|      valid_expect(Mod, Func, Arity),
+    30..|      call(Mod, {expect, Func, Arity, Result});
+        |  expect(Mod, Func, Arity, Result) when is_list(Mod) -&gt;
+     3..|      lists:foreach(fun(M) -&gt; expect(M, Func, Arity, Result) end, Mod),
+     3..|      ok.
+        |  
+        |  %% @spec sequence(Mod:: atom() | list(atom()), Func::atom(),
+        |  %%                Arity::pos_integer(), Sequence::[term()]) -&gt; ok
+        |  %% @doc Adds an expectation which returns a value from `Sequence'
+        |  %% until exhausted.
+        |  %%
+        |  %% This creates an expectation which takes `Arity' number of arguments
+        |  %% and returns one element from `Sequence' at a time. Thus, calls to
+        |  %% this expect will exhaust the list of return values in order until
+        |  %% the last value is reached. That value is then returned for all
+        |  %% subsequent calls.
+        |  -spec sequence(Mod:: atom() | [atom()], Func::atom(),
+        |                 Arity::pos_integer(), Sequence::[term()]) -&gt; ok.
+        |  sequence(Mod, Func, Arity, Sequence)
+        |    when is_atom(Mod), is_atom(Func), is_integer(Arity), Arity &gt;= 0 -&gt;
+     3..|      call(Mod, {sequence, Func, Arity, Sequence});
+        |  sequence(Mod, Func, Arity, Sequence) when is_list(Mod) -&gt;
+     1..|      lists:foreach(fun(M) -&gt; sequence(M, Func, Arity, Sequence) end, Mod),
+     1..|      ok.
+        |  
+        |  %% @spec loop(Mod:: atom() | list(atom()), Func::atom(),
+        |  %%            Arity::pos_integer(), Loop::[term()]) -&gt; ok
+        |  %% @doc Adds an expectation which returns a value from `Loop'
+        |  %% infinitely.
+        |  %%
+        |  %% This creates an expectation which takes `Arity' number of arguments
+        |  %% and returns one element from `Loop' at a time. Thus, calls to this
+        |  %% expect will return one element at a time from the list and will
+        |  %% restart at the first element when the end is reached.
+        |  -spec loop(Mod:: atom() | [atom()], Func::atom(),
+        |             Arity::pos_integer(), Loop::[term()]) -&gt; ok.
+        |  loop(Mod, Func, Arity, Loop)
+        |    when is_atom(Mod), is_atom(Func), is_integer(Arity), Arity &gt;= 0 -&gt;
+     3..|      call(Mod, {loop, Func, Arity, Loop});
+        |  loop(Mod, Func, Arity, Loop) when is_list(Mod) -&gt;
+     1..|      lists:foreach(fun(M) -&gt; loop(M, Func, Arity, Loop) end, Mod),
+     1..|      ok.
+        |  
+        |  %% @spec delete(Mod:: atom() | list(atom()), Func::atom(),
+        |  %%              Arity::pos_integer()) -&gt; ok
+        |  %% @doc Deletes an expectation.
+        |  %%
+        |  %% Deletes the expectation for the function `Func' with the matching
+        |  %% arity `Arity'.
+        |  -spec delete(Mod:: atom() | [atom()], Func::atom(), Arity::pos_integer()) -&gt;
+        |      ok.
+        |  delete(Mod, Func, Arity)
+        |    when is_atom(Mod), is_atom(Func), Arity &gt;= 0 -&gt;
+     4..|      call(Mod, {delete, Func, Arity});
+        |  delete(Mod, Func, Arity) when is_list(Mod) -&gt;
+     1..|      lists:foreach(fun(M) -&gt; delete(M, Func, Arity) end, Mod),
+     1..|      ok.
+        |  
+        |  %% @spec exception(Class:: throw | error | exit, Reason::term()) -&gt; no_return()
+        |  %% @doc Throws an expected exception inside an expect fun.
+        |  %%
+        |  %% This exception will get thrown without invalidating the mocked
+        |  %% module. That is, the code using the mocked module is expected to
+        |  %% handle this exception.
+        |  %%
+        |  %% &lt;em&gt;Note: this code should only be used inside an expect fun.&lt;/em&gt;
+        |  -spec exception(Class:: throw | error | exit, Reason::term()) -&gt; no_return().
+        |  exception(Class, Reason) when Class == throw; Class == error; Class == exit -&gt;
+     8..|      throw(mock_exception_fun(Class, Reason)).
+        |  
+        |  %% @spec passthrough(Args::list(term())) -&gt; no_return()
+        |  %% @doc Calls the original function (if existing) inside an expectation fun.
+        |  %%
+        |  %% This call does not return, thus everything after this call inside
+        |  %% an expectation fun will be ignored.
+        |  %%
+        |  %% &lt;em&gt;Note: this code should only be used inside an expect fun.&lt;/em&gt;
+        |  -spec passthrough(Args::[term()]) -&gt; no_return().
+     3..|  passthrough(Args) -&gt; throw(passthrough_fun(Args)).
+        |  
+        |  %% @spec validate(Mod:: atom() | list(atom())) -&gt; boolean()
+        |  %% @doc Validate the state of the mock module(s).
+        |  %%
+        |  %% The function returns `true' if the mocked module(s) has been used
+        |  %% according to its expectations. It returns `false' if a call has
+        |  %% failed in some way. Reasons for failure are wrong number of
+        |  %% arguments or non-existing function (undef), wrong arguments
+        |  %% (function clause) or unexpected exceptions.
+        |  %%
+        |  %% Use the {@link history/1} or {@link history/2} function to analyze errors.
+        |  -spec validate(Mod:: atom() | [atom()]) -&gt; boolean().
+        |  validate(Mod) when is_atom(Mod) -&gt;
+    49..|      call(Mod, validate);
+        |  validate(Mod) when is_list(Mod) -&gt;
+     7..|      not lists:member(false, [validate(M) || M &lt;- Mod]).
+        |  
+        |  %% @spec history(Mod::atom()) -&gt; history()
+        |  %% @doc Return the call history of the mocked module for all processes.
+        |  %%
+        |  %% @equiv history(Mod, '_')
+        |  -spec history(Mod::atom()) -&gt; history().
+    30..|  history(Mod) when is_atom(Mod) -&gt; call(Mod, history).
+        |  
+        |  %% @spec history(Mod::atom(), Pid::pid()) -&gt; history()
+        |  %% @doc Return the call history of the mocked module for the specified process.
+        |  %%
+        |  %% Returns a list of calls to the mocked module and their results for
+        |  %% the specified `Pid'.  Results can be either normal Erlang terms or
+        |  %% exceptions that occurred.
+        |  %%
+        |  %% @see history/1
+        |  %% @see called/3
+        |  %% @see called/4
+        |  %% @see num_calls/3
+        |  %% @see num_calls/4
+        |  -spec history(Mod::atom(), Pid:: pid() | '_') -&gt; history().
+        |  history(Mod, Pid) when is_atom(Mod), is_pid(Pid) orelse Pid == '_' -&gt; 
+    11..|      match_history(match_mfa('_', Pid), call(Mod, history)).
+        |  
+        |  %% @spec unload() -&gt; list(atom())
+        |  %% @doc Unloads all mocked modules from memory.
+        |  %%
+        |  %% The function returns the list of mocked modules that were unloaded
+        |  %% in the process.
+        |  -spec unload() -&gt; [atom()].
+     1..|  unload() -&gt; lists:foldl(fun unload_if_mocked/2, [], registered()).
+        |  
+        |  %% @spec unload(Mod:: atom() | list(atom())) -&gt; ok
+        |  %% @doc Unload a mocked module or a list of mocked modules.
+        |  %%
+        |  %% This will purge and delete the module(s) from the Erlang virtual
+        |  %% machine. If the mocked module(s) replaced an existing module, this
+        |  %% module will still be in the Erlang load path and can be loaded
+        |  %% manually or when called.
+        |  -spec unload(Mods:: atom() | [atom()]) -&gt; ok.
+    98..|  unload(Mod) when is_atom(Mod) -&gt; call(Mod, stop), wait_for_exit(Mod);
+     5..|  unload(Mods) when is_list(Mods) -&gt; lists:foreach(fun unload/1, Mods), ok.
+        |  
+        |  %% @spec called(Mod:: atom(), Fun:: atom(), Args:: list(term())) -&gt; boolean()
+        |  %% @doc Returns whether `Mod:Func' has been called with `Args'.
+        |  %%
+        |  %% @equiv called(Mod, Fun, Args, '_')
+        |  called(Mod, Fun, Args) -&gt;
+    11..|      has_call({Mod, Fun, Args}, meck:history(Mod)).
+        |  
+        |  %% @spec called(Mod:: atom(), Fun:: atom(), Args:: list(term()),
+        |  %%              Pid::pid()) -&gt; boolean()
+        |  %% @doc Returns whether `Pid' has called `Mod:Func' with `Args'.
+        |  %%
+        |  %% This will check the history for the module, `Mod', to determine
+        |  %% whether process `Pid' call the function, `Fun', with arguments, `Args'. If
+        |  %% so, this function returns true, otherwise false.
+        |  %%
+        |  %% Wildcards can be used, at any level in any term, by using the underscore
+        |  %% atom: ``'_' ''
+        |  %%
+        |  %% @see called/3
+        |  -spec called(Mod::atom(), Fun::atom(), Args::list(), Pid::pid()) -&gt; boolean().
+        |  called(Mod, Fun, Args, Pid) -&gt;
+     4..|      has_call({Mod, Fun, Args}, meck:history(Mod, Pid)).
+        |  
+        |  %% @spec num_calls(Mod:: atom(), Fun:: atom(), Args:: list(term()))
+        |  %% -&gt; non_neg_integer()
+        |  %% @doc Returns the number of times `Mod:Func' has been called with `Args'.
+        |  %%
+        |  %% @equiv num_calls(Mod, Fun, Args, '_')
+        |  num_calls(Mod, Fun, Args) -&gt;
+     5..|      num_calls({Mod, Fun, Args}, meck:history(Mod)).
+        |  
+        |  %% @spec num_calls(Mod:: atom(), Fun:: atom(), Args:: list(term()),
+        |  %%                 Pid::pid()) -&gt; non_neg_integer()
+        |  %% @doc Returns the number of times process `Pid' has called `Mod:Func'
+        |  %%      with `Args'.
+        |  %%
+        |  %% This will check the history for the module, `Mod', to determine how
+        |  %% many times process `Pid' has called the function, `Fun', with
+        |  %% arguments, `Args' and returns the result.
+        |  %%
+        |  %% @see num_calls/3
+        |  -spec num_calls(Mod::atom(), Fun::atom(), Args::list(), Pid::pid()) -&gt;
+        |      non_neg_integer().
+        |  num_calls(Mod, Fun, Args, Pid) -&gt;
+     4..|      num_calls({Mod, Fun, Args}, meck:history(Mod, Pid)).
+        |  
+        |  %%==============================================================================
+        |  %% Callback functions
+        |  %%==============================================================================
+        |  
+        |  %% @hidden
+        |  init([Mod, Options]) -&gt;
+   101..|      WasSticky = case proplists:is_defined(unstick, Options) of
+     5..|                      true -&gt; {module, Mod} = code:ensure_loaded(Mod),
+     5..|                              unstick_original(Mod);
+    96..|                      _    -&gt; false
+        |                  end,
+   101..|      NoPassCover = proplists:get_bool(no_passthrough_cover, Options),
+   101..|      Original = backup_original(Mod, NoPassCover),
+   101..|      process_flag(trap_exit, true),
+   101..|      Expects = init_expects(Mod, Options),
+   101..|      try
+   101..|          _Bin = meck_mod:compile_and_load_forms(to_forms(Mod, Expects)),
+   100..|          {ok, #state{mod = Mod, expects = Expects, original = Original,
+        |                      was_sticky = WasSticky}}
+        |      catch
+        |          exit:{error_loading_module, Mod, sticky_directory} -&gt;
+     1..|              {stop, module_is_sticky}
+        |      end.
+        |  
+        |  %% @hidden
+        |  handle_call({get_expect, Func, Arity}, _From, S) -&gt;
+   166..|      {Expect, NewExpects} = get_expect(S#state.expects, Func, Arity),
+   166..|      {reply, Expect, S#state{expects = NewExpects}};
+        |  handle_call({expect, Func, Expect}, _From, S) -&gt;
+    60..|      NewExpects = store_expect(S#state.mod, Func, Expect, S#state.expects),
+    60..|      {reply, ok, S#state{expects = NewExpects}};
+        |  handle_call({expect, Func, Arity, Result}, _From, S) -&gt;
+    30..|      NewExpects = store_expect(S#state.mod, Func, {anon, Arity, Result},
+        |                                S#state.expects),
+    30..|      {reply, ok, S#state{expects = NewExpects}};
+        |  handle_call({sequence, Func, Arity, Sequence}, _From, S) -&gt;
+     3..|      NewExpects = store_expect(S#state.mod, Func, {sequence, Arity, Sequence},
+        |                                S#state.expects),
+     3..|      {reply, ok, S#state{expects = NewExpects}};
+        |  handle_call({loop, Func, Arity, Loop}, _From, S) -&gt;
+     3..|      NewExpects = store_expect(S#state.mod, Func, {loop, Arity, Loop, Loop},
+        |                                S#state.expects),
+     3..|      {reply, ok, S#state{expects = NewExpects}};
+        |  handle_call({delete, Func, Arity}, _From, S) -&gt;
+     4..|      NewExpects = delete_expect(S#state.mod, Func, Arity, S#state.expects),
+     4..|      {reply, ok, S#state{expects = NewExpects}};
+        |  handle_call(history, _From, S) -&gt;
+    41..|      {reply, lists:reverse(S#state.history), S};
+        |  handle_call(invalidate, _From, S) -&gt;
+    11..|      {reply, ok, S#state{valid = false}};
+        |  handle_call(validate, _From, S) -&gt;
+    49..|      {reply, S#state.valid, S};
+        |  handle_call(stop, _From, S) -&gt;
+    97..|      {stop, normal, ok, S}.
+        |  
+        |  %% @hidden
+        |  handle_cast({add_history, Item}, S) -&gt;
+   184..|      {noreply, S#state{history = [Item| S#state.history]}};
+        |  handle_cast(_Msg, S)  -&gt;
+     1..|      {noreply, S}.
+        |  
+        |  %% @hidden
+   200..|  handle_info(_Info, S) -&gt; {noreply, S}.
+        |  
+        |  %% @hidden
+        |  terminate(_Reason, #state{mod = Mod, original = OriginalState,
+        |                            was_sticky = WasSticky}) -&gt;
+   100..|      export_original_cover(Mod, OriginalState),
+   100..|      cleanup(Mod),
+   100..|      restore_original(Mod, OriginalState, WasSticky),
+   100..|      ok.
+        |  
+        |  %% @hidden
+     1..|  code_change(_OldVsn, S, _Extra) -&gt; {ok, S}.
+        |  
+        |  %% @hidden
+        |  exec(Pid, Mod, Func, Arity, Args) -&gt;
+   166..|      Expect = call(Mod, {get_expect, Func, Arity}),
+   166..|      try Result = call_expect(Mod, Func, Expect, Args),
+   143..|          add_history(Pid, Mod, Func, Args, Result),
+   143..|          Result
+        |      catch
+        |          throw:Fun when is_function(Fun) -&gt;
+    12..|              case is_mock_exception(Fun) of
+    11..|                  true  -&gt; handle_mock_exception(Pid, Mod, Func, Fun, Args);
+     1..|                  false -&gt; invalidate_and_raise(Pid, Mod, Func, Args, throw, Fun)
+        |              end;
+        |          Class:Reason -&gt;
+    10..|              invalidate_and_raise(Pid, Mod, Func, Args, Class, Reason)
+        |      end.
+        |  
+        |  %%==============================================================================
+        |  %% Internal functions
+        |  %%==============================================================================
+        |  
+        |  %% --- Process functions -------------------------------------------------------
+        |  
+        |  start(Mod, Options) -&gt;
+   102..|      case proplists:is_defined(no_link, Options) of
+     2..|          true  -&gt; start(start, Mod, Options);
+   100..|          false -&gt; start(start_link, Mod, Options)
+        |      end.
+        |  
+        |  start(Func, Mod, Options) -&gt;
+   102..|      gen_server:Func({local, proc_name(Mod)}, ?MODULE, [Mod, Options], []).
+        |  
+   164..|  cast(Mod, Msg) -&gt; gen_server(cast, Mod, Msg).
+   466..|  call(Mod, Msg) -&gt; gen_server(call, Mod, Msg).
+        |  
+        |  gen_server(Func, Mod, Msg) -&gt;
+   630..|      Name = proc_name(Mod),
+   630..|      try gen_server:Func(Name, Msg)
+     2..|      catch exit:_Reason -&gt; erlang:error({not_mocked, Mod}) end.
+        |  
+   859..|  proc_name(Name) -&gt; list_to_atom(atom_to_list(Name) ++ "_meck").
+        |  
+   244..|  original_name(Name) -&gt; list_to_atom(atom_to_list(Name) ++ "_meck_original").
+        |  
+        |  wait_for_exit(Mod) -&gt;
+    97..|      MonitorRef = erlang:monitor(process, proc_name(Mod)),
+    97..|      receive {'DOWN', MonitorRef, _Type, _Object, _Info} -&gt; ok end.
+        |  
+        |  unload_if_mocked(P, L) when is_atom(P) -&gt;
+    40..|      unload_if_mocked(atom_to_list(P), L);
+        |  unload_if_mocked(P, L) when length(P) &gt; 5 -&gt;
+    37..|      case lists:split(length(P) - 5, P) of
+        |          {Name, "_meck"} -&gt;
+     5..|              Mocked = list_to_existing_atom(Name),
+     5..|              try
+     5..|                  unload(Mocked)
+        |              catch error:{not_mocked, Mocked} -&gt;
+<font color=red>     0..|                      ok</font>
+        |              end,
+     5..|              [Mocked|L];
+        |          _Else -&gt;
+    32..|              L
+        |      end;
+        |  unload_if_mocked(_P, L) -&gt;
+     3..|      L.
+        |  
+        |  %% --- Mock handling -----------------------------------------------------------
+        |  
+        |  valid_expect(M, F, A) -&gt;
+    32..|      case expect_type(M, F, A) of
+     1..|          autogenerated -&gt; erlang:error({cannot_mock_autogenerated, {M, F, A}});
+     1..|          builtin -&gt; erlang:error({cannot_mock_builtin, {M, F, A}});
+    30..|          normal -&gt; ok
+        |      end.
+        |  
+        |  init_expects(Mod, Options) -&gt;
+   101..|      case proplists:get_value(passthrough, Options, false) andalso exists(Mod) of
+     8..|          true -&gt; dict:from_list([{FA, passthrough} || FA &lt;- exports(Mod)]);
+    93..|          _    -&gt; dict:new()
+        |      end.
+        |  
+        |  
+        |  get_expect(Expects, Func, Arity) -&gt;
+   166..|      case e_fetch(Expects, Func, Arity) of
+        |          {sequence, Arity, [Result]} -&gt;
+    18..|              {{sequence, Arity, Result}, Expects};
+        |          {sequence, Arity, [Result|Rest]} -&gt;
+    12..|              {{sequence, Arity, Result},
+        |               e_store(Expects, Func, {sequence, Arity, Rest})};
+        |          {loop, Arity, [Result], Loop} -&gt;
+    15..|              {{loop, Arity, Result},
+        |               e_store(Expects, Func, {loop, Arity, Loop, Loop})};
+        |          {loop, Arity, [Result|Rest], Loop} -&gt;
+    60..|              {{loop, Arity, Result},
+        |               e_store(Expects, Func, {loop, Arity, Rest, Loop})};
+        |          Other -&gt;
+    61..|              {Other, Expects}
+        |      end.
+        |  
+        |  store_expect(Mod, Func, Expect, Expects) -&gt;
+    96..|      change_expects(fun e_store/3, Mod, Func, Expect, Expects).
+        |  
+        |  delete_expect(Mod, Func, Arity, Expects) -&gt;
+     4..|      change_expects(fun e_delete/3, Mod, Func, Arity, Expects).
+        |  
+        |  change_expects(Op, Mod, Func, Value, Expects) -&gt;
+   100..|      NewExpects = Op(Expects, Func, Value),
+   100..|      _Bin = meck_mod:compile_and_load_forms(to_forms(Mod, NewExpects)),
+   100..|      NewExpects.
+        |  
+        |  e_store(Expects, Func, Expect) -&gt;
+   183..|      dict:store({Func, arity(Expect)}, Expect, Expects).
+        |  
+        |  e_fetch(Expects, Func, Arity) -&gt;
+   166..|      dict:fetch({Func, Arity}, Expects).
+        |  
+        |  e_delete(Expects, Func, Arity) -&gt;
+     4..|      dict:erase({Func, Arity}, Expects).
+        |  
+        |  %% --- Code generation ---------------------------------------------------------
+        |  
+        |  func(Mod, {Func, Arity}, {anon, Arity, Result}) -&gt;
+    31..|     case contains_opaque(Result) of
+        |         true -&gt;
+     1..|              func_exec(Mod, Func, Arity);
+        |         false -&gt;
+    30..|             func_native(Mod, Func, Arity, Result)
+        |     end;
+        |  func(Mod, {Func, Arity}, _Expect) -&gt;
+   185..|      func_exec(Mod, Func, Arity).
+        |  
+        |  func_exec(Mod, Func, Arity) -&gt;
+   186..|      Args = args(Arity),
+   186..|      ?function(Func, Arity,
+        |                [?clause(Args,
+        |                         [?call(?MODULE, exec,
+        |                                [?call(erlang, self, []),
+        |                                 ?atom(Mod),
+        |                                 ?atom(Func),
+        |                                 ?integer(Arity),
+        |                                 list(Args)])])]).
+        |  
+        |  func_native(Mod, Func, Arity, Result) -&gt;
+    30..|      Args = args(Arity),
+    30..|      AbsResult = erl_parse:abstract(Result),
+    30..|      ?function(
+        |         Func, Arity,
+        |         [?clause(
+        |             Args,
+        |             [?call(gen_server, cast,
+        |                    [?atom(proc_name(Mod)),
+        |                     ?tuple([?atom(add_history),
+        |                             ?tuple([?call(erlang, self, []),
+        |                                     ?tuple([?atom(Mod), ?atom(Func),
+        |                                             list(Args)]),
+        |                                     AbsResult])])]),
+        |              AbsResult])]).
+        |  
+        |  contains_opaque(Term) when is_pid(Term); is_port(Term); is_function(Term) -&gt;
+     1..|      true;
+        |  contains_opaque(Term) when is_list(Term) -&gt;
+     1..|      lists:any(fun contains_opaque/1, Term);
+        |  contains_opaque(Term) when is_tuple(Term) -&gt;
+     1..|      lists:any(fun contains_opaque/1, tuple_to_list(Term));
+        |  contains_opaque(_Term) -&gt;
+    32..|      false.
+        |  
+        |  
+        |  to_forms(Mod, Expects) -&gt;
+   201..|      {Exports, Functions} = functions(Mod, Expects),
+   201..|      [?attribute(module, Mod)] ++ Exports ++ Functions.
+        |  
+        |  functions(Mod, Expects) -&gt;
+   201..|      dict:fold(fun(Export, Expect, {Exports, Functions}) -&gt;
+   216..|                        {[?attribute(export, [Export])|Exports],
+        |                         [func(Mod, Export, Expect)|Functions]}
+        |                end, {[], []}, Expects).
+        |  
+    93..|  args(0)     -&gt; [];
+   123..|  args(Arity) -&gt; [?var(var_name(N)) || N &lt;- lists:seq(1, Arity)].
+        |  
+   216..|  list([])    -&gt; {nil, ?LINE};
+   225..|  list([H|T]) -&gt; {cons, ?LINE, H, list(T)}.
+        |  
+   225..|  var_name(A) -&gt; list_to_atom("A"++integer_to_list(A)).
+        |  
+        |  arity({anon, Arity, _Result}) -&gt;
+    30..|      Arity;
+        |  arity({sequence, Arity, _Sequence}) -&gt;
+    15..|      Arity;
+        |  arity({loop, Arity, _Current, _Loop}) -&gt;
+    78..|      Arity;
+        |  arity(Fun) when is_function(Fun) -&gt;
+    60..|      {arity, Arity} = erlang:fun_info(Fun, arity),
+    60..|      Arity.
+        |  
+        |  %% --- Execution utilities -----------------------------------------------------
+        |  
+        |  is_local_function(Fun) -&gt;
+    12..|      {module, Module} = erlang:fun_info(Fun, module),
+    12..|      ?MODULE == Module.
+        |  
+        |  handle_mock_exception(Pid, Mod, Func, Fun, Args) -&gt;
+    11..|      case Fun() of
+        |          {exception, Class, Reason} -&gt;
+        |              % exception created with the mock:exception function,
+        |              % do not invalidate Mod
+     8..|              raise(Pid, Mod, Func, Args, Class, Reason);
+        |          {passthrough, PassthroughArgs} -&gt;
+        |              % call_original(Args) called from mock function
+     3..|              Result = apply(original_name(Mod), Func, PassthroughArgs),
+     2..|              add_history(Pid, Mod, Func, PassthroughArgs, Result),
+     2..|              Result
+        |      end.
+        |  
+        |  -spec invalidate_and_raise(_, _, _, _, _, _) -&gt; no_return().
+        |  invalidate_and_raise(Pid, Mod, Func, Args, Class, Reason) -&gt;
+    11..|      call(Mod, invalidate),
+    11..|      raise(Pid, Mod, Func, Args, Class, Reason).
+        |  
+        |  raise(Pid, Mod, Func, Args, Class, Reason) -&gt;
+    19..|      Stacktrace = inject(Mod, Func, Args, erlang:get_stacktrace()),
+    19..|      add_history(Pid, Mod, Func, Args, Class, Reason, Stacktrace),
+    19..|      erlang:raise(Class, Reason, Stacktrace).
+        |  
+     8..|  mock_exception_fun(Class, Reason) -&gt; fun() -&gt; {exception, Class, Reason} end.
+        |  
+     3..|  passthrough_fun(Args) -&gt; fun() -&gt; {passthrough, Args} end.
+        |  
+        |  call_expect(_Mod, _Func, {_Type, Arity, Return}, VarList)
+        |    when Arity == length(VarList) -&gt;
+   106..|      Return;
+        |  call_expect(Mod, Func, passthrough, VarList) -&gt;
+    10..|      apply(original_name(Mod), Func, VarList);
+        |  call_expect(_Mod, _Func, Fun, VarList) when is_function(Fun) -&gt;
+    50..|      apply(Fun, VarList).
+        |  
+        |  inject(_Mod, _Func, _Args, []) -&gt;
+<font color=red>     0..|      [];</font>
+        |  inject(Mod, Func, Args, [{meck, exec, _Arity} = Meck|Stack]) -&gt;
+    19..|      [Meck, {Mod, Func, Args}|Stack];
+        |  inject(Mod, Func, Args, [{meck, exec, _Arity, _Location} = Meck|Stack]) -&gt;
+<font color=red>     0..|      [Meck, {Mod, Func, Args}|Stack];</font>
+        |  inject(Mod, Func, Args, [H|Stack]) -&gt;
+    19..|      [H|inject(Mod, Func, Args, Stack)].
+        |  
+    12..|  is_mock_exception(Fun) -&gt; is_local_function(Fun).
+        |  
+        |  %% --- Original module handling ------------------------------------------------
+        |  
+        |  backup_original(Module, NoPassCover) -&gt;
+   101..|      Cover = get_cover_state(Module),
+   101..|      try
+   101..|          Forms = meck_mod:abstract_code(meck_mod:beam_file(Module)),
+    17..|          NewName = original_name(Module),
+    17..|          CompileOpts = meck_mod:compile_options(meck_mod:beam_file(Module)),
+    17..|          Renamed = meck_mod:rename_module(Forms, NewName),
+    17..|          Binary = meck_mod:compile_and_load_forms(Renamed, CompileOpts),
+        |  
+        |          %% At this point we care about `Binary' if and only if we want
+        |          %% to recompile it to enable cover on the original module code
+        |          %% so that we can still collect cover stats on functions that
+        |          %% have not been mocked.  Below are the different values
+        |          %% passed back along with `Cover'.
+        |          %%
+        |          %% `no_passthrough_cover' - there is no coverage on the
+        |          %% original module OR passthrough coverage has been disabled
+        |          %% via the `no_passthrough_cover' option
+        |          %%
+        |          %% `no_binary' - something went wrong while trying to compile
+        |          %% the original module in `backup_original'
+        |          %%
+        |          %% Binary - a `binary()' of the compiled code for the original
+        |          %% module that is being mocked, this needs to be passed around
+        |          %% so that it can be passed to Cover later.  There is no way
+        |          %% to use the code server to access this binary without first
+        |          %% saving it to disk.  Instead, it's passed around as state.
+    17..|          if (Cover == false) orelse NoPassCover -&gt;
+    10..|                  Binary2 = no_passthrough_cover;
+        |             true -&gt;
+     7..|                  Binary2 = Binary,
+     7..|                  meck_cover:compile_beam(NewName, Binary2)
+        |          end,
+    17..|          {Cover, Binary2}
+        |      catch
+        |          throw:{object_code_not_found, _Module} -&gt;
+    82..|              {Cover, no_binary}; % TODO: What to do here?
+        |          throw:no_abstract_code                 -&gt;
+     2..|              {Cover, no_binary} % TODO: What to do here?
+        |      end.
+        |  
+        |  restore_original(Mod, {false, _}, WasSticky) -&gt;
+    91..|      restick_original(Mod, WasSticky),
+    91..|      ok;
+        |  restore_original(Mod, OriginalState={{File, Data, Options},_}, WasSticky) -&gt;
+     9..|      case filename:extension(File) of
+        |          ".erl" -&gt;
+     6..|              {ok, Mod} = cover:compile_module(File, Options);
+        |          ".beam" -&gt;
+     3..|              cover:compile_beam(File)
+        |      end,
+     9..|      restick_original(Mod, WasSticky),
+     9..|      import_original_cover(Mod, OriginalState),
+     9..|      ok = cover:import(Data),
+     9..|      ok = file:delete(Data),
+     9..|      ok.
+        |  
+        |  %% @doc Import the cover data for `&lt;name&gt;_meck_original' but since it
+        |  %% was modified by `export_original_cover' it will count towards
+        |  %% `&lt;name&gt;'.
+        |  import_original_cover(Mod, {_,Bin}) when is_binary(Bin) -&gt;
+     7..|      OriginalData = atom_to_list(original_name(Mod)) ++ ".coverdata",
+     7..|      ok = cover:import(OriginalData),
+     7..|      ok = file:delete(OriginalData);
+        |  import_original_cover(_, _) -&gt;
+     2..|      ok.
+        |  
+        |  %% @doc Export the cover data for `&lt;name&gt;_meck_original' and modify
+        |  %% the data so it can be imported under `&lt;name&gt;'.
+        |  export_original_cover(Mod, {_, Bin}) when is_binary(Bin) -&gt;
+     7..|      OriginalMod = original_name(Mod),
+     7..|      File = atom_to_list(OriginalMod) ++ ".coverdata",
+     7..|      ok = cover:export(File, OriginalMod),
+     7..|      ok = meck_cover:rename_module(File, Mod);
+        |  export_original_cover(_, _) -&gt;
+    93..|      ok.
+        |  
+        |  
+     5..|  unstick_original(Module) -&gt; unstick_original(Module, code:is_sticky(Module)).
+        |  
+     4..|  unstick_original(Module, true) -&gt; code:unstick_mod(Module);
+     1..|  unstick_original(_,_) -&gt; false.
+        |  
+        |  restick_original(Module, true) -&gt;
+     4..|      code:stick_mod(Module),
+     4..|      {module, Module} = code:ensure_loaded(Module),
+     4..|      ok;
+    96..|  restick_original(_,_) -&gt; ok.
+        |  
+   101..|  get_cover_state(Module) -&gt; get_cover_state(Module, cover:is_compiled(Module)).
+        |  
+        |  get_cover_state(Module, {file, File}) -&gt;
+     9..|      Data = atom_to_list(Module) ++ ".coverdata",
+     9..|      ok = cover:export(Data, Module),
+     9..|      CompileOptions =
+        |          try
+     9..|              meck_mod:compile_options(meck_mod:beam_file(Module))
+        |          catch
+<font color=red>     0..|              throw:{object_code_not_found, _Module} -&gt; []</font>
+        |          end,
+     9..|      {File, Data, CompileOptions};
+        |  get_cover_state(_Module, _IsCompiled) -&gt;
+    92..|      false.
+        |  
+        |  exists(Module) -&gt;
+    12..|      code:which(Module) /= non_existing.
+        |  
+        |  exports(M) -&gt;
+     8..|      [ FA ||  FA = {F, A}  &lt;- M:module_info(exports),
+   102..|               normal == expect_type(M, F, A)].
+        |  
+        |  %% Functions we should not create expects for (auto-generated and BIFs)
+     9..|  expect_type(_, module_info, 0) -&gt; autogenerated;
+     8..|  expect_type(_, module_info, 1) -&gt; autogenerated;
+   117..|  expect_type(M, F, A) -&gt; expect_type(erlang:is_builtin(M, F, A)).
+        |  
+     4..|  expect_type(true)  -&gt; builtin;
+   113..|  expect_type(false) -&gt; normal.
+        |  
+        |  cleanup(Mod) -&gt;
+   100..|      code:purge(Mod),
+   100..|      code:delete(Mod),
+   100..|      code:purge(original_name(Mod)),
+   100..|      code:delete(original_name(Mod)).
+        |  
+        |  %% --- History utilities -------------------------------------------------------
+        |  
+        |  add_history(Pid, Mod, Func, Args, Result) -&gt;
+   145..|      add_history(Mod, {Pid, {Mod, Func, Args}, Result}).
+        |  add_history(Pid, Mod, Func, Args, Class, Reason, Stacktrace) -&gt;
+    19..|      add_history(Mod, {Pid, {Mod, Func, Args}, Class, Reason, Stacktrace}).
+        |  
+        |  add_history(Mod, Item) -&gt;
+   164..|      cast(Mod, {add_history, Item}).
+        |  
+        |  has_call(MFA, History) -&gt;
+    15..|      [] =/= match_history(match_mfa(MFA), History).
+        |  
+        |  num_calls(MFA, History) -&gt;
+     9..|      length(match_history(match_mfa(MFA), History)).
+        |  
+        |  match_history(MatchSpec, History) -&gt;
+    35..|      MS = ets:match_spec_compile(MatchSpec),
+    35..|      ets:match_spec_run(History, MS).
+        |  
+    24..|  match_mfa(MFA) -&gt; match_mfa(MFA, '_').
+        |  
+        |  match_mfa(MFA, Pid) -&gt;
+    35..|      [{{Pid, MFA, '_'}, [], ['$_']},
+        |       {{Pid, MFA, '_', '_', '_'}, [], ['$_']}].
+</pre>
+</body>
+</html>

File extern/meck/.eunit/meck.beam

Binary file added.

File extern/meck/.eunit/meck.erl

+%%==============================================================================
+%% Copyright 2011 Adam Lindberg & Erlang Solutions Ltd.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%==============================================================================
+
+%% @author Adam Lindberg <eproxus@gmail.com>
+%% @copyright 2011, Adam Lindberg & Erlang Solutions Ltd
+%% @doc Module mocking library for Erlang.
+
+-module(meck).
+-behaviour(gen_server).
+
+%% Interface exports
+-export([new/1]).
+-export([new/2]).
+-export([expect/3]).
+-export([expect/4]).
+-export([sequence/4]).
+-export([loop/4]).
+-export([delete/3]).
+-export([exception/2]).
+-export([passthrough/1]).
+-export([history/1]).
+-export([history/2]).
+-export([validate/1]).
+-export([unload/0]).
+-export([unload/1]).
+-export([called/3]).
+-export([called/4]).
+-export([num_calls/3]).
+-export([num_calls/4]).
+
+%% Callback exports
+-export([init/1]).
+-export([handle_call/3]).
+-export([handle_cast/2]).
+-export([handle_info/2]).
+-export([terminate/2]).
+-export([code_change/3]).
+-export([exec/5]).
+
+%% Types
+%% @type meck_mfa() = {Mod::atom(), Func::atom(), Args::list(term())}.
+%% Module, function and arguments that the mock module got called with.
+-type meck_mfa() :: {Mod::atom(), Func::atom(), Args::[term()]}.
+
+%% @type history() = [{pid(), meck_mfa(), Result::term()}
+%%                     | {pid(), meck_mfa(), Class:: exit | error | throw,
+%%                        Reason::term(), Stacktrace::list(mfa())}].
+%% History is a list of either successful function calls with a returned
+%% result or function calls that resulted in an exception with a type,
+%% reason and a stack trace. Each tuple begins with the pid of the process
+%% that made the call to the function.
+-type history() :: [{pid(), meck_mfa(), Result::term()}
+                    | {pid(), meck_mfa(), Class:: exit | error | throw,
+                       Reason::term(), Stacktrace::[mfa()]}].
+
+%% Records
+-record(state, {mod :: atom(),
+                expects :: dict(),
+                valid = true :: boolean(),
+                history = [] :: history(),
+                original :: term(),
+                was_sticky :: boolean()}).
+
+%% Includes
+-include("meck_abstract.hrl").
+
+%%==============================================================================
+%% Interface exports
+%%==============================================================================
+
+%% @spec new(Mod:: atom() | list(atom())) -> ok
+%% @equiv new(Mod, [])
+-spec new(Mod:: atom() | [atom()]) -> ok.
+new(Mod) when is_atom(Mod) -> new(Mod, []);
+new(Mod) when is_list(Mod) -> lists:foreach(fun new/1, Mod), ok.
+
+%% @spec new(Mod:: atom() | list(atom()), Options::list(term())) -> ok
+%% @doc Creates new mocked module(s).
+%%
+%% This replaces the current version (if any) of the modules in `Mod'
+%% with an empty module.
+%%
+%% Since this library is intended to use from test code, this
+%% function links a process for each mock to the calling process.
+%%
+%% The valid options are:
+%% <dl>
+%%   <dt>`passthrough'</dt><dd>Retains the original functions, if not
+%%                             mocked by meck.</dd>
+%%   <dt>`no_link'</dt>    <dd>Does not link the meck process to the caller
+%%                             process (needed for using meck in rpc calls).
+%%                         </dd>
+%%   <dt>`unstick'</dt>    <dd>Unstick the module to be mocked (e.g. needed
+%%                             for using meck with kernel and stdlib modules).
+%%                         </dd>
+%%   <dt>`no_passthrough_cover'</dt><dd>If cover is enabled on the module to be
+%%                                      mocked then meck will continue to
+%%                                      capture coverage on passthrough calls.
+%%                                      This option allows you to disable that
+%%                                      feature if it causes problems.
+%%                                  </dd>
+%% </dl>
+-spec new(Mod:: atom() | [atom()], Options::[term()]) -> ok.
+new(Mod, Options) when is_atom(Mod), is_list(Options) ->
+    case start(Mod, Options) of
+        {ok, _Pid} -> ok;
+        {error, Reason} -> erlang:error(Reason, [Mod, Options])
+    end;
+new(Mod, Options) when is_list(Mod) ->
+    lists:foreach(fun(M) -> new(M, Options) end, Mod),
+    ok.
+
+%% @spec expect(Mod:: atom() | list(atom()), Func::atom(), Expect::fun()) -> ok
+%% @doc Add expectation for a function `Func' to the mocked modules `Mod'.
+%%
+%% An expectation is a fun that is executed whenever the function
+%% `Func' is called.
+%%
+%% It affects the validation status of the mocked module(s). If an
+%% expectation is called with the wrong number of arguments or invalid
+%% arguments the mock module(s) is invalidated. It is also invalidated if
+%% an unexpected exception occurs.
+-spec expect(Mod:: atom() | [atom()], Func::atom(), Expect::fun()) -> ok.
+expect(Mod, Func, Expect)
+  when is_atom(Mod), is_atom(Func), is_function(Expect) ->
+    call(Mod, {expect, Func, Expect});
+expect(Mod, Func, Expect) when is_list(Mod) ->
+    lists:foreach(fun(M) -> expect(M, Func, Expect) end, Mod),
+    ok.
+
+%% @spec expect(Mod:: atom() | list(atom()), Func::atom(),
+%%              Arity::pos_integer(), Result::term()) -> ok
+%% @doc Adds an expectation with the supplied arity and return value.
+%%
+%% This creates an expectation which takes `Arity' number of functions
+%% and always returns `Result'.
+%%
+%% @see expect/3.
+-spec expect(Mod:: atom() | [atom()], Func::atom(),
+             Arity::pos_integer(), Result::term()) -> ok.
+expect(Mod, Func, Arity, Result)
+  when is_atom(Mod), is_atom(Func), is_integer(Arity), Arity >= 0 ->
+    valid_expect(Mod, Func, Arity),
+    call(Mod, {expect, Func, Arity, Result});
+expect(Mod, Func, Arity, Result) when is_list(Mod) ->
+    lists:foreach(fun(M) -> expect(M, Func, Arity, Result) end, Mod),
+    ok.
+
+%% @spec sequence(Mod:: atom() | list(atom()), Func::atom(),
+%%                Arity::pos_integer(), Sequence::[term()]) -> ok
+%% @doc Adds an expectation which returns a value from `Sequence'
+%% until exhausted.
+%%
+%% This creates an expectation which takes `Arity' number of arguments
+%% and returns one element from `Sequence' at a time. Thus, calls to
+%% this expect will exhaust the list of return values in order until
+%% the last value is reached. That value is then returned for all
+%% subsequent calls.
+-spec sequence(Mod:: atom() | [atom()], Func::atom(),
+               Arity::pos_integer(), Sequence::[term()]) -> ok.
+sequence(Mod, Func, Arity, Sequence)
+  when is_atom(Mod), is_atom(Func), is_integer(Arity), Arity >= 0 ->
+    call(Mod, {sequence, Func, Arity, Sequence});
+sequence(Mod, Func, Arity, Sequence) when is_list(Mod) ->
+    lists:foreach(fun(M) -> sequence(M, Func, Arity, Sequence) end, Mod),
+    ok.
+
+%% @spec loop(Mod:: atom() | list(atom()), Func::atom(),
+%%            Arity::pos_integer(), Loop::[term()]) -> ok
+%% @doc Adds an expectation which returns a value from `Loop'
+%% infinitely.
+%%
+%% This creates an expectation which takes `Arity' number of arguments
+%% and returns one element from `Loop' at a time. Thus, calls to this
+%% expect will return one element at a time from the list and will
+%% restart at the first element when the end is reached.
+-spec loop(Mod:: atom() | [atom()], Func::atom(),
+           Arity::pos_integer(), Loop::[term()]) -> ok.
+loop(Mod, Func, Arity, Loop)
+  when is_atom(Mod), is_atom(Func), is_integer(Arity), Arity >= 0 ->
+    call(Mod, {loop, Func, Arity, Loop});
+loop(Mod, Func, Arity, Loop) when is_list(Mod) ->
+    lists:foreach(fun(M) -> loop(M, Func, Arity, Loop) end, Mod),
+    ok.
+
+%% @spec delete(Mod:: atom() | list(atom()), Func::atom(),
+%%              Arity::pos_integer()) -> ok
+%% @doc Deletes an expectation.
+%%
+%% Deletes the expectation for the function `Func' with the matching
+%% arity `Arity'.
+-spec delete(Mod:: atom() | [atom()], Func::atom(), Arity::pos_integer()) ->
+    ok.
+delete(Mod, Func, Arity)
+  when is_atom(Mod), is_atom(Func), Arity >= 0 ->
+    call(Mod, {delete, Func, Arity});
+delete(Mod, Func, Arity) when is_list(Mod) ->
+    lists:foreach(fun(M) -> delete(M, Func, Arity) end, Mod),
+    ok.
+
+%% @spec exception(Class:: throw | error | exit, Reason::term()) -> no_return()
+%% @doc Throws an expected exception inside an expect fun.
+%%
+%% This exception will get thrown without invalidating the mocked
+%% module. That is, the code using the mocked module is expected to
+%% handle this exception.
+%%
+%% <em>Note: this code should only be used inside an expect fun.</em>
+-spec exception(Class:: throw | error | exit, Reason::term()) -> no_return().
+exception(Class, Reason) when Class == throw; Class == error; Class == exit ->
+    throw(mock_exception_fun(Class, Reason)).
+
+%% @spec passthrough(Args::list(term())) -> no_return()
+%% @doc Calls the original function (if existing) inside an expectation fun.
+%%
+%% This call does not return, thus everything after this call inside
+%% an expectation fun will be ignored.
+%%
+%% <em>Note: this code should only be used inside an expect fun.</em>
+-spec passthrough(Args::[term()]) -> no_return().
+passthrough(Args) -> throw(passthrough_fun(Args)).
+
+%% @spec validate(Mod:: atom() | list(atom())) -> boolean()
+%% @doc Validate the state of the mock module(s).
+%%
+%% The function returns `true' if the mocked module(s) has been used
+%% according to its expectations. It returns `false' if a call has
+%% failed in some way. Reasons for failure are wrong number of
+%% arguments or non-existing function (undef), wrong arguments
+%% (function clause) or unexpected exceptions.
+%%
+%% Use the {@link history/1} or {@link history/2} function to analyze errors.
+-spec validate(Mod:: atom() | [atom()]) -> boolean().
+validate(Mod) when is_atom(Mod) ->
+    call(Mod, validate);
+validate(Mod) when is_list(Mod) ->
+    not lists:member(false, [validate(M) || M <- Mod]).
+
+%% @spec history(Mod::atom()) -> history()
+%% @doc Return the call history of the mocked module for all processes.
+%%
+%% @equiv history(Mod, '_')
+-spec history(Mod::atom()) -> history().
+history(Mod) when is_atom(Mod) -> call(Mod, history).
+
+%% @spec history(Mod::atom(), Pid::pid()) -> history()
+%% @doc Return the call history of the mocked module for the specified process.
+%%
+%% Returns a list of calls to the mocked module and their results for
+%% the specified `Pid'.  Results can be either normal Erlang terms or
+%% exceptions that occurred.
+%%
+%% @see history/1
+%% @see called/3
+%% @see called/4
+%% @see num_calls/3
+%% @see num_calls/4
+-spec history(Mod::atom(), Pid:: pid() | '_') -> history().
+history(Mod, Pid) when is_atom(Mod), is_pid(Pid) orelse Pid == '_' -> 
+    match_history(match_mfa('_', Pid), call(Mod, history)).
+
+%% @spec unload() -> list(atom())
+%% @doc Unloads all mocked modules from memory.
+%%
+%% The function returns the list of mocked modules that were unloaded
+%% in the process.
+-spec unload() -> [atom()].
+unload() -> lists:foldl(fun unload_if_mocked/2, [], registered()).
+
+%% @spec unload(Mod:: atom() | list(atom())) -> ok
+%% @doc Unload a mocked module or a list of mocked modules.
+%%
+%% This will purge and delete the module(s) from the Erlang virtual
+%% machine. If the mocked module(s) replaced an existing module, this
+%% module will still be in the Erlang load path and can be loaded
+%% manually or when called.
+-spec unload(Mods:: atom() | [atom()]) -> ok.
+unload(Mod) when is_atom(Mod) -> call(Mod, stop), wait_for_exit(Mod);
+unload(Mods) when is_list(Mods) -> lists:foreach(fun unload/1, Mods), ok.
+
+%% @spec called(Mod:: atom(), Fun:: atom(), Args:: list(term())) -> boolean()
+%% @doc Returns whether `Mod:Func' has been called with `Args'.
+%%
+%% @equiv called(Mod, Fun, Args, '_')
+called(Mod, Fun, Args) ->
+    has_call({Mod, Fun, Args}, meck:history(Mod)).
+
+%% @spec called(Mod:: atom(), Fun:: atom(), Args:: list(term()),
+%%              Pid::pid()) -> boolean()
+%% @doc Returns whether `Pid' has called `Mod:Func' with `Args'.
+%%
+%% This will check the history for the module, `Mod', to determine
+%% whether process `Pid' call the function, `Fun', with arguments, `Args'. If
+%% so, this function returns true, otherwise false.
+%%
+%% Wildcards can be used, at any level in any term, by using the underscore
+%% atom: ``'_' ''
+%%
+%% @see called/3
+-spec called(Mod::atom(), Fun::atom(), Args::list(), Pid::pid()) -> boolean().
+called(Mod, Fun, Args, Pid) ->
+    has_call({Mod, Fun, Args}, meck:history(Mod, Pid)).
+
+%% @spec num_calls(Mod:: atom(), Fun:: atom(), Args:: list(term()))
+%% -> non_neg_integer()
+%% @doc Returns the number of times `Mod:Func' has been called with `Args'.
+%%
+%% @equiv num_calls(Mod, Fun, Args, '_')
+num_calls(Mod, Fun, Args) ->
+    num_calls({Mod, Fun, Args}, meck:history(Mod)).
+
+%% @spec num_calls(Mod:: atom(), Fun:: atom(), Args:: list(term()),
+%%                 Pid::pid()) -> non_neg_integer()
+%% @doc Returns the number of times process `Pid' has called `Mod:Func'
+%%      with `Args'.
+%%
+%% This will check the history for the module, `Mod', to determine how
+%% many times process `Pid' has called the function, `Fun', with
+%% arguments, `Args' and returns the result.
+%%
+%% @see num_calls/3
+-spec num_calls(Mod::atom(), Fun::atom(), Args::list(), Pid::pid()) ->
+    non_neg_integer().
+num_calls(Mod, Fun, Args, Pid) ->
+    num_calls({Mod, Fun, Args}, meck:history(Mod, Pid)).
+
+%%==============================================================================
+%% Callback functions
+%%==============================================================================
+
+%% @hidden
+init([Mod, Options]) ->
+    WasSticky = case proplists:is_defined(unstick, Options) of
+                    true -> {module, Mod} = code:ensure_loaded(Mod),
+                            unstick_original(Mod);
+                    _    -> false
+                end,
+    NoPassCover = proplists:get_bool(no_passthrough_cover, Options),
+    Original = backup_original(Mod, NoPassCover),
+    process_flag(trap_exit, true),
+    Expects = init_expects(Mod, Options),
+    try
+        _Bin = meck_mod:compile_and_load_forms(to_forms(Mod, Expects)),
+        {ok, #state{mod = Mod, expects = Expects, original = Original,
+                    was_sticky = WasSticky}}
+    catch
+        exit:{error_loading_module, Mod, sticky_directory} ->
+            {stop, module_is_sticky}
+    end.
+
+%% @hidden
+handle_call({get_expect, Func, Arity}, _From, S) ->
+    {Expect, NewExpects} = get_expect(S#state.expects, Func, Arity),
+    {reply, Expect, S#state{expects = NewExpects}};
+handle_call({expect, Func, Expect}, _From, S) ->
+    NewExpects = store_expect(S#state.mod, Func, Expect, S#state.expects),
+    {reply, ok, S#state{expects = NewExpects}};
+handle_call({expect, Func, Arity, Result}, _From, S) ->
+    NewExpects = store_expect(S#state.mod, Func, {anon, Arity, Result},
+                              S#state.expects),
+    {reply, ok, S#state{expects = NewExpects}};
+handle_call({sequence, Func, Arity, Sequence}, _From, S) ->
+    NewExpects = store_expect(S#state.mod, Func, {sequence, Arity, Sequence},
+                              S#state.expects),
+    {reply, ok, S#state{expects = NewExpects}};
+handle_call({loop, Func, Arity, Loop}, _From, S) ->
+    NewExpects = store_expect(S#state.mod, Func, {loop, Arity, Loop, Loop},
+                              S#state.expects),
+    {reply, ok, S#state{expects = NewExpects}};
+handle_call({delete, Func, Arity}, _From, S) ->
+    NewExpects = delete_expect(S#state.mod, Func, Arity, S#state.expects),
+    {reply, ok, S#state{expects = NewExpects}};
+handle_call(history, _From, S) ->
+    {reply, lists:reverse(S#state.history), S};
+handle_call(invalidate, _From, S) ->
+    {reply, ok, S#state{valid = false}};
+handle_call(validate, _From, S) ->
+    {reply, S#state.valid, S};
+handle_call(stop, _From, S) ->
+    {stop, normal, ok, S}.
+
+%% @hidden
+handle_cast({add_history, Item}, S) ->
+    {noreply, S#state{history = [Item| S#state.history]}};
+handle_cast(_Msg, S)  ->
+    {noreply, S}.
+
+%% @hidden
+handle_info(_Info, S) -> {noreply, S}.
+
+%% @hidden
+terminate(_Reason, #state{mod = Mod, original = OriginalState,
+                          was_sticky = WasSticky}) ->
+    export_original_cover(Mod, OriginalState),
+    cleanup(Mod),
+    restore_original(Mod, OriginalState, WasSticky),
+    ok.
+
+%% @hidden
+code_change(_OldVsn, S, _Extra) -> {ok, S}.
+
+%% @hidden
+exec(Pid, Mod, Func, Arity, Args) ->
+    Expect = call(Mod, {get_expect, Func, Arity}),
+    try Result = call_expect(Mod, Func, Expect, Args),
+        add_history(Pid, Mod, Func, Args, Result),
+        Result
+    catch
+        throw:Fun when is_function(Fun) ->
+            case is_mock_exception(Fun) of
+                true  -> handle_mock_exception(Pid, Mod, Func, Fun, Args);
+                false -> invalidate_and_raise(Pid, Mod, Func, Args, throw, Fun)
+            end;
+        Class:Reason ->
+            invalidate_and_raise(Pid, Mod, Func, Args, Class, Reason)
+    end.
+
+%%==============================================================================
+%% Internal functions
+%%==============================================================================
+
+%% --- Process functions -------------------------------------------------------
+
+start(Mod, Options) ->
+    case proplists:is_defined(no_link, Options) of
+        true  -> start(start, Mod, Options);
+        false -> start(start_link, Mod, Options)
+    end.
+
+start(Func, Mod, Options) ->
+    gen_server:Func({local, proc_name(Mod)}, ?MODULE, [Mod, Options], []).
+
+cast(Mod, Msg) -> gen_server(cast, Mod, Msg).
+call(Mod, Msg) -> gen_server(call, Mod, Msg).
+
+gen_server(Func, Mod, Msg) ->
+    Name = proc_name(Mod),
+    try gen_server:Func(Name, Msg)
+    catch exit:_Reason -> erlang:error({not_mocked, Mod}) end.
+
+proc_name(Name) -> list_to_atom(atom_to_list(Name) ++ "_meck").
+
+original_name(Name) -> list_to_atom(atom_to_list(Name) ++ "_meck_original").
+
+wait_for_exit(Mod) ->
+    MonitorRef = erlang:monitor(process, proc_name(Mod)),
+    receive {'DOWN', MonitorRef, _Type, _Object, _Info} -> ok end.
+
+unload_if_mocked(P, L) when is_atom(P) ->
+    unload_if_mocked(atom_to_list(P), L);
+unload_if_mocked(P, L) when length(P) > 5 ->
+    case lists:split(length(P) - 5, P) of
+        {Name, "_meck"} ->
+            Mocked = list_to_existing_atom(Name),
+            try
+                unload(Mocked)
+            catch error:{not_mocked, Mocked} ->
+                    ok
+            end,
+            [Mocked|L];
+        _Else ->
+            L
+    end;
+unload_if_mocked(_P, L) ->
+    L.
+
+%% --- Mock handling -----------------------------------------------------------
+
+valid_expect(M, F, A) ->
+    case expect_type(M, F, A) of
+        autogenerated -> erlang:error({cannot_mock_autogenerated, {M, F, A}});
+        builtin -> erlang:error({cannot_mock_builtin, {M, F, A}});
+        normal -> ok
+    end.
+
+init_expects(Mod, Options) ->
+    case proplists:get_value(passthrough, Options, false) andalso exists(Mod) of
+        true -> dict:from_list([{FA, passthrough} || FA <- exports(Mod)]);
+        _    -> dict:new()
+    end.
+
+
+get_expect(Expects, Func, Arity) ->
+    case e_fetch(Expects, Func, Arity) of
+        {sequence, Arity, [Result]} ->
+            {{sequence, Arity, Result}, Expects};
+        {sequence, Arity, [Result|Rest]} ->
+            {{sequence, Arity, Result},
+             e_store(Expects, Func, {sequence, Arity, Rest})};
+        {loop, Arity, [Result], Loop} ->
+            {{loop, Arity, Result},
+             e_store(Expects, Func, {loop, Arity, Loop, Loop})};
+        {loop, Arity, [Result|Rest], Loop} ->
+            {{loop, Arity, Result},
+             e_store(Expects, Func, {loop, Arity, Rest, Loop})};
+        Other ->
+            {Other, Expects}
+    end.
+
+store_expect(Mod, Func, Expect, Expects) ->
+    change_expects(fun e_store/3, Mod, Func, Expect, Expects).
+
+delete_expect(Mod, Func, Arity, Expects) ->
+    change_expects(fun e_delete/3, Mod, Func, Arity, Expects).
+
+change_expects(Op, Mod, Func, Value, Expects) ->
+    NewExpects = Op(Expects, Func, Value),
+    _Bin = meck_mod:compile_and_load_forms(to_forms(Mod, NewExpects)),
+    NewExpects.
+
+e_store(Expects, Func, Expect) ->
+    dict:store({Func, arity(Expect)}, Expect, Expects).
+
+e_fetch(Expects, Func, Arity) ->
+    dict:fetch({Func, Arity}, Expects).
+
+e_delete(Expects, Func, Arity) ->
+    dict:erase({Func, Arity}, Expects).
+
+%% --- Code generation ---------------------------------------------------------
+
+func(Mod, {Func, Arity}, {anon, Arity, Result}) ->
+   case contains_opaque(Result) of
+       true ->
+            func_exec(Mod, Func, Arity);
+       false ->
+           func_native(Mod, Func, Arity, Result)
+   end;
+func(Mod, {Func, Arity}, _Expect) ->
+    func_exec(Mod, Func, Arity).
+
+func_exec(Mod, Func, Arity) ->
+    Args = args(Arity),
+    ?function(Func, Arity,
+              [?clause(Args,
+                       [?call(?MODULE, exec,
+                              [?call(erlang, self, []),
+                               ?atom(Mod),
+                               ?atom(Func),
+                               ?integer(Arity),
+                               list(Args)])])]).
+
+func_native(Mod, Func, Arity, Result) ->
+    Args = args(Arity),
+    AbsResult = erl_parse:abstract(Result),
+    ?function(
+       Func, Arity,
+       [?clause(
+           Args,
+           [?call(gen_server, cast,
+                  [?atom(proc_name(Mod)),
+                   ?tuple([?atom(add_history),
+                           ?tuple([?call(erlang, self, []),
+                                   ?tuple([?atom(Mod), ?atom(Func),
+                                           list(Args)]),
+                                   AbsResult])])]),
+            AbsResult])]).
+
+contains_opaque(Term) when is_pid(Term); is_port(Term); is_function(Term) ->
+    true;
+contains_opaque(Term) when is_list(Term) ->
+    lists:any(fun contains_opaque/1, Term);
+contains_opaque(Term) when is_tuple(Term) ->
+    lists:any(fun contains_opaque/1, tuple_to_list(Term));
+contains_opaque(_Term) ->
+    false.
+
+
+to_forms(Mod, Expects) ->
+    {Exports, Functions} = functions(Mod, Expects),
+    [?attribute(module, Mod)] ++ Exports ++ Functions.
+
+functions(Mod, Expects) ->
+    dict:fold(fun(Export, Expect, {Exports, Functions}) ->
+                      {[?attribute(export, [Export])|Exports],
+                       [func(Mod, Export, Expect)|Functions]}
+              end, {[], []}, Expects).
+
+args(0)     -> [];
+args(Arity) -> [?var(var_name(N)) || N <- lists:seq(1, Arity)].
+
+list([])    -> {nil, ?LINE};
+list([H|T]) -> {cons, ?LINE, H, list(T)}.
+
+var_name(A) -> list_to_atom("A"++integer_to_list(A)).
+
+arity({anon, Arity, _Result}) ->
+    Arity;
+arity({sequence, Arity, _Sequence}) ->
+    Arity;
+arity({loop, Arity, _Current, _Loop}) ->
+    Arity;
+arity(Fun) when is_function(Fun) ->
+    {arity, Arity} = erlang:fun_info(Fun, arity),
+    Arity.
+
+%% --- Execution utilities -----------------------------------------------------
+
+is_local_function(Fun) ->
+    {module, Module} = erlang:fun_info(Fun, module),
+    ?MODULE == Module.
+
+handle_mock_exception(Pid, Mod, Func, Fun, Args) ->
+    case Fun() of
+        {exception, Class, Reason} ->
+            % exception created with the mock:exception function,
+            % do not invalidate Mod
+            raise(Pid, Mod, Func, Args, Class, Reason);
+        {passthrough, PassthroughArgs} ->
+            % call_original(Args) called from mock function
+            Result = apply(original_name(Mod), Func, PassthroughArgs),
+            add_history(Pid, Mod, Func, PassthroughArgs, Result),
+            Result
+    end.
+
+-spec invalidate_and_raise(_, _, _, _, _, _) -> no_return().
+invalidate_and_raise(Pid, Mod, Func, Args, Class, Reason) ->
+    call(Mod, invalidate),
+    raise(Pid, Mod, Func, Args, Class, Reason).
+
+raise(Pid, Mod, Func, Args, Class, Reason) ->
+    Stacktrace = inject(Mod, Func, Args, erlang:get_stacktrace()),
+    add_history(Pid, Mod, Func, Args, Class, Reason, Stacktrace),
+    erlang:raise(Class, Reason, Stacktrace).
+
+mock_exception_fun(Class, Reason) -> fun() -> {exception, Class, Reason} end.
+
+passthrough_fun(Args) -> fun() -> {passthrough, Args} end.
+
+call_expect(_Mod, _Func, {_Type, Arity, Return}, VarList)
+  when Arity == length(VarList) ->
+    Return;
+call_expect(Mod, Func, passthrough, VarList) ->
+    apply(original_name(Mod), Func, VarList);
+call_expect(_Mod, _Func, Fun, VarList) when is_function(Fun) ->
+    apply(Fun, VarList).
+
+inject(_Mod, _Func, _Args, []) ->
+    [];
+inject(Mod, Func, Args, [{meck, exec, _Arity} = Meck|Stack]) ->
+    [Meck, {Mod, Func, Args}|Stack];
+inject(Mod, Func, Args, [{meck, exec, _Arity, _Location} = Meck|Stack]) ->
+    [Meck, {Mod, Func, Args}|Stack];
+inject(Mod, Func, Args, [H|Stack]) ->
+    [H|inject(Mod, Func, Args, Stack)].
+
+is_mock_exception(Fun) -> is_local_function(Fun).
+
+%% --- Original module handling ------------------------------------------------
+
+backup_original(Module, NoPassCover) ->
+    Cover = get_cover_state(Module),
+    try
+        Forms = meck_mod:abstract_code(meck_mod:beam_file(Module)),
+        NewName = original_name(Module),
+        CompileOpts = meck_mod:compile_options(meck_mod:beam_file(Module)),
+        Renamed = meck_mod:rename_module(Forms, NewName),
+        Binary = meck_mod:compile_and_load_forms(Renamed, CompileOpts),
+
+        %% At this point we care about `Binary' if and only if we want
+        %% to recompile it to enable cover on the original module code
+        %% so that we can still collect cover stats on functions that
+        %% have not been mocked.  Below are the different values
+        %% passed back along with `Cover'.
+        %%
+        %% `no_passthrough_cover' - there is no coverage on the
+        %% original module OR passthrough coverage has been disabled
+        %% via the `no_passthrough_cover' option
+        %%
+        %% `no_binary' - something went wrong while trying to compile
+        %% the original module in `backup_original'
+        %%
+        %% Binary - a `binary()' of the compiled code for the original
+        %% module that is being mocked, this needs to be passed around
+        %% so that it can be passed to Cover later.  There is no way
+        %% to use the code server to access this binary without first
+        %% saving it to disk.  Instead, it's passed around as state.
+        if (Cover == false) orelse NoPassCover ->
+                Binary2 = no_passthrough_cover;
+           true ->
+                Binary2 = Binary,
+                meck_cover:compile_beam(NewName, Binary2)
+        end,
+        {Cover, Binary2}
+    catch
+        throw:{object_code_not_found, _Module} ->
+            {Cover, no_binary}; % TODO: What to do here?
+        throw:no_abstract_code                 ->
+            {Cover, no_binary} % TODO: What to do here?
+    end.
+
+restore_original(Mod, {false, _}, WasSticky) ->
+    restick_original(Mod, WasSticky),
+    ok;
+restore_original(Mod, OriginalState={{File, Data, Options},_}, WasSticky) ->
+    case filename:extension(File) of
+        ".erl" ->
+            {ok, Mod} = cover:compile_module(File, Options);
+        ".beam" ->
+            cover:compile_beam(File)
+    end,
+    restick_original(Mod, WasSticky),
+    import_original_cover(Mod, OriginalState),
+    ok = cover:import(Data),
+    ok = file:delete(Data),
+    ok.
+
+%% @doc Import the cover data for `<name>_meck_original' but since it
+%% was modified by `export_original_cover' it will count towards
+%% `<name>'.
+import_original_cover(Mod, {_,Bin}) when is_binary(Bin) ->
+    OriginalData = atom_to_list(original_name(Mod)) ++ ".coverdata",
+    ok = cover:import(OriginalData),
+    ok = file:delete(OriginalData);
+import_original_cover(_, _) ->
+    ok.
+
+%% @doc Export the cover data for `<name>_meck_original' and modify
+%% the data so it can be imported under `<name>'.
+export_original_cover(Mod, {_, Bin}) when is_binary(Bin) ->
+    OriginalMod = original_name(Mod),
+    File = atom_to_list(OriginalMod) ++ ".coverdata",
+    ok = cover:export(File, OriginalMod),
+    ok = meck_cover:rename_module(File, Mod);
+export_original_cover(_, _) ->
+    ok.
+
+
+unstick_original(Module) -> unstick_original(Module, code:is_sticky(Module)).
+
+unstick_original(Module, true) -> code:unstick_mod(Module);
+unstick_original(_,_) -> false.
+
+restick_original(Module, true) ->
+    code:stick_mod(Module),
+    {module, Module} = code:ensure_loaded(Module),
+    ok;
+restick_original(_,_) -> ok.
+
+get_cover_state(Module) -> get_cover_state(Module, cover:is_compiled(Module)).
+
+get_cover_state(Module, {file, File}) ->
+    Data = atom_to_list(Module) ++ ".coverdata",
+    ok = cover:export(Data, Module),
+    CompileOptions =
+        try
+            meck_mod:compile_options(meck_mod:beam_file(Module))
+        catch
+            throw:{object_code_not_found, _Module} -> []
+        end,
+    {File, Data, CompileOptions};
+get_cover_state(_Module, _IsCompiled) ->
+    false.
+
+exists(Module) ->
+    code:which(Module) /= non_existing.
+
+exports(M) ->
+    [ FA ||  FA = {F, A}  <- M:module_info(exports),
+             normal == expect_type(M, F, A)].
+
+%% Functions we should not create expects for (auto-generated and BIFs)
+expect_type(_, module_info, 0) -> autogenerated;
+expect_type(_, module_info, 1) -> autogenerated;
+expect_type(M, F, A) -> expect_type(erlang:is_builtin(M, F, A)).
+
+expect_type(true)  -> builtin;
+expect_type(false) -> normal.
+
+cleanup(Mod) ->
+    code:purge(Mod),
+    code:delete(Mod),
+    code:purge(original_name(Mod)),
+    code:delete(original_name(Mod)).
+
+%% --- History utilities -------------------------------------------------------
+
+add_history(Pid, Mod, Func, Args, Result) ->
+    add_history(Mod, {Pid, {Mod, Func, Args}, Result}).
+add_history(Pid, Mod, Func, Args, Class, Reason, Stacktrace) ->
+    add_history(Mod, {Pid, {Mod, Func, Args}, Class, Reason, Stacktrace}).
+
+add_history(Mod, Item) ->
+    cast(Mod, {add_history, Item}).
+
+has_call(MFA, History) ->
+    [] =/= match_history(match_mfa(MFA), History).
+
+num_calls(MFA, History) ->
+    length(match_history(match_mfa(MFA), History)).
+
+match_history(MatchSpec, History) ->
+    MS = ets:match_spec_compile(MatchSpec),
+    ets:match_spec_run(History, MS).
+
+match_mfa(MFA) -> match_mfa(MFA, '_').
+
+match_mfa(MFA, Pid) ->
+    [{{Pid, MFA, '_'}, [], ['$_']},
+     {{Pid, MFA, '_', '_', '_'}, [], ['$_']}].

File extern/meck/.eunit/meck_cover.COVER.html

+<html>
+<head><title>.eunit/meck_cover.COVER.html</title></head><body bgcolor=white text=black>
+<pre>
+File generated from /mnt/work/dev/home/kissbang/extern/meck/.eunit/meck_cover.erl by COVER 2012-05-30 at 17:17:56
+
+****************************************************************************
+
+        |  %%==============================================================================
+        |  %% Licensed under the Apache License, Version 2.0 (the "License");
+        |  %% you may not use this file except in compliance with the License.
+        |  %% You may obtain a copy of the License at
+        |  %%
+        |  %% http://www.apache.org/licenses/LICENSE-2.0
+        |  %%
+        |  %% Unless required by applicable law or agreed to in writing, software
+        |  %% distributed under the License is distributed on an "AS IS" BASIS,
+        |  %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        |  %% See the License for the specific language governing permissions and
+        |  %% limitations under the License.
+        |  %%==============================================================================
+        |  
+        |  %% @doc Module containing functions needed by meck to integrate with cover.
+        |  
+        |  -module(meck_cover).
+        |  
+        |  %% Interface exports
+        |  -export([compile_beam/2]).
+        |  -export([rename_module/2]).
+        |  
+        |  %%==============================================================================
+        |  %% Interface exports
+        |  %%==============================================================================
+        |  
+        |  %% @doc Enabled cover on `&lt;name&gt;_meck_original'.
+        |  compile_beam(OriginalMod, Bin) -&gt;
+     7..|      alter_cover(),
+     7..|      {ok, _} = cover:compile_beam(OriginalMod, Bin).
+        |  
+        |  %% @doc Given a cover file `File' exported by `cover:export' overwrite
+        |  %% the module name with `Name'.
+        |  rename_module(File, Name) -&gt;
+     7..|      NewTerms = change_cover_mod_name(read_cover_file(File), Name),
+     7..|      write_terms(File, NewTerms),
+     7..|      ok.
+        |  
+        |  %%==============================================================================
+        |  %% Internal functions
+        |  %%==============================================================================
+        |  
+        |  %% @private
+        |  %%
+        |  %% @doc Alter the cover BEAM module to export some of it's private
+        |  %% functions.  This is done for two reasons:
+        |  %%
+        |  %% 1. Meck needs to alter the export analysis data on disk and
+        |  %% therefore needs to understand this format.  This is why `get_term'
+        |  %% and `write' are exposed.
+        |  %%
+        |  %% 2. In order to avoid creating temporary files meck needs direct
+        |  %% access to `compile_beam/2' which allows passing a binary.
+        |  alter_cover() -&gt;
+     7..|      case lists:member({compile_beam,2}, cover:module_info(exports)) of
+        |          true -&gt;
+     6..|              ok;
+        |          false -&gt;
+     1..|              Beam = meck_mod:beam_file(cover),
+     1..|              AbsCode = meck_mod:abstract_code(Beam),
+     1..|              Exports = [{compile_beam, 2}, {get_term, 1}, {write, 2}],
+     1..|              AbsCode2 = meck_mod:add_exports(Exports, AbsCode),
+     1..|              _Bin = meck_mod:compile_and_load_forms(AbsCode2),
+     1..|              ok
+        |      end.
+        |  
+        |  change_cover_mod_name(CoverTerms, Name) -&gt;
+     7..|      {_, Terms} = lists:foldl(fun change_name_in_term/2, {Name,[]}, CoverTerms),
+     7..|      Terms.
+        |  
+        |  change_name_in_term({file, Mod, File}, {Name, Terms}) -&gt;
+     7..|      Term2 = {file, Name, replace_string(File, Mod, Name)},
+     7..|      {Name, [Term2|Terms]};
+        |  change_name_in_term({Bump={bump,_,_,_,_,_},_}=Term, {Name, Terms}) -&gt;
+    20..|      Bump2 = setelement(2, Bump, Name),
+    20..|      Term2 = setelement(1, Term, Bump2),
+    20..|      {Name, [Term2|Terms]};
+        |  change_name_in_term({_Mod,Clauses}, {Name, Terms}) -&gt;
+     7..|      Clauses2 = lists:foldl(fun change_name_in_clause/2, {Name, []}, Clauses),
+     7..|      Term2 = {Name, Clauses2},
+     7..|      {Name, [Term2|Terms]}.
+        |  
+        |  change_name_in_clause(Clause, {Name, NewClauses}) -&gt;
+    20..|      {Name, [setelement(1, Clause, Name)|NewClauses]}.
+        |  
+        |  replace_string(File, Old, New) -&gt;
+     7..|      Old2 = atom_to_list(Old),
+     7..|      New2 = atom_to_list(New),
+     7..|      re:replace(File, Old2, New2, [{return, list}]).
+        |  
+        |  read_cover_file(File) -&gt;
+     7..|      {ok, Fd} = file:open(File, [read, binary, raw]),
+     7..|      Terms = get_terms(Fd, []),
+     7..|      ok = file:close(Fd),
+     7..|      Terms.
+        |