commit 2c9b8a671d2f3a95bdf13bb8894c88fc82bc703a
Author: Victor Seva <linuxmaniac@torreviejawireless.org>
Date:   Wed Mar 20 15:14:35 2013 +0100

    Imported Upstream version 0.6

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..049d304
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,51 @@
+#
+# LuaDist Travis-CI Hook
+#
+
+# We assume C build environments
+language: C
+	
+# Try using multiple Lua Implementations
+env:
+  - TOOL=""                     # Use native compiler (GCC usually)
+  - COMPILER="clang"            # Use clang
+  - TOOL="i686-w64-mingw32"     # 32bit MinGW
+  - TOOL="x86_64-w64-mingw32"   # 64bit MinGW
+  - TOOL="arm-linux-gnueabihf"  # ARM hard-float (hf), linux
+
+# Crosscompile builds may fail
+matrix:
+  allow_failures:
+    - env: TOOL="i686-w64-mingw32"
+    - env: TOOL="x86_64-w64-mingw32"
+    - env: TOOL="arm-linux-gnueabihf"
+  
+# Install dependencies
+install:
+  - git clone git://github.com/LuaDist/_util.git ~/_util
+  - ~/_util/travis install
+
+# Bootstap
+before_script:
+  - ~/_util/travis bootstrap
+
+# Build the module
+script:
+  - ~/_util/travis build
+
+# Execute additional tests or commands
+#after_script:
+#  - ~/_util/travis test
+
+# Only watch the master branch
+branches:
+  only:
+    - master
+
+# Notify the LuaDist Dev group if needed
+notifications:
+  recipients:
+    - luadist-dev@googlegroups.com
+  email:
+    on_success: change
+    on_failure: always
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..3d3fbf1
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Copyright (C) 2011-2012 LuaDist.
+# Created by Peter Kapec
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# For details see the COPYRIGHT file distributed with LuaDist.
+# Please note that the package source code is licensed under its own license.
+
+project ( lemock NONE )
+cmake_minimum_required ( VERSION 2.8 )
+include ( cmake/dist.cmake )
+include ( lua )
+
+# Install all files and documentation
+install_lua_module ( lemock build/lemock.lua )
+install_doc ( build/htdocs/ )
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644
index 0000000..6714417
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,28 @@
+LeMock License
+
+
+LeMock is licensed under the terms of the MIT license reproduced below. This
+means that LeMock is free software and can be used for both academic and
+commercial purposes at absolutely no cost.
+
+--------------------------------------------------------------------------
+Copyright (C) 2009 Tommy Petterson <ptp@lysator.liu.se>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+--------------------------------------------------------------------------
diff --git a/DEVEL b/DEVEL
new file mode 100644
index 0000000..a8c5906
--- /dev/null
+++ b/DEVEL
@@ -0,0 +1,57 @@
+LeMock Developer Notes
+
+
+LeMock is implemented in Lua 5.1, but its source code is written as
+literate documents, and usees the tool noweb to generate the .lua files.
+The distributed source archive includes all the tangled files in the build
+directory, to avoid dependending on noweb for installation.
+
+The source is contained in the src directory in the form of literate
+documents. To extract (tangle) the final files from the sources, the tool
+[noweb http://www.cs.tufts.edu/~nr/noweb/] is needed.
+
+The source files are meant to be tangled together all at once, because the
+contents of a target file can be spread over several source files. The
+target files are all the chunk names that are roots. These can be found
+with noroots in the noweb toolbox. To automate the tangle process, there is
+a custom script named autotangle in the tools directory. This script finds
+all the target file names and tangles them in the current directory,
+creating subdirectories as needed. The script is written for yet another
+obscure tool, [rc http://www.libra-aries-books.co.uk/software/rc] [1]. It
+is probably easy to port the short rc script to your favourit language. It
+is invoked (in rc syntax) as:
+
+``` ../tools/autotangle `{find ../src -name '*.nw'}
+
+which means it wants all (recursively) .nw files in the src directory as
+arguments.
+
+The documentation is written in [txt2tags http://txt2tags.sourceforge.net/],
+which can generate HTML among many other formats. The README, HISTORY,
+COPYRIGHT, and this DEVEL text file are written as simple txt2tags
+documents to remain readable as is. The .nw source files define wrapper
+txt2tags documents for the web pages, which use txt2tags' include mechanism
+to include the actual txt2tags files. The user guide is defined in the .nw
+sources as a separate txt2tags document, so it can be easily generated as a
+LaTeX document or Unix man page, but it too is included in a wrapper
+txt2tags document when generating the web pages.
+
+The building of the web pages is done with
+[mk http://en.wikipedia.org/wiki/Mk_%28software%29], a Unix port of the
+Plan9 make tool. (The mk files uses rc syntax.)
+
+A set of unit tests (defined in the .nw source) can be run with
+[lunit http://www.nessie.de/mroth/lunit/index.html] with the command:
+
+``` lunit unit/*.lua
+
+A program like [luacov http://luacov.luaforge.net/] can be used to check
+the coverage of the unit tests.
+
+
+--------------------
+== Footnotes ==
+: [1]
+  I use Byron's Unix port, which syntax is extended and incompatible with
+  the original (and other ports).
+:
diff --git a/HISTORY b/HISTORY
new file mode 100644
index 0000000..8a6c383
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,22 @@
+LeMock History
+
+
+: 0.6
+  - Actions can be set to raise an error.
+  - //anytimes// and //atleastonce//.
+  - Fail immediately if an unsatisfied action is closed.
+  - Simplify semantics for Anyarg and Anyargs.
+  - Documentation.
+: 0.5
+  - Anyarg and Anyargs.
+  - Third rewrite (major refactoring).
+: 0.4
+  - Labels, dependencies, closes, and replay count limits.
+  - Allow attribute modifying controller methods to be chained.
+: 0.3
+  - Initial import.
+  - This is the second rewrite of the initial prototype. It handles recording
+    and replaying of actions with returnvalues, and verifies replay
+    completeness.
+
+
diff --git a/README b/README
new file mode 100644
index 0000000..1df32fa
--- /dev/null
+++ b/README
@@ -0,0 +1,44 @@
+LeMock Readme
+
+
+== What is Lua Easy Mock ==
+
+LeMock (Lua Easy Mock) is a mock creation module intended for use together
+with a unit test framework such as lunit or lunity. It is inspired by
+EasyMock (for Java), and strives to be easy to use.
+
+
+== Availability ==
+
+LeMock is hosted at LuaForge at http://luaforge.net/projects/lemock/
+
+
+== Installation ==
+
+Copy the file build/lemock.lua to a Lua search path directory. This is
+usually something like ``/usr/share/lua/5.1/`` or
+``/usr/local/lib/lua/5.1/``. You can type ``print(package.path)`` at the
+Lua prompt to see what search path your Lua installation is using.
+
+Documentation in HTML format is available in build/htdocs/.
+
+
+== License ==
+
+LeMock is licensed under the MIT license, which is the same license that
+Lua uses. See COPYRIGHT_ for full terms.
+
+
+== User Documentation ==
+
+See build/htdocs/userguide.html.
+
+
+== Development ==
+
+LeMock is implemented in Lua 5.1, but its source code is written as
+literate documents, and uses the tool noweb to tangle the .lua files. The
+distributed source archive includes all the tangled files, to avoid
+depending on noweb for installation. See DEVEL_ for information about how
+the source code is organized, and what tools are needed for the build
+process.
diff --git a/build/htdocs/COPYRIGHT.html b/build/htdocs/COPYRIGHT.html
new file mode 100644
index 0000000..1ec776e
--- /dev/null
+++ b/build/htdocs/COPYRIGHT.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+<META NAME="generator" CONTENT="http://txt2tags.sf.net">
+<LINK REL="stylesheet" TYPE="text/css" HREF="style.css">
+<TITLE>LeMock</TITLE>
+</HEAD>
+<BODY>
+
+<DIV CLASS="header" ID="header">
+<H1>LeMock</H1>
+</DIV>
+
+<DIV CLASS="body" ID="page-COPYRIGHT">
+<ul id="main_menu">
+  <li id="main_menu-README"><a    href="README.html"   >Readme</a></li>
+  <li id="main_menu-COPYRIGHT"><a href="COPYRIGHT.html">License</a></li>
+  <li id="main_menu-userguide"><a href="userguide.html">Userguide</a></li>
+  <li id="main_menu-HISTORY"><a   href="HISTORY.html"  >History</a></li>
+  <li id="main_menu-DEVEL"><a     href="DEVEL.html"    >Devel</a></li>
+</ul>
+<H1>License</H1>
+<P>
+LeMock is licensed under the terms of the MIT license reproduced below. This
+means that LeMock is free software and can be used for both academic and
+commercial purposes at absolutely no cost.
+</P>
+<HR NOSHADE SIZE=1>
+<P>
+Copyright (C) 2009 Tommy Petterson &lt;<A HREF="mailto:ptp@lysator.liu.se">ptp@lysator.liu.se</A>&gt;
+</P>
+<P>
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+</P>
+<P>
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+</P>
+<P>
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+</P>
+<HR NOSHADE SIZE=1>
+</DIV>
+
+<!-- html code generated by txt2tags 2.3 (http://txt2tags.sf.net) -->
+<!-- cmdline: txt2tags -t html -i www/COPYRIGHT.t2t -o htdocs/COPYRIGHT.html -->
+</BODY></HTML>
diff --git a/build/htdocs/DEVEL.html b/build/htdocs/DEVEL.html
new file mode 100644
index 0000000..13ccad2
--- /dev/null
+++ b/build/htdocs/DEVEL.html
@@ -0,0 +1,98 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+<META NAME="generator" CONTENT="http://txt2tags.sf.net">
+<LINK REL="stylesheet" TYPE="text/css" HREF="style.css">
+<TITLE>LeMock</TITLE>
+</HEAD>
+<BODY>
+
+<DIV CLASS="header" ID="header">
+<H1>LeMock</H1>
+</DIV>
+
+<DIV CLASS="body" ID="page-DEVEL">
+<ul id="main_menu">
+  <li id="main_menu-README"><a    href="README.html"   >Readme</a></li>
+  <li id="main_menu-COPYRIGHT"><a href="COPYRIGHT.html">License</a></li>
+  <li id="main_menu-userguide"><a href="userguide.html">Userguide</a></li>
+  <li id="main_menu-HISTORY"><a   href="HISTORY.html"  >History</a></li>
+  <li id="main_menu-DEVEL"><a     href="DEVEL.html"    >Devel</a></li>
+</ul>
+<H1>Developer Notes</H1>
+<P>
+LeMock is implemented in Lua 5.1, but its source code is written as
+literate documents, and usees the tool noweb to generate the .lua files.
+The distributed source archive includes all the tangled files in the build
+directory, to avoid dependending on noweb for installation.
+</P>
+<P>
+The source is contained in the src directory in the form of literate
+documents. To extract (tangle) the final files from the sources, the tool
+<A HREF="http://www.cs.tufts.edu/~nr/noweb/">noweb</A> is needed.
+</P>
+<P>
+The source files are meant to be tangled together all at once, because the
+contents of a target file can be spread over several source files. The
+target files are all the chunk names that are roots. These can be found
+with noroots in the noweb toolbox. To automate the tangle process, there is
+a custom script named autotangle in the tools directory. This script finds
+all the target file names and tangles them in the current directory,
+creating subdirectories as needed. The script is written for yet another
+obscure tool, <A HREF="http://www.libra-aries-books.co.uk/software/rc">rc</A> [1]. It
+is probably easy to port the short rc script to your favourit language. It
+is invoked (in rc syntax) as:
+</P>
+<PRE>
+../tools/autotangle `{find ../src -name '*.nw'}
+</PRE>
+<P></P>
+<P>
+which means it wants all (recursively) .nw files in the src directory as
+arguments.
+</P>
+<P>
+The documentation is written in <A HREF="http://txt2tags.sourceforge.net/">txt2tags</A>,
+which can generate HTML among many other formats. The README, HISTORY,
+COPYRIGHT, and this DEVEL text file are written as simple txt2tags
+documents to remain readable as is. The .nw source files define wrapper
+txt2tags documents for the web pages, which use txt2tags' include mechanism
+to include the actual txt2tags files. The user guide is defined in the .nw
+sources as a separate txt2tags document, so it can be easily generated as a
+LaTeX document or Unix man page, but it too is included in a wrapper
+txt2tags document when generating the web pages.
+</P>
+<P>
+The building of the web pages is done with
+<A HREF="http://en.wikipedia.org/wiki/Mk_%28software%29">mk</A>, a Unix port of the
+Plan9 make tool. (The mk files uses rc syntax.)
+</P>
+<P>
+A set of unit tests (defined in the .nw source) can be run with
+<A HREF="http://www.nessie.de/mroth/lunit/index.html">lunit</A> with the command:
+</P>
+<PRE>
+lunit unit/*.lua
+</PRE>
+<P></P>
+<P>
+A program like <A HREF="http://luacov.luaforge.net/">luacov</A> can be used to check
+the coverage of the unit tests.
+</P>
+<HR NOSHADE SIZE=1>
+<H2>Footnotes</H2>
+<DL>
+<DT>[1]</DT><DD>
+  I use Byron's Unix port, which syntax is extended and incompatible with
+  the original (and other ports).
+</DL>
+
+<HR NOSHADE SIZE=1>
+<P>
+2009-05-31
+</P>
+</DIV>
+
+<!-- html code generated by txt2tags 2.3 (http://txt2tags.sf.net) -->
+<!-- cmdline: txt2tags -t html -i www/DEVEL.t2t -o htdocs/DEVEL.html -->
+</BODY></HTML>
diff --git a/build/htdocs/HISTORY.html b/build/htdocs/HISTORY.html
new file mode 100644
index 0000000..79089d4
--- /dev/null
+++ b/build/htdocs/HISTORY.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+<META NAME="generator" CONTENT="http://txt2tags.sf.net">
+<LINK REL="stylesheet" TYPE="text/css" HREF="style.css">
+<TITLE>LeMock</TITLE>
+</HEAD>
+<BODY>
+
+<DIV CLASS="header" ID="header">
+<H1>LeMock</H1>
+</DIV>
+
+<DIV CLASS="body" ID="page-HISTORY">
+<ul id="main_menu">
+  <li id="main_menu-README"><a    href="README.html"   >Readme</a></li>
+  <li id="main_menu-COPYRIGHT"><a href="COPYRIGHT.html">License</a></li>
+  <li id="main_menu-userguide"><a href="userguide.html">Userguide</a></li>
+  <li id="main_menu-HISTORY"><a   href="HISTORY.html"  >History</a></li>
+  <li id="main_menu-DEVEL"><a     href="DEVEL.html"    >Devel</a></li>
+</ul>
+<H1>History</H1>
+<DL>
+<DT>0.6</DT><DD>
+  <UL>
+  <LI>Actions can be set to raise an error.
+  <LI><I>anytimes</I> and <I>atleastonce</I>.
+  <LI>Fail immediately if an unsatisfied action is closed.
+  <LI>Simplify semantics for Anyarg and Anyargs.
+  <LI>Documentation.
+  </UL>
+<DT>0.5</DT><DD>
+  <UL>
+  <LI>Anyarg and Anyargs.
+  <LI>Third rewrite (major refactoring).
+  </UL>
+<DT>0.4</DT><DD>
+  <UL>
+  <LI>Labels, dependencies, closes, and replay count limits.
+  <LI>Allow attribute modifying controller methods to be chained.
+  </UL>
+<DT>0.3</DT><DD>
+  <UL>
+  <LI>Initial import.
+  <LI>This is the second rewrite of the initial prototype. It handles recording
+    and replaying of actions with returnvalues, and verifies replay
+    completeness.
+  </UL>
+</DL>
+
+<HR NOSHADE SIZE=1>
+<P>
+2009-05-31
+</P>
+</DIV>
+
+<!-- html code generated by txt2tags 2.3 (http://txt2tags.sf.net) -->
+<!-- cmdline: txt2tags -t html -i www/HISTORY.t2t -o htdocs/HISTORY.html -->
+</BODY></HTML>
diff --git a/build/htdocs/README.html b/build/htdocs/README.html
new file mode 100644
index 0000000..adec969
--- /dev/null
+++ b/build/htdocs/README.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+<META NAME="generator" CONTENT="http://txt2tags.sf.net">
+<LINK REL="stylesheet" TYPE="text/css" HREF="style.css">
+<TITLE>LeMock</TITLE>
+</HEAD>
+<BODY>
+
+<DIV CLASS="header" ID="header">
+<H1>LeMock</H1>
+</DIV>
+
+<DIV CLASS="body" ID="page-README">
+<ul id="main_menu">
+  <li id="main_menu-README"><a    href="README.html"   >Readme</a></li>
+  <li id="main_menu-COPYRIGHT"><a href="COPYRIGHT.html">License</a></li>
+  <li id="main_menu-userguide"><a href="userguide.html">Userguide</a></li>
+  <li id="main_menu-HISTORY"><a   href="HISTORY.html"  >History</a></li>
+  <li id="main_menu-DEVEL"><a     href="DEVEL.html"    >Devel</a></li>
+</ul>
+<H1>Readme</H1>
+<H2>What is Lua Easy Mock</H2>
+<P>
+LeMock (Lua Easy Mock) is a mock creation module intended for use together
+with a unit test framework such as lunit or lunity. It is inspired by
+EasyMock (for Java), and strives to be easy to use.
+</P>
+<H2>Availability</H2>
+<P>
+LeMock is hosted at LuaForge at <A HREF="http://luaforge.net/projects/lemock/">http://luaforge.net/projects/lemock/</A>
+</P>
+<H2>Installation</H2>
+<P>
+Copy the file build/lemock.lua to a Lua search path directory. This is
+usually something like <CODE>/usr/share/lua/5.1/</CODE> or
+<CODE>/usr/local/lib/lua/5.1/</CODE>. You can type <CODE>print(package.path)</CODE> at the
+Lua prompt to see what search path your Lua installation is using.
+</P>
+<P>
+Documentation in HTML format is available in build/htdocs/.
+</P>
+<H2>License</H2>
+<P>
+LeMock is licensed under the MIT license, which is the same license that
+Lua uses. See <A HREF="COPYRIGHT.html">COPYRIGHT</A> for full terms.
+</P>
+<H2>User Documentation</H2>
+<P>
+See <A HREF="userguide.html">the user guide</A>.
+</P>
+<H2>Development</H2>
+<P>
+LeMock is implemented in Lua 5.1, but its source code is written as
+literate documents, and uses the tool noweb to tangle the .lua files. The
+distributed source archive includes all the tangled files, to avoid
+depending on noweb for installation. See <A HREF="DEVEL.html">DEVEL</A> for information about how
+the source code is organized, and what tools are needed for the build
+process.
+</P>
+<HR NOSHADE SIZE=1>
+<P>
+2009-05-31
+</P>
+</DIV>
+
+<!-- html code generated by txt2tags 2.3 (http://txt2tags.sf.net) -->
+<!-- cmdline: txt2tags -t html -i www/README.t2t -o htdocs/README.html -->
+</BODY></HTML>
diff --git a/build/htdocs/index.html b/build/htdocs/index.html
new file mode 100644
index 0000000..d4a04f2
--- /dev/null
+++ b/build/htdocs/index.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+<META NAME="generator" CONTENT="http://txt2tags.sf.net">
+<LINK REL="stylesheet" TYPE="text/css" HREF="style.css">
+<TITLE>LeMock</TITLE>
+</HEAD>
+<BODY>
+
+<DIV CLASS="header" ID="header">
+<H1>LeMock</H1>
+</DIV>
+
+<DIV CLASS="body" ID="page-index">
+<ul id="main_menu">
+  <li id="main_menu-README"><a    href="README.html"   >Readme</a></li>
+  <li id="main_menu-COPYRIGHT"><a href="COPYRIGHT.html">License</a></li>
+  <li id="main_menu-userguide"><a href="userguide.html">Userguide</a></li>
+  <li id="main_menu-HISTORY"><a   href="HISTORY.html"  >History</a></li>
+  <li id="main_menu-DEVEL"><a     href="DEVEL.html"    >Devel</a></li>
+</ul>
+</DIV>
+
+<!-- html code generated by txt2tags 2.3 (http://txt2tags.sf.net) -->
+<!-- cmdline: txt2tags -t html -i www/index.t2t -o htdocs/index.html -->
+</BODY></HTML>
diff --git a/build/htdocs/style.css b/build/htdocs/style.css
new file mode 100644
index 0000000..52c88f5
--- /dev/null
+++ b/build/htdocs/style.css
@@ -0,0 +1,120 @@
+                body {
+                        color:            #181818;
+                        background-color: #E0E4F0;
+                        font:             normal 10pt sans-serif;
+                        max-width:        30em;
+                        margin:           25pt;
+                }
+                .body h1 {
+                        margin:           2em 0em 0em 0em;
+                        font-size:        14pt;
+                }
+                .body h2 {
+                        margin:           1.5em 0em 0em 0em;
+                        font-size:        12pt;
+                }
+                .body h3 {
+                        margin:           1em 0em 0em 0em;
+                        font-size:        10pt;
+                }
+                .body p, .body ul, .body ol {
+                        margin-top:       0.5em;
+                }
+                .body li {
+                        margin-top:       0.5em;
+                }
+                a {
+                        text-decoration:  none;
+                }
+                hr {
+                        margin-top:       3em;
+                }
+
+                .header h1 {
+                        text-align:       center;
+                        padding:          0.3em;
+                        border:           1pt solid black;
+                }
+
+                code, pre {
+                        font-family:      fixed;
+                        font-style:       normal;
+                        font-size:        9pt;
+                        line-height:      9pt;
+                        background-color: #E8ECF8;
+                }
+                pre {
+                        padding:          2pt;
+                }
+
+                div.toc {
+                        margin-top:       3em;
+                        line-height:      6pt;
+                }
+                .toc ul {
+                        padding-left:     1.6em;
+                        margin:           0em;
+                        line-height:      10pt;
+                }
+                .toc li {
+                        margin:           0em;
+                        padding:          0em;
+                        list-style-type:  none;
+                }
+                .toc a {
+                        color:            #091;
+                }
+
+                #page-HISTORY DL DT {
+                        font-weight:      bold;
+                        margin-top:       2em;
+                }
+                #page-HISTORY DL DD UL {
+                        margin-top:       0pt;
+                        padding-left:     0pt;
+                }
+
+        #main_menu {
+                margin:  0;
+                padding: 0;
+        }
+        #main_menu li {
+                margin:  0;
+                padding: 0;
+                display: inline;
+        }
+        #main_menu a {
+                padding:    3px 3px 2px 4px;
+                text-decoration:none;
+                font:bold 8pt/8pt Arial, Helvetica, sans-serif;
+                border:       1px solid #000;
+        }
+        #main_menu a:link,
+        #main_menu a:visited {
+                color:      #fff;
+                background: #777;
+        }
+        #main_menu a:hover {
+                color:      #000;
+                background: #777;
+        }
+        #page-README    #main_menu-README    a,
+        #page-COPYRIGHT #main_menu-COPYRIGHT a,
+        #page-userguide #main_menu-userguide a,
+        #page-HISTORY   #main_menu-HISTORY   a,
+        #page-DEVEL     #main_menu-DEVEL     a {
+                color:      #000;
+                background: #aaa;
+        }
+        #page-README    #main_menu-README    a:hover,
+        #page-COPYRIGHT #main_menu-COPYRIGHT a:hover,
+        #page-userguide #main_menu-userguide a:hover,
+        #page-HISTORY   #main_menu-HISTORY   a:hover,
+        #page-DEVEL     #main_menu-DEVEL     a:hover {
+                color:      #000;
+                background: #aaa;
+        }
+        #nav a:active {
+                color:      #000;
+                background: #aaa;
+        }
diff --git a/build/htdocs/userguide.html b/build/htdocs/userguide.html
new file mode 100644
index 0000000..ae13153
--- /dev/null
+++ b/build/htdocs/userguide.html
@@ -0,0 +1,425 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+<META NAME="generator" CONTENT="http://txt2tags.sf.net">
+<LINK REL="stylesheet" TYPE="text/css" HREF="style.css">
+<TITLE>LeMock</TITLE>
+</HEAD>
+<BODY>
+
+<DIV CLASS="header" ID="header">
+<H1>LeMock</H1>
+</DIV>
+
+<DIV CLASS="body" ID="page-userguide">
+<ul id="main_menu">
+  <li id="main_menu-README"><a    href="README.html"   >Readme</a></li>
+  <li id="main_menu-COPYRIGHT"><a href="COPYRIGHT.html">License</a></li>
+  <li id="main_menu-userguide"><a href="userguide.html">Userguide</a></li>
+  <li id="main_menu-HISTORY"><a   href="HISTORY.html"  >History</a></li>
+  <li id="main_menu-DEVEL"><a     href="DEVEL.html"    >Devel</a></li>
+</ul>
+<DIV CLASS="toc" ID="toc">
+  <UL>
+  <LI><A HREF="#toc1">Introduction</A>
+  <LI><A HREF="#toc2">The Mock Object</A>
+    <UL>
+    <LI><A HREF="#toc3">Actions</A>
+    <LI><A HREF="#anyargs">Anyargs</A>
+    </UL>
+  <LI><A HREF="#toc5">The Controller</A>
+    <UL>
+    <LI><A HREF="#toc6">Returns &amp; Error</A>
+    <LI><A HREF="#toc7">Label &amp; Depend</A>
+    <LI><A HREF="#toc8">Times</A>
+    <LI><A HREF="#toc9">Close</A>
+    </UL>
+  <LI><A HREF="#toc10">Tricks</A>
+    <UL>
+    <LI><A HREF="#toc11">Method Overloading</A>
+    </UL>
+  </UL>
+
+</DIV>
+<A NAME="toc1"></A>
+<H1>Introduction</H1>
+<P>
+Mock objects replace difficult external objects during unit testing by
+simulating the behaviors of the replaced objects. This is done by first
+recording actions and their responses with the mock objects, and then
+switching to replay mode. During replay mode the mock objects simulate the
+replaced objects by looking up actions and replaying the recorded
+responses, and finally verifying that all expected actions where completely
+replayed.
+</P>
+<P>
+Actions are stored in a list in a special controller object. During replay
+the list is searched in recording order for the first matching action that
+can be replayed.
+</P>
+<P>
+Restrictions on the actions can be inserted during the recording phase. An
+action can have a maximum count of how many times it will be replayed, and
+a minimum count of how many times it must be replayed to be satisfied. An
+action can depend on any set of other actions, and can not be replayed
+before all of its depended actions are satisfied. An action can close any
+set of actions when it is replayed, which stops all further replaying of
+the closed actions. This is good for simulating state changes.
+</P>
+<H3>Example</H3>
+<P>
+This example tests that the insert_data function of the foo module handles
+a missing data base table gracefully.
+</P>
+<PRE>
+-- Setup
+require 'lemock'
+local mc = lemock.controller()
+local sqlite3 = mc:mock()
+local env     = mc:mock()
+local con     = mc:mock()
+package.loaded.luasql = nil
+package.preload['luasql.sqlite3'] = function ()
+    luasql = {}
+    luasql.sqlite3 = sqlite3
+    return sqlite3
+end
+
+-- Record
+sqlite3()                 ;mc :returns(env)
+env:connect('/data/base') ;mc :returns(con)
+con:execute(mc.ANYARGS)   ;mc :error('LuaSQL: no such table')
+con:close()
+env:close()
+
+-- Replay
+mc:replay()
+require 'foo'
+local res = foo.insert_data(17)
+assert(res==false)
+
+--Verify
+mc:verify()
+</PRE>
+<P></P>
+<P>
+First a controller is created. Then three mock objects are created, one for
+the sqlite3 module, and two for objects returned by the (simulated) module.
+</P>
+<P>
+Then a preloader for the sqlite3 module is installed, which returns the
+sqlite3 mock object instead of the actual sqlite3 module.
+</P>
+<P>
+In the record phase the expected calls and their return values (or thrown
+errors) are recorded. The order is not significant, so this simplified test
+will not detect if the close method is called before the execute method.
+</P>
+<P>
+In the replay phase the tested module is loaded and executed. It will use
+the mock objects instead of the real data base, and if it makes any
+unrecorded calls, an error is thrown.
+</P>
+<P>
+The verify phase asserts that all recorded actions have been replayed. If
+the foo module for example forgets to call the close method, verify throws
+an error.
+</P>
+<A NAME="toc2"></A>
+<H1>The Mock Object</H1>
+<P>
+Mock objects are empty objects with special Lua meta methods that detect
+actions performed with the object. What happens depends on the state
+(recording or replaying) of the controller which created the mock object.
+During recording the mock object adds the action to the controller's list
+of recorded actions. During replay the mock object looks for a matching
+recorded action that can be replayed, and simulates the action.
+</P>
+<P>
+Some action attributes can not be inferred by the mock objects, for example
+return values. These attributes have to be added afterwards with special
+controller methods, and always affect the last recorded action.
+</P>
+<A NAME="toc3"></A>
+<H2>Actions</H2>
+<P>
+Mock objects detect four types of actions: assignment, indexing, method
+call, and self call. During replay an action will only match if it is the
+very same action, that is, the same type of action performed on the same
+mock object with all the same arguments. There are however
+<A HREF="#anyargs">special arguments</A> that can be used during recording.
+</P>
+<PRE>
+require 'lemock'
+local mc = lemock.controller()
+local m = mc:mock()
+
+m.x = 17    -- assignment
+r = m.x     -- indexing
+m.x(1,2,3)  -- method call
+m:x(1,2,3)  -- method call
+m(1,2,3)    -- self call
+</PRE>
+<A NAME="anyargs"></A>
+<H2>Anyargs</H2>
+<P>
+An <I>anyarg</I> is a special argument used when recording, that will match
+any argument during replay. It can appear anywhere and any times in an
+argument list, or as the argument in an assignment, to replace real
+arguments. There is also <I>anyargs</I>, which will match any number
+(including zero) of any arguments. Anyargs can only appear as the last
+argument of an argument list. Anyarg and anyargs are handy when the actual
+values of the arguments during replay are unimportant or unknown.
+</P>
+<P>
+Anyarg and anyargs are constants defined in the controller object.
+</P>
+<H3>Example</H3>
+<P>
+This example tests that the fetch_data function of module foo waits a while
+and retries when no data is immediately available, and that it updates the
+value of lasttime.
+</P>
+<PRE>
+require 'lemock'
+local mc = lemock.controller()
+local con = mc:mock()
+
+con:poll()           ;mc :returns(nil)
+con:sleep(mc.ANYARG)
+con:poll()           ;mc :returns('123.45')
+con.lasttime = mc.ANYARG
+
+mc:replay()
+require 'foo'
+local res = foo.fetch_data(con)
+assert( math.abs(res-123.45) &lt; 0.0005 )
+
+mc:verify()
+</PRE>
+<A NAME="toc5"></A>
+<H1>The Controller</H1>
+<P>
+The controller's main purpose is to store the recorded actions, create mock
+objects, switch to replay mode, and verify the completion of the replay
+phase. But it is also needed to set or change special action attributes
+during recording.
+</P>
+<P>
+It is possible, although doubtfully useful, to use several controllers in
+parallel during a single unit test. Each controller maintains its own
+action list and state, and mock objects remember which controller they
+belong to.
+</P>
+<A NAME="toc6"></A>
+<H2>Returns &amp; Error</H2>
+<P>
+The by far most useful special action attribute is the return value.
+Indexing actions can return a single value, while call actions and self
+call actions can return a list of values. The return value is set with the
+<I>returns</I> method, and it is an error to set the return value twice for
+the same action.
+</P>
+<P>
+For purposes of unit testing it is often useful to simulate errors. All
+actions can raise an error, and return an error value (usually a string).
+The return value is set with the <I>error</I> method. An action can not have
+both a return value and raise an error.
+</P>
+<H3>Example</H3>
+<PRE>
+require 'lemock'
+local mc = lemock.controller()
+local m = mc:mock()
+
+m:foo(17)  ;mc :returns(nil, "index out of range")
+m:bar(-1)  ;mc :error("invalid index")
+</PRE>
+<A NAME="toc7"></A>
+<H2>Label &amp; Depend</H2>
+<P>
+Dependencies block actions from replaying until other actions have replayed
+first. They can be used to verify that actions are being replayed in a
+valid order.
+</P>
+<P>
+To add dependencies, actions must first be labeled with one or more
+<I>labels</I>. The same label can be given to several actions. As long as some
+action with the label remains unsatisfied, that label is blocked, and all
+actions depending on that label will not replay.
+</P>
+<H3>Example</H3>
+<P>
+This (contrived) example tests that function draw_square in module foo
+calls all the necessary drawing methods of a square object in a correct
+order. Note that there can be more than one correct order.
+</P>
+<PRE>
+require 'lemock'
+local mc = lemock.controller()
+local square = mc:mock()
+
+square:topleft()   ;mc :label('tl')
+square:topright()  ;mc :label('tr')
+square:botleft()   ;mc :label('bl')
+square:botright()  ;mc :label('br')
+square:leftedge()  ;mc :label('edge') :depend('tl', 'bl')
+square:rightedge() ;mc :label('edge') :depend('tr', 'br')
+square:topedge()   ;mc :label('edge') :depend('tl', 'tr')
+square:botedge()   ;mc :label('edge') :depend('bl', 'br')
+square:fill()      ;mc                :depend('edge')
+
+mc:replay()
+require 'foo'
+foo.draw_square( square )
+
+mc:verify()
+</PRE>
+<P></P>
+<P>
+This example demonstrates two different ways of using dependencies. All the
+corners have unique labels, because each edge depend on a set of specific
+corners. But all the edges have the same label, because the fill operation
+only depends on <I>all</I> edges have been satisfied.
+</P>
+<A NAME="toc8"></A>
+<H2>Times</H2>
+<P>
+The default for a recorded action is to be replayed exactly once.
+<CODE>times(2)</CODE> changes that to exactly two times, and <CODE>times(1,2)</CODE> changes
+it to at least one time and at most two times.
+</P>
+<P>
+When the action has been replayed the least count times it is
+<I>satisfied</I>, which means verify will not complain about it, and it no
+longer blocks actions that depend on this action from being replayed. If
+the least count is zero the action is automatically satisfied and need not
+be replayed at all, i.e., it is optional.
+</P>
+<P>
+When the action has been replayed the most count times it will not replay
+any more. The most replay count can be set to infinity (<CODE>math.huge</CODE> or
+<CODE>1/0</CODE>), in which case the action will never stop replaying.
+</P>
+<P>
+<CODE>anytimes()</CODE> can be used as an alias for <CODE>times(0,1/0)</CODE>, and
+<CODE>atleastonce()</CODE> can be used as an alias for <CODE>times(1,1/0)</CODE>.
+</P>
+<H3>Example</H3>
+<P>
+This example tests that method update is called at least once.
+</P>
+<PRE>
+require 'lemock'
+local mc = lemock.controller()
+local con = mc:mock()
+
+con:log(mc.ANYARGS) ;mc                :anytimes()
+con:update('x',3)   ;mc :returns(true) :atleastonce()
+
+mc:replay()
+require 'foo'
+local watcher = foo.mk_watcher( con )
+watcher:set( 'x', 3 )
+
+mc:verify()
+</PRE>
+<A NAME="toc9"></A>
+<H2>Close</H2>
+<P>
+Close can be used to simulate state changes in a limited way. When an
+action with a close statement is replayed for the first time, it will
+permanently block all labels in its close statement, so that actions with
+these labels no longer replays. This passes on matching to later actions in
+the action list, which may for example have different return values.
+</P>
+<P>
+The closing simply blocks the labels, and it has nothing to do with max
+replay counts or if closed actions have been satisfied or not. Closing an
+unsatisfied action however results in an immediate failure.
+</P>
+<H3>Example</H3>
+<P>
+This example tests that the dump function of module foo calls the myio
+functions in a correct order. The read function can be called any number of
+times, until it is closed by the close function.
+</P>
+<PRE>
+require 'lemock'
+local mc = lemock.controller()
+local myio = mc:mock()
+local fs   = mc:mock()
+
+myio.open('abc', 'r') ;mc :returns(fs)
+mc :label('open')
+
+fs:read(mc.ANYARG) ;mc :returns('data')
+mc :atleastonce() :label('read') :depend('open')
+
+fs:close() ;mc :returns(true)
+mc :depend('open') :close('read')
+
+mc:replay()
+require 'foo'
+foo.dump(myio, 'abc', 128)
+
+mc:verify()
+</PRE>
+<A NAME="toc10"></A>
+<H1>Tricks</H1>
+<P>
+Mock objects are completely empty, and do not contain any methods or
+properties of their own. If they did, that would risk shadowing a name of a
+simulated object's method or property. There is however nothing preventing
+users from defining methods and properties in mock objects. This way mock
+objects can be turned into stubs, or a kind of mock–stub hybrid.
+</P>
+<A NAME="toc11"></A>
+<H2>Method Overloading</H2>
+<P>
+Lua does not support method overloading, but it can be (and sometimes is)
+implemented manually by testing of function arguments. This presents a
+problem to LeMock, because it matches exact arguments, and anyargs in not
+sufficient. In this case the mock object can be extended with a dispatcher
+function.
+</P>
+<H3>Example</H3>
+<P>
+This example shows a mock object with an overloaded add function. The stub
+function can not be defined in the usual way, because that would record an
+assignment action; it needs to be defined with <I>rawset</I>.
+</P>
+<PRE>
+require 'lemock'
+local mc = lemock.controller()
+local m = mc:mock()
+
+do
+local function add (a, b)
+    if type(a) == 'number' then
+        return m.add_number(a, b)
+    else
+        return m.add_string(a, b)
+    end
+end
+rawset( m, 'add', add ) -- not recorded
+end -- do
+
+m.add_number(1, 2)         ;mc :returns(3)
+m.add_string('foo', 'bar') ;mc :returns('foobar')
+
+mc:replay()
+assert_equal( 3, m.add(1, 2) )
+assert_equal( 'foobar', m.add('foo', 'bar') )
+
+mc:verify()
+</PRE>
+<HR NOSHADE SIZE=1>
+<P>
+2009-05-31
+</P>
+</DIV>
+
+<!-- html code generated by txt2tags 2.3 (http://txt2tags.sf.net) -->
+<!-- cmdline: txt2tags -t html -\-toc -\-toc-level 2 -i www/userguide.t2t -o htdocs/userguide.html -->
+</BODY></HTML>
diff --git a/build/lemock.lua b/build/lemock.lua
new file mode 100644
index 0000000..a25bc8c
--- /dev/null
+++ b/build/lemock.lua
@@ -0,0 +1,659 @@
+------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------
+-- Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+-- See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+module( 'lemock', package.seeall )
+_VERSION   = "LeMock 0.6"
+_COPYRIGHT = "Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>"
+local class, object, qtostring, sfmt, add_to_set
+local elements_of_set, value_equal
+function object (class)
+	return setmetatable( {}, class )
+end
+function class (parent)
+	local c = object(parent)
+	c.__index = c
+	return c
+end
+sfmt = string.format
+function qtostring (v)
+	if type(v) == 'string' then
+		return sfmt( '%q', v )
+	else
+		return tostring( v )
+	end
+end
+function add_to_set (o, setname, element)
+	if not o[setname] then
+		o[setname] = {}
+	end
+	local l = o[setname]
+	for i = 1, #l do
+		if l[i] == element then return end
+	end
+	l[#l+1] = element
+end
+function elements_of_set (o, setname)
+	local l = o[setname]
+	local i = l and #l+1 or 0
+	return function ()
+		i = i - 1
+		if i > 0 then return l[i] end
+	end
+end
+function value_equal (a, b)
+	if a == b then return true end
+	if a ~= a and b ~= b then return true end -- NaN == NaN
+	return false
+end
+local mock_controller_map = setmetatable( {}, {__mode='k'} )
+-- All the classes are private
+local Action, Argv, Callable, Controller, Mock
+Action = {}
+-- abstract
+Action.generic = class()
+function Action.generic:add_close (label)
+	add_to_set( self, 'closelist', label )
+end
+function Action.generic:add_depend (d)
+	add_to_set( self, 'dependlist', d )
+end
+function Action.generic:add_label (label)
+	add_to_set( self, 'labellist', label )
+end
+function Action.generic:assert_satisfied ()
+	assert( self.replay_count <= self.max_replays, "lemock internal error" )
+	if not (
+self.min_replays <= self.replay_count
+                                  ) then
+		error( sfmt( "Wrong replay count %d (expected %d..%d) for %s"
+		             , self.replay_count
+		             , self.min_replays, self.max_replays
+		             , self:tostring()
+		       )
+		       , 0
+		)
+	end
+end
+function Action.generic:blocks ()
+	if self:is_satisfied() then
+		return function () end
+	end
+	return elements_of_set( self, 'labellist' )
+end
+function Action.generic:closes ()
+	return elements_of_set( self, 'closelist' )
+end
+function Action.generic:depends ()
+	return elements_of_set( self, 'dependlist' )
+end
+function Action.generic:has_label (l)
+	for x in elements_of_set( self, 'labellist' ) do
+		if x == l then return true end
+	end
+	return false
+end
+function Action.generic:is_expected ()
+	return self.replay_count < self.max_replays
+	   and not self.is_blocked
+	   and not self.is_closed
+end
+function Action.generic:is_satisfied ()
+	return 
+self.min_replays <= self.replay_count
+end
+function Action.generic:match (key)
+	if getmetatable(self) ~= getmetatable(key)  then return false end
+	if self.mock ~= key.mock                    then return false end
+	return self:is_expected()
+end
+function Action.generic:new (mock)
+	local a = object( self )
+	a.mock         = mock
+	a.replay_count = 0
+	a.min_replays  = 1
+	a.max_replays  = 1
+	return a
+end
+function Action.generic:set_times (a, b)
+	min = a or 1
+	max = b or min
+	min, max = tonumber(min), tonumber(max)
+	if (not min) or (not max) or (min >= math.huge)
+	             or (min ~= min) or (max ~= max) -- NaN
+	             or (min < 0) or (max <= 0) or (min > max) then
+		error( sfmt( "Unrealistic time arguments (%s, %s)"
+		           , qtostring( min )
+		           , qtostring( max )
+		           )
+		     , 0
+		     )
+	end
+	self.min_replays = min
+	self.max_replays = max
+end
+Action.generic_call = class( Action.generic )
+Action.generic_call.can_return = true
+function Action.generic_call:get_returnvalue ()
+	if self.has_returnvalue then
+		return self.returnvalue:unpack()
+	end
+end
+function Action.generic_call:set_returnvalue (...)
+	self.returnvalue = Argv:new(...)
+	self.has_returnvalue = true
+end
+function Action.generic_call:match (q)
+	if not Action.generic.match( self, q )  then return false end
+	if not self.argv:equal( q.argv )        then return false end
+	return true
+end
+function Action.generic_call:new (m, ...)
+	local a = Action.generic.new( self, m )
+	a.argv   = Argv:new(...)
+	return a
+end
+-- concrete
+Action.call = class( Action.generic_call )
+function Action.call:match (q)
+	if not Action.generic_call.match( self, q )  then return false end
+	if self.key ~= q.key                         then return false end
+	return true
+end
+function Action.call:new (m, key, ...)
+	local a = Action.generic_call.new( self, m, ... )
+	a.key = key
+	return a
+end
+function Action.call:tostring ()
+	if self.has_returnvalue then
+		return sfmt( "call %s(%s) => %s"
+		             , tostring(self.key)
+		             , self.argv:tostring()
+		             , self.returnvalue:tostring()
+		       )
+	else
+		return sfmt( "call %s(%s)"
+		             , tostring(self.key)
+		             , self.argv:tostring()
+		       )
+	end
+end
+Action.index = class( Action.generic )
+Action.index.can_return = true
+function Action.index:get_returnvalue ()
+	return self.returnvalue
+end
+function Action.index:set_returnvalue (v)
+	self.returnvalue = v
+	self.has_returnvalue = true
+end
+function Action.index:match (q)
+	if not Action.generic.match( self, q )  then return false end
+	if self.key ~= q.key                    then return false end
+	return true
+end
+function Action.index:new (m, key)
+	local a = Action.generic.new( self, m )
+	a.key = key
+	return a
+end
+function Action.index:tostring ()
+	local key = 'index '..tostring( self.key )
+	if self.has_returnvalue then
+		return sfmt( "index %s => %s"
+		             , tostring( self.key )
+		             , qtostring( self.returnvalue )
+		       )
+	elseif self.is_callable then
+		return sfmt( "index %s()"
+		             , tostring( self.key )
+		       )
+	else
+		return sfmt( "index %s"
+		             , tostring( self.key )
+		       )
+	end
+end
+Action.newindex = class( Action.generic )
+function Action.newindex:match (q)
+	if not Action.generic.match( self, q )  then return false end
+	if self.key ~= q.key                    then return false end
+	if not value_equal( self.val, q.val )
+	   and self.val ~= Argv.ANYARG
+	   and q.val    ~= Argv.ANYARG          then return false end
+	return true
+end
+function Action.newindex:new (m, key, val)
+	local a = Action.generic.new( self, m )
+	a.key    = key
+	a.val    = val
+	return a
+end
+function Action.newindex:tostring ()
+	return sfmt( "newindex %s = %s"
+	             , tostring(self.key)
+	             , qtostring(self.val)
+	       )
+end
+Action.selfcall = class( Action.generic_call )
+function Action.selfcall:match (q)
+	return Action.generic_call.match( self, q )
+end
+function Action.selfcall:new (m, ...)
+	local a = Action.generic_call.new( self, m, ... )
+	return a
+end
+function Action.selfcall:tostring ()
+	if self.has_returnvalue then
+		return sfmt( "selfcall (%s) => %s"
+		             , self.argv:tostring()
+		             , self.returnvalue:tostring()
+		       )
+	else
+		return sfmt( "selfcall (%s)"
+		             , self.argv:tostring()
+		       )
+	end
+end
+Argv = class()
+Argv.ANYARGS = newproxy()  local ANYARGS = Argv.ANYARGS
+Argv.ANYARG  = newproxy()  local ANYARG  = Argv.ANYARG
+function Argv:equal (other)
+	local a1, n1 = self.v,  self.len
+	local a2, n2 = other.v, other.len
+	if n1-1 <= n2 and a1[n1] == ANYARGS then
+		n1 = n1-1
+		n2 = n1
+	elseif n2-1 <= n1 and a2[n2] == ANYARGS then
+		n2 = n2-1
+		n1 = n2
+	end
+	if n1 ~= n2 then
+		return false
+	end
+	for i = 1, n1 do
+		local v1, v2 = a1[i], a2[i]
+		if not value_equal(v1,v2) and v1 ~= ANYARG and v2 ~= ANYARG then
+			return false
+		end
+	end
+	return true
+end
+function Argv:new (...)
+	local av = object( self )
+	av.v = {...}
+	av.len = select('#',...)
+	for i = 1, av.len - 1 do
+		if av.v[i] == Argv.ANYARGS then
+			error( "ANYARGS not at end.", 0 )
+		end
+	end
+	return av
+end
+function Argv:tostring ()
+	local res = {}
+	local function w (v)
+		res[#res+1] = qtostring( v )
+	end
+	local av, ac = self.v, self.len
+	for i = 1, ac do
+		if av[i] == Argv.ANYARG then
+			res[#res+1] = 'ANYARG'
+		elseif av[i] == Argv.ANYARGS then
+			res[#res+1] = 'ANYARGS'
+		else
+			w( av[i] )
+		end
+		if i < ac then
+			res[#res+1] = ',' -- can not use qtostring in w()
+		end
+	end
+	return table.concat( res )
+end
+function Argv:unpack ()
+	return unpack( self.v, 1, self.len )
+end
+Callable = {}
+Callable.generic = class()
+Callable.record  = class( Callable.generic )
+Callable.replay  = class( Callable.generic )
+function Callable.generic:new ( index_action )
+	local f = object( self )
+	f.action = index_action
+	return f
+end
+function Callable.record:__call (...)
+	local index_action = self.action
+	local m = index_action.mock
+	local mc = mock_controller_map[m]
+	assert( mc.is_recording, "client uses cached callable from recording" )
+	mc:make_callable( index_action )
+	mc:add_action( Action.call:new( m, index_action.key, ... ))
+end
+function Callable.replay:__call (...)
+	local index_action = self.action
+	local m = index_action.mock
+	local mc = mock_controller_map[m]
+	local call_action = mc:lookup( Action.call:new( m, index_action.key, ... ))
+	mc:replay_action( call_action )
+	if call_action.throws_error then
+		error( call_action.errorvalue, 2 )
+	end
+	return call_action:get_returnvalue()
+end
+Controller = class()
+-- Exported methods
+function Controller:close (...)
+	if not self.is_recording then
+		error( "Can not insert close in replay mode.", 2 )
+	end
+	local action = self:get_last_action()
+	for _, close in ipairs{ ... } do
+		action:add_close( close )
+	end
+	return self -- for chaining
+end
+function Controller:depend (...)
+	if not self.is_recording then
+		error( "Can not add dependency in replay mode.", 2 )
+	end
+	local action = self:get_last_action()
+	for _, dependency in ipairs{ ... } do
+		action:add_depend( dependency )
+	end
+	return self -- for chaining
+end
+function Controller:error (value)
+	if not self.is_recording then
+		error( "Error called during replay.", 2 )
+	end
+	local action = self:get_last_action()
+	if action.has_returnvalue or action.throws_error then
+		error( "Returns and/or Error called twice for same action.", 2 )
+	end
+	action.throws_error = true
+	action.errorvalue = value
+	return self -- for chaining
+end
+function Controller:label (...)
+if not self.is_recording then
+	error( "Can not add labels in replay mode.", 2 )
+end
+local action = self:get_last_action()
+for _, label in ipairs{ ... } do
+	action:add_label( label )
+end
+return self -- for chaining
+end
+function Controller:mock ()
+	if not self.is_recording then
+		error( "New mock during replay.", 2 )
+	end
+	local m = object( Mock.record )
+	mock_controller_map[m] = self
+	return m
+end
+function Controller:new ()
+	local mc = object( self )
+	mc.actionlist   = {}
+	mc.is_recording = true
+	return mc
+end
+function Controller:replay ()
+	if not self.is_recording then
+		error( "Replay called twice.", 2 )
+	end
+	self.is_recording = false
+	for m, mc in pairs( mock_controller_map ) do
+		if mc == self then
+			setmetatable( m, Mock.replay )
+		end
+	end
+	self:update_dependencies()
+	self:assert_no_dependency_cycles()
+end
+function Controller:returns (...)
+	if not self.is_recording then
+		error( "Returns called during replay.", 2 )
+	end
+	local action = self:get_last_action()
+	assert( not action.is_callable, "lemock internal error" )
+	if not action.can_return then
+		error( "Previous action can not return anything.", 2 )
+	end
+	if action.has_returnvalue or action.throws_error then
+		error( "Returns and/or Error called twice for same action.", 2 )
+	end
+	action:set_returnvalue(...)
+	return self -- for chaining
+end
+function Controller:times (min, max)
+	if not self.is_recording then
+		error( "Can not set times in replay mode.", 0 )
+	end
+	self:get_last_action():set_times( min, max )
+	return self -- for chaining
+end
+-- convenience functions
+function Controller:anytimes()    return self:times( 0, math.huge ) end
+function Controller:atleastonce() return self:times( 1, math.huge ) end
+function Controller:verify ()
+	if self.is_recording then
+		error( "Verify called during record.", 2 )
+	end
+	for a in self:actions() do
+		a:assert_satisfied()
+	end
+end
+-- Protected methods
+function Controller:actions (q)
+	local l = self.actionlist
+	local i = 0
+	return function ()
+		i = i + 1
+		return l[i]
+	end				
+end
+function Controller:add_action (a)
+	assert( a ~= nil, "lemock internal error" ) -- breaks array property
+	table.insert( self.actionlist, a )
+end
+function Controller:assert_no_dependency_cycles ()
+	local function is_in_path (label, path)
+		if not path then return false end -- is root
+		for _, l in ipairs( path ) do
+			if l == label then return true end
+		end
+		if path.prev then return is_in_path( label, path.prev ) end
+		return false
+	end
+	local function can_block (action, node)
+		for _, label in ipairs( node ) do
+			if action:has_label( label ) then return true end
+		end
+		return false
+	end
+	local function step (action, path)
+		local new_head
+		for label in action:depends() do
+			if is_in_path( label, path ) then
+				error( "Detected dependency cycle", 0 )
+			end
+			-- only create table if needed to reduce garbage
+			if not new_head then new_head = { prev=path } end
+			new_head[#new_head+1] = label
+		end
+		return new_head
+	end
+	local function search_depth_first (path)
+		for action in self:actions() do
+			if can_block( action, path ) then
+				local new_head = step( action, path )
+				if new_head then
+					search_depth_first( new_head )
+				end
+			end
+		end
+	end
+	for action in self:actions() do
+		local root = step( action, nil )
+		if root then search_depth_first( root ) end
+	end
+end
+function Controller:close_actions( ... ) -- takes iterator
+	for label in ... do
+		for candidate in self:actions() do
+			if candidate:has_label( label ) then
+				if not candidate:is_satisfied() then
+					error( "Closes unsatisfied action: "..candidate:tostring(), 0 )
+				end
+				candidate.is_closed = true
+			end
+		end
+	end
+end
+function Controller:get_last_action ()
+	local l = self.actionlist
+	if #l == 0 then
+		error( "No action is recorded yet.", 0 )
+	end
+	return l[#l]
+end
+function Controller:lookup (actual)
+	for action in self:actions() do
+		if action:match( actual ) then
+			return action
+		end
+	end
+local expected = {}
+for _, a in ipairs( self.actionlist ) do
+	if a:is_expected() and not a.is_callable then
+		expected[#expected+1] = a:tostring()
+	end
+end
+table.sort( expected )
+if #expected == 0 then
+	expected[1] = "(Nothing)"
+end
+	error( sfmt( "Unexpected action %s, expected:\n%s\n"
+	             , actual:tostring()
+	             , table.concat(expected,'\n')
+	       )
+	       , 0
+	)
+end
+function Controller:make_callable (action)
+	if action.has_returnvalue then
+		error( "Can not call "..action.key..". It has a returnvalue.", 0 )
+	end
+	action.is_callable = true
+	action.min_replays = 0
+	action.max_replays = math.huge
+end
+function Controller:new ()
+	local mc = object( self )
+	mc.actionlist   = {}
+	mc.is_recording = true
+	return mc
+end
+function Controller:replay_action ( action )
+	assert( action:is_expected(), "lemock internal error" )
+	assert( action.replay_count < action.max_replays, "lemock internal error" )
+	local was_satisfied = action:is_satisfied()
+	action.replay_count = action.replay_count + 1
+	if not was_satisfied and action.labellist and action:is_satisfied() then
+		self:update_dependencies()
+	end
+	if action.closelist then
+		self:close_actions( action:closes() )
+	end
+end
+function Controller:update_dependencies ()
+	local blocked = {}
+	for action in self:actions() do
+		for label in action:blocks() do
+			blocked[label] = true
+		end
+	end
+	local function is_blocked (action)
+		for label in action:depends() do
+			if blocked[label] then return true end
+		end
+		return false
+	end
+	for action in self:actions() do
+		action.is_blocked = is_blocked( action )
+	end
+end
+Mock = { record={}, replay={} } -- no self-referencing __index!
+function Mock.record:__index (key)
+	local mc = mock_controller_map[self]
+	local action = Action.index:new( self, key )
+	mc:add_action( action )
+	return Callable.record:new( action )
+end
+function Mock.record:__newindex (key, val)
+	local mc = mock_controller_map[self]
+	mc:add_action( Action.newindex:new( self, key, val ))
+end
+function Mock.record:__call (...)
+	local mc = mock_controller_map[self]
+	mc:add_action( Action.selfcall:new( self, ... ))
+end
+function Mock.replay:__index (key)
+	local mc = mock_controller_map[self]
+	local index_action = mc:lookup( Action.index:new( self, key ))
+	mc:replay_action( index_action )
+	if index_action.throws_error then
+		error( index_action.errorvalue, 2 )
+	end
+	if index_action.is_callable then
+		return Callable.replay:new( index_action )
+	else
+		return index_action:get_returnvalue()
+	end
+end
+function Mock.replay:__newindex (key, val)
+	local mc = mock_controller_map[self]
+	local newindex_action = mc:lookup( Action.newindex:new( self, key, val ))
+	mc:replay_action( newindex_action )
+	if newindex_action.throws_error then
+		error( newindex_action.errorvalue, 2 )
+	end
+end
+function Mock.replay:__call (...)
+	local mc = mock_controller_map[self]
+	local selfcall_action = mc:lookup( Action.selfcall:new( self, ... ))
+	mc:replay_action( selfcall_action )
+	if selfcall_action.throws_error then
+		error( selfcall_action.errorvalue, 2 )
+	end
+	return selfcall_action:get_returnvalue()
+end
+function controller ()
+	local exported_methods = {
+		'anytimes',
+		'atleastonce',
+		'close',
+		'depend',
+		'error',
+		'label',
+		'mock',
+		'new',
+		'replay',
+		'returns',
+		'times',
+		'verify',
+	}
+	local mc = Controller:new()
+	local wrapper = {}
+	for _, method in ipairs( exported_methods ) do
+		wrapper[ method ] = function (self, ...)
+			return mc[ method ]( mc, ... )
+		end
+	end
+	wrapper.ANYARG  = Argv.ANYARG
+	wrapper.ANYARGS = Argv.ANYARGS
+	return wrapper
+end
+return _M
diff --git a/build/mkfile b/build/mkfile
new file mode 100644
index 0000000..16b57ba
--- /dev/null
+++ b/build/mkfile
@@ -0,0 +1,20 @@
+MKSHELL = rc
+
+all:V: htdocs
+
+wrappers  = `{find www -name '*.t2t'}
+htmls = ${wrappers:www/%.t2t=htdocs/%.html}
+
+htdocs:V: $htmls
+
+$htmls: www/menubar.html
+htdocs/COPYRIGHT.html: ../COPYRIGHT
+htdocs/DEVEL.html:     ../DEVEL
+htdocs/HISTORY.html:   ../HISTORY
+htdocs/README.html:    ../README
+
+htdocs/%.html: www/%.t2t
+	txt2tags -t html -i www/$stem.t2t -o $target
+
+htdocs/userguide.html: www/userguide.t2t userguide.t2t
+	txt2tags -t html --toc --toc-level 2 -i www/userguide.t2t -o $target
diff --git a/build/unit/action.lua b/build/unit/action.lua
new file mode 100644
index 0000000..3cc75f0
--- /dev/null
+++ b/build/unit/action.lua
@@ -0,0 +1,603 @@
+-- ../src/unittestfiles.nw:145
+	
+-- ../src/misc.nw:7
+	------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------
+	-- Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+	-- See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+
+-- ../src/unittestfiles.nw:146
+	
+	require 'lunit'
+	module( 'unit.action', lunit.testcase, package.seeall )
+	
+	local class, object, qtostring, sfmt
+	
+-- ../src/helperfunctions.nw:12
+	function object (class)
+		return setmetatable( {}, class )
+	end
+	function class (parent)
+		local c = object(parent)
+		c.__index = c
+		return c
+	end
+-- ../src/unittestfiles.nw:152
+	
+-- ../src/helperfunctions.nw:29
+	function value_equal (a, b)
+		if a == b then return true end
+		if a ~= a and b ~= b then return true end -- NaN == NaN
+		return false
+	end
+-- ../src/unittestfiles.nw:153
+	
+-- ../src/tostring.nw:23
+	sfmt = string.format
+	function qtostring (v)
+		if type(v) == 'string' then
+			return sfmt( '%q', v )
+		else
+			return tostring( v )
+		end
+	end
+-- ../src/unittestfiles.nw:154
+	
+	local Action, Argv
+	
+-- ../src/class/action.nw:24
+	Action = {}
+	
+	-- abstract
+	
+-- ../src/class/action.nw:41
+	Action.generic = class()
+	
+	
+-- ../src/restrictions.nw:607
+	function Action.generic:add_close (label)
+		add_to_set( self, 'closelist', label )
+	end
+-- ../src/class/action.nw:44
+	
+-- ../src/restrictions.nw:443
+	function Action.generic:add_depend (d)
+		add_to_set( self, 'dependlist', d )
+	end
+
+-- ../src/class/action.nw:45
+	
+-- ../src/restrictions.nw:207
+	function Action.generic:add_label (label)
+		add_to_set( self, 'labellist', label )
+	end
+
+-- ../src/class/action.nw:46
+	
+-- ../src/main.nw:338
+	function Action.generic:assert_satisfied ()
+		assert( self.replay_count <= self.max_replays, "lemock internal error" )
+		if not (
+-- ../src/main.nw:330
+	self.min_replays <= self.replay_count
+
+-- ../src/main.nw:340
+                                  ) then
+			error( sfmt( "Wrong replay count %d (expected %d..%d) for %s"
+			             , self.replay_count
+			             , self.min_replays, self.max_replays
+			             , self:tostring()
+			       )
+			       , 0
+			)
+		end
+	end
+-- ../src/class/action.nw:47
+	
+-- ../src/restrictions.nw:220
+	function Action.generic:blocks ()
+		if self:is_satisfied() then
+			return function () end
+		end
+		return elements_of_set( self, 'labellist' )
+	end
+-- ../src/class/action.nw:48
+	
+-- ../src/restrictions.nw:630
+	function Action.generic:closes ()
+		return elements_of_set( self, 'closelist' )
+	end
+-- ../src/class/action.nw:49
+	
+-- ../src/restrictions.nw:448
+	function Action.generic:depends ()
+		return elements_of_set( self, 'dependlist' )
+	end
+-- ../src/class/action.nw:50
+	
+-- ../src/restrictions.nw:212
+	function Action.generic:has_label (l)
+		for x in elements_of_set( self, 'labellist' ) do
+			if x == l then return true end
+		end
+		return false
+	end
+
+-- ../src/class/action.nw:51
+	
+-- ../src/main.nw:247
+	function Action.generic:is_expected ()
+		return self.replay_count < self.max_replays
+		   and not self.is_blocked
+		   and not self.is_closed
+	end
+
+-- ../src/class/action.nw:52
+	
+-- ../src/main.nw:333
+	function Action.generic:is_satisfied ()
+		return 
+-- ../src/main.nw:330
+	self.min_replays <= self.replay_count
+
+-- ../src/main.nw:335
+	end
+
+-- ../src/class/action.nw:53
+	
+-- ../src/main.nw:269
+	function Action.generic:match (key)
+		if getmetatable(self) ~= getmetatable(key)  then return false end
+		if self.mock ~= key.mock                    then return false end
+		return self:is_expected()
+	end
+-- ../src/class/action.nw:54
+	
+-- ../src/main.nw:219
+	function Action.generic:new (mock)
+		local a = object( self )
+		a.mock         = mock
+		a.replay_count = 0
+		a.min_replays  = 1
+		a.max_replays  = 1
+		return a
+	end
+-- ../src/class/action.nw:55
+	
+-- ../src/restrictions.nw:102
+	function Action.generic:set_times (a, b)
+		min = a or 1
+		max = b or min
+		min, max = tonumber(min), tonumber(max)
+		if (not min) or (not max) or (min >= math.huge)
+		             or (min ~= min) or (max ~= max) -- NaN
+		             or (min < 0) or (max <= 0) or (min > max) then
+			error( sfmt( "Unrealistic time arguments (%s, %s)"
+			           , qtostring( min )
+			           , qtostring( max )
+			           )
+			     , 0
+			     )
+		end
+		self.min_replays = min
+		self.max_replays = max
+	end
+
+
+-- ../src/class/action.nw:28
+	
+-- ../src/class/action.nw:59
+	Action.generic_call = class( Action.generic )
+	
+	Action.generic_call.can_return = true
+	
+-- ../src/action/generic_call.nw:76
+	function Action.generic_call:get_returnvalue ()
+		if self.has_returnvalue then
+			return self.returnvalue:unpack()
+		end
+	end
+-- ../src/class/action.nw:63
+	
+-- ../src/action/generic_call.nw:56
+	function Action.generic_call:set_returnvalue (...)
+		self.returnvalue = Argv:new(...)
+		self.has_returnvalue = true
+	end
+-- ../src/class/action.nw:64
+	
+	
+-- ../src/action/generic_call.nw:45
+	function Action.generic_call:match (q)
+		if not Action.generic.match( self, q )  then return false end
+		if not self.argv:equal( q.argv )        then return false end
+		return true
+	end
+-- ../src/class/action.nw:66
+	
+-- ../src/action/generic_call.nw:32
+	function Action.generic_call:new (m, ...)
+		local a = Action.generic.new( self, m )
+		a.argv   = Argv:new(...)
+		return a
+	end
+-- ../src/class/action.nw:29
+	
+	-- concrete
+	
+-- ../src/class/action.nw:93
+	Action.call = class( Action.generic_call )
+	
+	
+-- ../src/action/call.nw:118
+	function Action.call:match (q)
+		if not Action.generic_call.match( self, q )  then return false end
+		if self.key ~= q.key                         then return false end
+		return true
+	end
+-- ../src/class/action.nw:96
+	
+-- ../src/action/call.nw:82
+	function Action.call:new (m, key, ...)
+		local a = Action.generic_call.new( self, m, ... )
+		a.key = key
+		return a
+	end
+-- ../src/class/action.nw:97
+	
+-- ../src/tostring.nw:101
+	function Action.call:tostring ()
+		if self.has_returnvalue then
+			return sfmt( "call %s(%s) => %s"
+			             , tostring(self.key)
+			             , self.argv:tostring()
+			             , self.returnvalue:tostring()
+			       )
+		else
+			return sfmt( "call %s(%s)"
+			             , tostring(self.key)
+			             , self.argv:tostring()
+			       )
+		end
+	end
+
+
+-- ../src/class/action.nw:32
+	
+-- ../src/class/action.nw:81
+	Action.index = class( Action.generic )
+	
+	Action.index.can_return = true
+	
+-- ../src/action/index.nw:134
+	function Action.index:get_returnvalue ()
+		return self.returnvalue
+	end
+-- ../src/class/action.nw:85
+	
+-- ../src/action/index.nw:85
+	function Action.index:set_returnvalue (v)
+		self.returnvalue = v
+		self.has_returnvalue = true
+	end
+-- ../src/class/action.nw:86
+	
+	
+-- ../src/action/index.nw:123
+	function Action.index:match (q)
+		if not Action.generic.match( self, q )  then return false end
+		if self.key ~= q.key                    then return false end
+		return true
+	end
+-- ../src/class/action.nw:88
+	
+-- ../src/action/index.nw:67
+	function Action.index:new (m, key)
+		local a = Action.generic.new( self, m )
+		a.key = key
+		return a
+	end
+-- ../src/class/action.nw:89
+	
+-- ../src/tostring.nw:70
+	function Action.index:tostring ()
+		local key = 'index '..tostring( self.key )
+		if self.has_returnvalue then
+			return sfmt( "index %s => %s"
+			             , tostring( self.key )
+			             , qtostring( self.returnvalue )
+			       )
+		elseif self.is_callable then
+			return sfmt( "index %s()"
+			             , tostring( self.key )
+			       )
+		else
+			return sfmt( "index %s"
+			             , tostring( self.key )
+			       )
+		end
+	end
+
+
+-- ../src/class/action.nw:33
+	
+-- ../src/class/action.nw:73
+	Action.newindex = class( Action.generic )
+	
+	
+-- ../src/action/newindex.nw:102
+	function Action.newindex:match (q)
+		if not Action.generic.match( self, q )  then return false end
+		if self.key ~= q.key                    then return false end
+		if not value_equal( self.val, q.val )
+		   and self.val ~= Argv.ANYARG
+		   and q.val    ~= Argv.ANYARG          then return false end
+		return true
+	end
+-- ../src/class/action.nw:76
+	
+-- ../src/action/newindex.nw:54
+	function Action.newindex:new (m, key, val)
+		local a = Action.generic.new( self, m )
+		a.key    = key
+		a.val    = val
+		return a
+	end
+-- ../src/class/action.nw:77
+	
+-- ../src/tostring.nw:45
+	function Action.newindex:tostring ()
+		return sfmt( "newindex %s = %s"
+		             , tostring(self.key)
+		             , qtostring(self.val)
+		       )
+	end
+
+
+-- ../src/class/action.nw:34
+	
+-- ../src/class/action.nw:101
+	Action.selfcall = class( Action.generic_call )
+	
+	
+-- ../src/action/selfcall.nw:93
+	function Action.selfcall:match (q)
+		return Action.generic_call.match( self, q )
+	end
+-- ../src/class/action.nw:104
+	
+-- ../src/action/selfcall.nw:61
+	function Action.selfcall:new (m, ...)
+		local a = Action.generic_call.new( self, m, ... )
+		return a
+	end
+-- ../src/class/action.nw:105
+	
+-- ../src/tostring.nw:129
+	function Action.selfcall:tostring ()
+		if self.has_returnvalue then
+			return sfmt( "selfcall (%s) => %s"
+			             , self.argv:tostring()
+			             , self.returnvalue:tostring()
+			       )
+		else
+			return sfmt( "selfcall (%s)"
+			             , self.argv:tostring()
+			       )
+		end
+	end
+-- ../src/unittestfiles.nw:157
+	
+-- ../src/class/argv.nw:6
+	Argv = class()
+	
+	
+-- ../src/argv.nw:119
+	Argv.ANYARGS = newproxy()  local ANYARGS = Argv.ANYARGS
+	Argv.ANYARG  = newproxy()  local ANYARG  = Argv.ANYARG
+	function Argv:equal (other)
+		local a1, n1 = self.v,  self.len
+		local a2, n2 = other.v, other.len
+		if n1-1 <= n2 and a1[n1] == ANYARGS then
+			n1 = n1-1
+			n2 = n1
+		elseif n2-1 <= n1 and a2[n2] == ANYARGS then
+			n2 = n2-1
+			n1 = n2
+		end
+		if n1 ~= n2 then
+			return false
+		end
+		for i = 1, n1 do
+			local v1, v2 = a1[i], a2[i]
+			if not value_equal(v1,v2) and v1 ~= ANYARG and v2 ~= ANYARG then
+				return false
+			end
+		end
+		return true
+	end
+-- ../src/class/argv.nw:9
+	
+-- ../src/argv.nw:46
+	function Argv:new (...)
+		local av = object( self )
+		av.v = {...}
+		av.len = select('#',...)
+		for i = 1, av.len - 1 do
+			if av.v[i] == Argv.ANYARGS then
+				error( "ANYARGS not at end.", 0 )
+			end
+		end
+		return av
+	end
+-- ../src/class/argv.nw:10
+	
+-- ../src/tostring.nw:163
+	function Argv:tostring ()
+		local res = {}
+		local function w (v)
+			res[#res+1] = qtostring( v )
+		end
+		local av, ac = self.v, self.len
+		for i = 1, ac do
+			if av[i] == Argv.ANYARG then
+				res[#res+1] = 'ANYARG'
+			elseif av[i] == Argv.ANYARGS then
+				res[#res+1] = 'ANYARGS'
+			else
+				w( av[i] )
+			end
+			if i < ac then
+				res[#res+1] = ',' -- can not use qtostring in w()
+			end
+		end
+		return table.concat( res )
+	end
+-- ../src/class/argv.nw:11
+	
+-- ../src/argv.nw:156
+	function Argv:unpack ()
+		return unpack( self.v, 1, self.len )
+	end
+-- ../src/unittestfiles.nw:158
+	
+	
+-- ../src/action/call.nw:106
+	function call_match_test ()
+		local m = {}
+		local a = Action.call:new( m, 'foo', 4, 'bb' )
+		assert_true(  a:match( Action.call:new( m, 'foo', 4, 'bb' )))
+		assert_false( a:match( Action.call:new( {}, 'foo', 4, 'bb' )))
+		assert_false( a:match( Action.call:new( m, 'bar', 4, 'bb' )))
+		assert_false( a:match( Action.call:new( m, 'foo', 1, 'bb' )))
+		assert_false( a:match( Action.call:new( m, 'foo', 4, 'b' )))
+		assert_false( a:match( Action.call:new( m, 'foo', 4, 'bb', 'cc' )))
+	end
+
+-- ../src/unittestfiles.nw:160
+	
+-- ../src/tostring.nw:93
+	function call_tostring_test ()
+		local a = Action.call:new( {}, 'foo', 1, '"', 3 )
+		assert_equal( 'call foo(1,"\\"",3)', a:tostring() )
+		a:set_returnvalue( 'false', false )
+		assert_equal( 'call foo(1,"\\"",3) => "false",false', a:tostring() )
+	end
+
+-- ../src/unittestfiles.nw:161
+	
+-- ../src/action/generic_call.nw:66
+	function generic_call_set_and_get_returnvalue_test ()
+		local a = Action.generic_call:new()
+		assert_equal( 0, select('#', a:get_returnvalue() ))
+		a:set_returnvalue( nil, false )
+		local r1, r2 = a:get_returnvalue()
+		assert_equal( nil, r1 )
+		assert_equal( false, r2 )
+	end
+
+-- ../src/unittestfiles.nw:162
+	
+-- ../src/action/index.nw:114
+	function index_match_test ()
+		local m = {}
+		local a = Action.index:new( m, -1 )
+		assert_true(  a:match( Action.index:new( m, -1 )))
+		assert_false( a:match( Action.index:new( {}, -1 )))
+		assert_false( a:match( Action.index:new( m, 'a' )))
+	end
+
+-- ../src/unittestfiles.nw:163
+	
+-- ../src/action/index.nw:59
+	function create_index_action_test ()
+		local m = {}
+		local a = Action.index:new( m, 'foo' )
+		assert_equal( m, a.mock )
+		assert_equal( 'foo', a.key )
+	end
+
+-- ../src/unittestfiles.nw:164
+	
+-- ../src/action/index.nw:78
+	function index_returnvalue_test ()
+		local a = Action.index:new( {}, -3 )
+		a:set_returnvalue( 'foo' )
+		assert_equal( 'foo', a:get_returnvalue() )
+	end
+
+-- ../src/unittestfiles.nw:165
+	
+-- ../src/tostring.nw:57
+	function index_tostring_test ()
+		local a = Action.index:new( {}, true )
+		assert_equal( 'index true', a:tostring() )
+		a:set_returnvalue('"false"')
+		assert_equal( 'index true => "\\"false\\""', a:tostring() )
+	end
+	function callable_index_tostring_test ()
+		local a = Action.index:new( {}, 'f' )
+		a.is_callable = true
+		assert_equal( 'index f()', a:tostring() )
+	end
+
+-- ../src/unittestfiles.nw:166
+	
+-- ../src/action/newindex.nw:76
+	function newindex_match_test ()
+		local m = {}
+		local a = Action.newindex:new( m, 'foo', 17 )
+		assert_true(  a:match( Action.newindex:new( m, 'foo', 17 )))
+		assert_false( a:match( Action.newindex:new( {}, 'foo', 17 )))
+		assert_false( a:match( Action.newindex:new( m, 'fo', 17 )))
+		assert_false( a:match( Action.newindex:new( m, 'foo', 7 )))
+	end
+	function newindex_anyarg_test ()
+		local m = {}
+		local a = Action.newindex:new( m, 'foo', Argv.ANYARG )
+		local b = Action.newindex:new( m, 'foo', 33 )
+		local c = Action.newindex:new( m, 'foo', nil )
+		assert_true( a:match(b) )
+		assert_true( b:match(a) )
+		assert_true( a:match(c) )
+		assert_true( c:match(a) )
+	end
+	function newindex_NaN_test ()
+		local m = {}
+		local nan = 0/0
+		local a = Action.newindex:new( m, m, nan )
+		assert_true( a:match( Action.newindex:new( m, m, nan )))
+	end
+
+-- ../src/unittestfiles.nw:167
+	
+-- ../src/tostring.nw:37
+	function newindex_tostring_test ()
+		local a = Action.newindex:new( {}, 'key', 7 )
+		assert_equal( 'newindex key = 7', a:tostring() )
+		a = Action.newindex:new( {}, true, '7' )
+		assert_equal( 'newindex true = "7"', a:tostring() )
+	end
+
+-- ../src/unittestfiles.nw:168
+	
+-- ../src/action/selfcall.nw:82
+	function selfcall_match_test ()
+		local m = {}
+		local a = Action.selfcall:new( m, 5, nil, false )
+		assert_true(  a:match( Action.selfcall:new( m, 5, nil, false )))
+		assert_false( a:match( Action.selfcall:new( {}, 5, nil, false )))
+		assert_false( a:match( Action.selfcall:new( m, nil, nil, false )))
+		assert_false( a:match( Action.selfcall:new( m, 5, false, false )))
+		assert_false( a:match( Action.selfcall:new( m, 5, nil, nil )))
+	end
+
+-- ../src/unittestfiles.nw:169
+	
+-- ../src/tostring.nw:121
+	function selfcall_tostring_test ()
+		local a = Action.selfcall:new( {}, 1, '"', nil )
+		assert_equal( 'selfcall (1,"\\"",nil)', a:tostring() )
+		a:set_returnvalue( 'false', false )
+		assert_equal( 'selfcall (1,"\\"",nil) => "false",false', a:tostring() )
+	end
+
diff --git a/build/unit/action_generic.lua b/build/unit/action_generic.lua
new file mode 100644
index 0000000..7b91c3b
--- /dev/null
+++ b/build/unit/action_generic.lua
@@ -0,0 +1,598 @@
+-- ../src/unittestfiles.nw:108
+	
+-- ../src/misc.nw:7
+	------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------
+	-- Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+	-- See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+
+-- ../src/unittestfiles.nw:109
+	
+	require 'lunit'
+	module( 'unit.action_generic', lunit.testcase, package.seeall )
+	
+	local class, object, qtostring, sfmt, add_to_set, elements_of_set
+	
+-- ../src/helperfunctions.nw:12
+	function object (class)
+		return setmetatable( {}, class )
+	end
+	function class (parent)
+		local c = object(parent)
+		c.__index = c
+		return c
+	end
+-- ../src/unittestfiles.nw:115
+	
+-- ../src/tostring.nw:23
+	sfmt = string.format
+	function qtostring (v)
+		if type(v) == 'string' then
+			return sfmt( '%q', v )
+		else
+			return tostring( v )
+		end
+	end
+-- ../src/unittestfiles.nw:116
+	
+-- ../src/helperfunctions.nw:47
+	function add_to_set (o, setname, element)
+		if not o[setname] then
+			o[setname] = {}
+		end
+		local l = o[setname]
+		
+		for i = 1, #l do
+			if l[i] == element then return end
+		end
+		l[#l+1] = element
+	end
+	function elements_of_set (o, setname)
+		local l = o[setname]
+		local i = l and #l+1 or 0
+		return function ()
+			i = i - 1
+			if i > 0 then return l[i] end
+		end
+	end
+-- ../src/unittestfiles.nw:117
+	
+	local Action, Argv
+	
+-- ../src/class/action.nw:24
+	Action = {}
+	
+	-- abstract
+	
+-- ../src/class/action.nw:41
+	Action.generic = class()
+	
+	
+-- ../src/restrictions.nw:607
+	function Action.generic:add_close (label)
+		add_to_set( self, 'closelist', label )
+	end
+-- ../src/class/action.nw:44
+	
+-- ../src/restrictions.nw:443
+	function Action.generic:add_depend (d)
+		add_to_set( self, 'dependlist', d )
+	end
+
+-- ../src/class/action.nw:45
+	
+-- ../src/restrictions.nw:207
+	function Action.generic:add_label (label)
+		add_to_set( self, 'labellist', label )
+	end
+
+-- ../src/class/action.nw:46
+	
+-- ../src/main.nw:338
+	function Action.generic:assert_satisfied ()
+		assert( self.replay_count <= self.max_replays, "lemock internal error" )
+		if not (
+-- ../src/main.nw:330
+	self.min_replays <= self.replay_count
+
+-- ../src/main.nw:340
+                                  ) then
+			error( sfmt( "Wrong replay count %d (expected %d..%d) for %s"
+			             , self.replay_count
+			             , self.min_replays, self.max_replays
+			             , self:tostring()
+			       )
+			       , 0
+			)
+		end
+	end
+-- ../src/class/action.nw:47
+	
+-- ../src/restrictions.nw:220
+	function Action.generic:blocks ()
+		if self:is_satisfied() then
+			return function () end
+		end
+		return elements_of_set( self, 'labellist' )
+	end
+-- ../src/class/action.nw:48
+	
+-- ../src/restrictions.nw:630
+	function Action.generic:closes ()
+		return elements_of_set( self, 'closelist' )
+	end
+-- ../src/class/action.nw:49
+	
+-- ../src/restrictions.nw:448
+	function Action.generic:depends ()
+		return elements_of_set( self, 'dependlist' )
+	end
+-- ../src/class/action.nw:50
+	
+-- ../src/restrictions.nw:212
+	function Action.generic:has_label (l)
+		for x in elements_of_set( self, 'labellist' ) do
+			if x == l then return true end
+		end
+		return false
+	end
+
+-- ../src/class/action.nw:51
+	
+-- ../src/main.nw:247
+	function Action.generic:is_expected ()
+		return self.replay_count < self.max_replays
+		   and not self.is_blocked
+		   and not self.is_closed
+	end
+
+-- ../src/class/action.nw:52
+	
+-- ../src/main.nw:333
+	function Action.generic:is_satisfied ()
+		return 
+-- ../src/main.nw:330
+	self.min_replays <= self.replay_count
+
+-- ../src/main.nw:335
+	end
+
+-- ../src/class/action.nw:53
+	
+-- ../src/main.nw:269
+	function Action.generic:match (key)
+		if getmetatable(self) ~= getmetatable(key)  then return false end
+		if self.mock ~= key.mock                    then return false end
+		return self:is_expected()
+	end
+-- ../src/class/action.nw:54
+	
+-- ../src/main.nw:219
+	function Action.generic:new (mock)
+		local a = object( self )
+		a.mock         = mock
+		a.replay_count = 0
+		a.min_replays  = 1
+		a.max_replays  = 1
+		return a
+	end
+-- ../src/class/action.nw:55
+	
+-- ../src/restrictions.nw:102
+	function Action.generic:set_times (a, b)
+		min = a or 1
+		max = b or min
+		min, max = tonumber(min), tonumber(max)
+		if (not min) or (not max) or (min >= math.huge)
+		             or (min ~= min) or (max ~= max) -- NaN
+		             or (min < 0) or (max <= 0) or (min > max) then
+			error( sfmt( "Unrealistic time arguments (%s, %s)"
+			           , qtostring( min )
+			           , qtostring( max )
+			           )
+			     , 0
+			     )
+		end
+		self.min_replays = min
+		self.max_replays = max
+	end
+
+
+-- ../src/class/action.nw:28
+	
+-- ../src/class/action.nw:59
+	Action.generic_call = class( Action.generic )
+	
+	Action.generic_call.can_return = true
+	
+-- ../src/action/generic_call.nw:76
+	function Action.generic_call:get_returnvalue ()
+		if self.has_returnvalue then
+			return self.returnvalue:unpack()
+		end
+	end
+-- ../src/class/action.nw:63
+	
+-- ../src/action/generic_call.nw:56
+	function Action.generic_call:set_returnvalue (...)
+		self.returnvalue = Argv:new(...)
+		self.has_returnvalue = true
+	end
+-- ../src/class/action.nw:64
+	
+	
+-- ../src/action/generic_call.nw:45
+	function Action.generic_call:match (q)
+		if not Action.generic.match( self, q )  then return false end
+		if not self.argv:equal( q.argv )        then return false end
+		return true
+	end
+-- ../src/class/action.nw:66
+	
+-- ../src/action/generic_call.nw:32
+	function Action.generic_call:new (m, ...)
+		local a = Action.generic.new( self, m )
+		a.argv   = Argv:new(...)
+		return a
+	end
+-- ../src/class/action.nw:29
+	
+	-- concrete
+	
+-- ../src/class/action.nw:93
+	Action.call = class( Action.generic_call )
+	
+	
+-- ../src/action/call.nw:118
+	function Action.call:match (q)
+		if not Action.generic_call.match( self, q )  then return false end
+		if self.key ~= q.key                         then return false end
+		return true
+	end
+-- ../src/class/action.nw:96
+	
+-- ../src/action/call.nw:82
+	function Action.call:new (m, key, ...)
+		local a = Action.generic_call.new( self, m, ... )
+		a.key = key
+		return a
+	end
+-- ../src/class/action.nw:97
+	
+-- ../src/tostring.nw:101
+	function Action.call:tostring ()
+		if self.has_returnvalue then
+			return sfmt( "call %s(%s) => %s"
+			             , tostring(self.key)
+			             , self.argv:tostring()
+			             , self.returnvalue:tostring()
+			       )
+		else
+			return sfmt( "call %s(%s)"
+			             , tostring(self.key)
+			             , self.argv:tostring()
+			       )
+		end
+	end
+
+
+-- ../src/class/action.nw:32
+	
+-- ../src/class/action.nw:81
+	Action.index = class( Action.generic )
+	
+	Action.index.can_return = true
+	
+-- ../src/action/index.nw:134
+	function Action.index:get_returnvalue ()
+		return self.returnvalue
+	end
+-- ../src/class/action.nw:85
+	
+-- ../src/action/index.nw:85
+	function Action.index:set_returnvalue (v)
+		self.returnvalue = v
+		self.has_returnvalue = true
+	end
+-- ../src/class/action.nw:86
+	
+	
+-- ../src/action/index.nw:123
+	function Action.index:match (q)
+		if not Action.generic.match( self, q )  then return false end
+		if self.key ~= q.key                    then return false end
+		return true
+	end
+-- ../src/class/action.nw:88
+	
+-- ../src/action/index.nw:67
+	function Action.index:new (m, key)
+		local a = Action.generic.new( self, m )
+		a.key = key
+		return a
+	end
+-- ../src/class/action.nw:89
+	
+-- ../src/tostring.nw:70
+	function Action.index:tostring ()
+		local key = 'index '..tostring( self.key )
+		if self.has_returnvalue then
+			return sfmt( "index %s => %s"
+			             , tostring( self.key )
+			             , qtostring( self.returnvalue )
+			       )
+		elseif self.is_callable then
+			return sfmt( "index %s()"
+			             , tostring( self.key )
+			       )
+		else
+			return sfmt( "index %s"
+			             , tostring( self.key )
+			       )
+		end
+	end
+
+
+-- ../src/class/action.nw:33
+	
+-- ../src/class/action.nw:73
+	Action.newindex = class( Action.generic )
+	
+	
+-- ../src/action/newindex.nw:102
+	function Action.newindex:match (q)
+		if not Action.generic.match( self, q )  then return false end
+		if self.key ~= q.key                    then return false end
+		if not value_equal( self.val, q.val )
+		   and self.val ~= Argv.ANYARG
+		   and q.val    ~= Argv.ANYARG          then return false end
+		return true
+	end
+-- ../src/class/action.nw:76
+	
+-- ../src/action/newindex.nw:54
+	function Action.newindex:new (m, key, val)
+		local a = Action.generic.new( self, m )
+		a.key    = key
+		a.val    = val
+		return a
+	end
+-- ../src/class/action.nw:77
+	
+-- ../src/tostring.nw:45
+	function Action.newindex:tostring ()
+		return sfmt( "newindex %s = %s"
+		             , tostring(self.key)
+		             , qtostring(self.val)
+		       )
+	end
+
+
+-- ../src/class/action.nw:34
+	
+-- ../src/class/action.nw:101
+	Action.selfcall = class( Action.generic_call )
+	
+	
+-- ../src/action/selfcall.nw:93
+	function Action.selfcall:match (q)
+		return Action.generic_call.match( self, q )
+	end
+-- ../src/class/action.nw:104
+	
+-- ../src/action/selfcall.nw:61
+	function Action.selfcall:new (m, ...)
+		local a = Action.generic_call.new( self, m, ... )
+		return a
+	end
+-- ../src/class/action.nw:105
+	
+-- ../src/tostring.nw:129
+	function Action.selfcall:tostring ()
+		if self.has_returnvalue then
+			return sfmt( "selfcall (%s) => %s"
+			             , self.argv:tostring()
+			             , self.returnvalue:tostring()
+			       )
+		else
+			return sfmt( "selfcall (%s)"
+			             , self.argv:tostring()
+			       )
+		end
+	end
+-- ../src/unittestfiles.nw:120
+	
+-- ../src/class/argv.nw:6
+	Argv = class()
+	
+	
+-- ../src/argv.nw:119
+	Argv.ANYARGS = newproxy()  local ANYARGS = Argv.ANYARGS
+	Argv.ANYARG  = newproxy()  local ANYARG  = Argv.ANYARG
+	function Argv:equal (other)
+		local a1, n1 = self.v,  self.len
+		local a2, n2 = other.v, other.len
+		if n1-1 <= n2 and a1[n1] == ANYARGS then
+			n1 = n1-1
+			n2 = n1
+		elseif n2-1 <= n1 and a2[n2] == ANYARGS then
+			n2 = n2-1
+			n1 = n2
+		end
+		if n1 ~= n2 then
+			return false
+		end
+		for i = 1, n1 do
+			local v1, v2 = a1[i], a2[i]
+			if not value_equal(v1,v2) and v1 ~= ANYARG and v2 ~= ANYARG then
+				return false
+			end
+		end
+		return true
+	end
+-- ../src/class/argv.nw:9
+	
+-- ../src/argv.nw:46
+	function Argv:new (...)
+		local av = object( self )
+		av.v = {...}
+		av.len = select('#',...)
+		for i = 1, av.len - 1 do
+			if av.v[i] == Argv.ANYARGS then
+				error( "ANYARGS not at end.", 0 )
+			end
+		end
+		return av
+	end
+-- ../src/class/argv.nw:10
+	
+-- ../src/tostring.nw:163
+	function Argv:tostring ()
+		local res = {}
+		local function w (v)
+			res[#res+1] = qtostring( v )
+		end
+		local av, ac = self.v, self.len
+		for i = 1, ac do
+			if av[i] == Argv.ANYARG then
+				res[#res+1] = 'ANYARG'
+			elseif av[i] == Argv.ANYARGS then
+				res[#res+1] = 'ANYARGS'
+			else
+				w( av[i] )
+			end
+			if i < ac then
+				res[#res+1] = ',' -- can not use qtostring in w()
+			end
+		end
+		return table.concat( res )
+	end
+-- ../src/class/argv.nw:11
+	
+-- ../src/argv.nw:156
+	function Argv:unpack ()
+		return unpack( self.v, 1, self.len )
+	end
+-- ../src/unittestfiles.nw:121
+	
+	local A = Action.generic
+	Action = nil -- only allow generic action
+	function A:tostring () return "<generic action>" end
+	
+	local a
+	
+	function setup ()
+		a = A:new()
+	end
+	
+	
+-- ../src/restrictions.nw:422
+	function add_depend_test ()
+		local ls = { 0, 'foo', 1/0, a, {} }
+		local seen = {}
+		for _, l in ipairs( ls ) do
+			seen[l] = 0
+			a:add_depend( l )
+		end
+		for l in a:depends() do
+			seen[l] = seen[l] + 1
+		end
+		for _, l in ipairs( ls ) do
+			assert_equal( 1, seen[l], "Mismatch for "..qtostring(l) )
+		end
+	end
+	function dependencies_dont_iterate_on_empty_list_test ()
+		for _ in a:depends() do
+			fail( "unexpected dependency" )
+		end
+	end
+
+-- ../src/unittestfiles.nw:133
+	
+-- ../src/restrictions.nw:178
+	function label_test ()
+		local ls = { 1/0, 0, false, {}, a, "foo", true }
+		for i = 1, #ls do
+			assert_false( a:has_label( ls[i] ))
+		end
+		for i = 1, #ls do
+			a:add_label( ls[i] )
+			for j = 1 , #ls do
+				if j <= i then
+					assert_true( a:has_label( ls[j] ))
+				else
+					assert_false( a:has_label( ls[j] ))
+				end
+			end
+		end
+	end
+	function add_label_twice_test ()
+		local l = 'foo'
+		a:add_label( l )
+		a:add_label( l )
+		local cnt = 0
+		for x in a:blocks() do
+			assert_equal( l, x )
+			cnt = cnt + 1
+		end
+		assert_equal( 1, cnt )
+	end
+
+-- ../src/unittestfiles.nw:134
+	
+-- ../src/main.nw:242
+	function expect_unreplayed_action_test ()
+		assert_true( a:is_expected() )
+	end
+
+-- ../src/unittestfiles.nw:135
+	
+-- ../src/main.nw:320
+	function unreplayed_action_is_not_satisfied_test ()
+		assert_false( a:is_satisfied() )
+	end
+	function assert_satisfied_unreplayed_action_fails_test ()
+		local ok, err = pcall( function() a:assert_satisfied() end )
+		assert_false( ok, "unreplayed action was satisfied" )
+		assert_match( "Wrong replay count 0", err )
+	end
+
+-- ../src/unittestfiles.nw:136
+	
+-- ../src/main.nw:254
+	function match_unreplayed_test ()
+		assert_true( a:match( a ))
+	end
+	function match_rejects_replayed_action_test ()
+		a.replay_count = 1
+		assert_false( a:match( a ))
+	end
+	function match_rejects_wrong_action_type_test ()
+		-- Fake different type
+		local B = class( A )
+		local b = B:new()
+		assert_false( a:match( b ))
+	end
+
+-- ../src/unittestfiles.nw:137
+	
+-- ../src/main.nw:212
+	function new_action_has_right_default_values_test ()
+		assert_equal( 0, a.replay_count )
+		assert_equal( 1, a.min_replays )
+		assert_equal( 1, a.max_replays )
+	end
+
+-- ../src/unittestfiles.nw:138
+	
+-- ../src/restrictions.nw:90
+	function set_and_get_times_test ()
+	end
+	function unrealistic_times_fails_test ()
+		local ps = { {'foo'}, {8,'bar'}, {-1}, {3,2}, {1/0}, {0/0}, {0,0} }
+		for _, p in ipairs( ps ) do
+			local ok, err = pcall( function() a:set_times( unpack(p) ) end )
+			assert_false( ok, "unrealistic times "..table.concat(p,", ") )
+			assert_match( "Unrealistic time arguments ", err )
+		end
+	end
+
diff --git a/build/unit/argv.lua b/build/unit/argv.lua
new file mode 100644
index 0000000..ddecbcf
--- /dev/null
+++ b/build/unit/argv.lua
@@ -0,0 +1,213 @@
+-- ../src/unittestfiles.nw:85
+	
+-- ../src/misc.nw:7
+	------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------
+	-- Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+	-- See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+
+-- ../src/unittestfiles.nw:86
+	
+	require 'lunit'
+	module( 'unit.argv', lunit.testcase, package.seeall )
+	
+	local class, object, value_equal, sfmt, qtostring
+	
+-- ../src/helperfunctions.nw:12
+	function object (class)
+		return setmetatable( {}, class )
+	end
+	function class (parent)
+		local c = object(parent)
+		c.__index = c
+		return c
+	end
+-- ../src/unittestfiles.nw:92
+	
+-- ../src/helperfunctions.nw:29
+	function value_equal (a, b)
+		if a == b then return true end
+		if a ~= a and b ~= b then return true end -- NaN == NaN
+		return false
+	end
+-- ../src/unittestfiles.nw:93
+	
+-- ../src/tostring.nw:23
+	sfmt = string.format
+	function qtostring (v)
+		if type(v) == 'string' then
+			return sfmt( '%q', v )
+		else
+			return tostring( v )
+		end
+	end
+-- ../src/unittestfiles.nw:94
+	
+	local Argv
+	
+-- ../src/class/argv.nw:6
+	Argv = class()
+	
+	
+-- ../src/argv.nw:119
+	Argv.ANYARGS = newproxy()  local ANYARGS = Argv.ANYARGS
+	Argv.ANYARG  = newproxy()  local ANYARG  = Argv.ANYARG
+	function Argv:equal (other)
+		local a1, n1 = self.v,  self.len
+		local a2, n2 = other.v, other.len
+		if n1-1 <= n2 and a1[n1] == ANYARGS then
+			n1 = n1-1
+			n2 = n1
+		elseif n2-1 <= n1 and a2[n2] == ANYARGS then
+			n2 = n2-1
+			n1 = n2
+		end
+		if n1 ~= n2 then
+			return false
+		end
+		for i = 1, n1 do
+			local v1, v2 = a1[i], a2[i]
+			if not value_equal(v1,v2) and v1 ~= ANYARG and v2 ~= ANYARG then
+				return false
+			end
+		end
+		return true
+	end
+-- ../src/class/argv.nw:9
+	
+-- ../src/argv.nw:46
+	function Argv:new (...)
+		local av = object( self )
+		av.v = {...}
+		av.len = select('#',...)
+		for i = 1, av.len - 1 do
+			if av.v[i] == Argv.ANYARGS then
+				error( "ANYARGS not at end.", 0 )
+			end
+		end
+		return av
+	end
+-- ../src/class/argv.nw:10
+	
+-- ../src/tostring.nw:163
+	function Argv:tostring ()
+		local res = {}
+		local function w (v)
+			res[#res+1] = qtostring( v )
+		end
+		local av, ac = self.v, self.len
+		for i = 1, ac do
+			if av[i] == Argv.ANYARG then
+				res[#res+1] = 'ANYARG'
+			elseif av[i] == Argv.ANYARGS then
+				res[#res+1] = 'ANYARGS'
+			else
+				w( av[i] )
+			end
+			if i < ac then
+				res[#res+1] = ',' -- can not use qtostring in w()
+			end
+		end
+		return table.concat( res )
+	end
+-- ../src/class/argv.nw:11
+	
+-- ../src/argv.nw:156
+	function Argv:unpack ()
+		return unpack( self.v, 1, self.len )
+	end
+-- ../src/unittestfiles.nw:97
+	
+	
+-- ../src/argv.nw:63
+	local l = {}
+	local function p (...) l[#l+1] = { n=select('#',...), ... } end
+	p() p(nil) p(nil,nil) p(false) p({}) p(false,nil,{},nil) p(nil,p)
+	p(true) p(0.1,'','a') p(1/0,nil,0/0) p(0/0) p(0/0, true) p(0/0, false)
+	function equal_test ()
+		local a1, a2, f, op
+		for i = 1, #l do
+			ai = Argv:new( unpack( l[i], 1, l[i].n ))
+			for j = 1, #l do
+				aj = Argv:new( unpack( l[j], 1, l[j].n ))
+				if i == j then
+					f, op = assert_true,  ') ~= ('
+				else
+					f, op = assert_false, ') == ('
+				end
+				f( ai:equal(aj), '('..ai:tostring()..op..aj:tostring()..')' )
+			end
+		end
+	end
+	function equal_anyargs_test ()
+		local a, b = {}, {}
+		a[1] = Argv:new( Argv.ANYARGS )
+		a[2] = Argv:new( 6, Argv.ANYARGS )
+		a[3] = Argv:new( 6, 5, Argv.ANYARGS )
+		for i = 1, #l do
+			b[1] = Argv:new( unpack( l[i], 1, l[i].n ))
+			b[2] = Argv:new( 6, unpack( l[i], 1, l[i].n ))
+			b[3] = Argv:new( 6, 5, unpack( l[i], 1, l[i].n ))
+			for j = 1, 3 do
+				local astr = '('..a[j]:tostring()..')'
+				local bstr = '('..b[j]:tostring()..')'
+				assert_true( a[j]:equal(b[j]), astr..' ~= '..bstr )
+				assert_true( b[j]:equal(a[j]), bstr..' ~= '..astr )
+			end
+		end
+	end
+	function equal_anyarg_test ()
+		local l = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }
+		local a1 = Argv:new( unpack(l) )
+		for i = 1, 9 do
+			l[i] = Argv.ANYARG
+			local a2 = Argv:new( unpack(l) )
+			assert_true( a1:equal(a2) )
+			assert_true( a2:equal(a1) )
+			l[i] = i
+		end
+	end
+-- ../src/unittestfiles.nw:99
+	
+-- ../src/argv.nw:27
+	function new_test ()
+		Argv:new( Argv.ANYARGS )
+		Argv:new( 1, Argv.ANYARGS )
+		Argv:new( 1, 2, Argv.ANYARGS )
+	end
+	function new_anyargs_with_extra_arguments_fails_test ()
+		local l = {}
+		l['ANYARGS,1']         = { Argv.ANYARGS, 1 }
+		l['ANYARGS,ANYARGS'  ] = { Argv.ANYARGS, Argv.ANYARGS }
+		l['1,ANYARGS,1']       = { 1, Argv.ANYARGS, 1 }
+		l['1,ANYARGS,ANYARGS'] = { 1, Argv.ANYARGS, Argv.ANYARGS }
+		for msg, args in pairs( l ) do
+			local ok, err = pcall( function() Argv:new( unpack(args) ) end )
+			assert_false( ok, "Bad ANYARGS accepted for "..msg )
+			assert_match( "ANYARGS not at end", err )
+		end
+	end
+
+-- ../src/unittestfiles.nw:100
+	
+-- ../src/tostring.nw:151
+	function tostring_test ()
+		assert_equal( '',              Argv:new()              :tostring() )
+		assert_equal( '""',            Argv:new('')            :tostring() )
+		assert_equal( 'nil,nil',       Argv:new(nil,nil)       :tostring() )
+		assert_equal( '"false",false', Argv:new('false',false) :tostring() )
+		assert_equal( '1,2,3',         Argv:new(1,2,3)         :tostring() )
+		assert_equal( '1,ANYARG,3',    Argv:new(1,Argv.ANYARG,3):tostring() )
+		assert_equal( 'ANYARGS',       Argv:new(Argv.ANYARGS)  :tostring() )
+		assert_equal( '7,0,ANYARGS',   Argv:new(7,0,Argv.ANYARGS):tostring() )
+	end
+
+-- ../src/unittestfiles.nw:101
+	
+-- ../src/argv.nw:148
+	function unpack_test ()
+		local a, b, c = Argv:new( false, nil, 7 ):unpack()
+		assert_equal( false, a )
+		assert_equal( nil,   b )
+		assert_equal( 7,     c )
+	end
+
diff --git a/build/unit/controller.lua b/build/unit/controller.lua
new file mode 100644
index 0000000..5bb22e6
--- /dev/null
+++ b/build/unit/controller.lua
@@ -0,0 +1,860 @@
+-- ../src/unittestfiles.nw:46
+	
+-- ../src/misc.nw:7
+	------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------
+	-- Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+	-- See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+
+-- ../src/unittestfiles.nw:47
+	
+	require 'lunit'
+	module( 'unit.controller', lunit.testcase, package.seeall )
+	
+	local class, object, qtostring, sfmt, add_to_set, elements_of_set
+	
+-- ../src/helperfunctions.nw:12
+	function object (class)
+		return setmetatable( {}, class )
+	end
+	function class (parent)
+		local c = object(parent)
+		c.__index = c
+		return c
+	end
+-- ../src/unittestfiles.nw:53
+	
+-- ../src/tostring.nw:23
+	sfmt = string.format
+	function qtostring (v)
+		if type(v) == 'string' then
+			return sfmt( '%q', v )
+		else
+			return tostring( v )
+		end
+	end
+-- ../src/unittestfiles.nw:54
+	
+-- ../src/helperfunctions.nw:47
+	function add_to_set (o, setname, element)
+		if not o[setname] then
+			o[setname] = {}
+		end
+		local l = o[setname]
+		
+		for i = 1, #l do
+			if l[i] == element then return end
+		end
+		l[#l+1] = element
+	end
+	function elements_of_set (o, setname)
+		local l = o[setname]
+		local i = l and #l+1 or 0
+		return function ()
+			i = i - 1
+			if i > 0 then return l[i] end
+		end
+	end
+-- ../src/unittestfiles.nw:55
+	
+	
+-- ../src/main.nw:373
+	local mock_controller_map = setmetatable( {}, {__mode='k'} )
+-- ../src/unittestfiles.nw:57
+	
+	local Controller, Action
+	
+-- ../src/class/controller.nw:6
+	Controller = class()
+	
+	-- Exported methods
+	
+-- ../src/restrictions.nw:595
+	function Controller:close (...)
+		if not self.is_recording then
+			error( "Can not insert close in replay mode.", 2 )
+		end
+		local action = self:get_last_action()
+		for _, close in ipairs{ ... } do
+			action:add_close( close )
+		end
+		return self -- for chaining
+	end
+
+-- ../src/class/controller.nw:10
+	
+-- ../src/restrictions.nw:410
+	function Controller:depend (...)
+		if not self.is_recording then
+			error( "Can not add dependency in replay mode.", 2 )
+		end
+		local action = self:get_last_action()
+		for _, dependency in ipairs{ ... } do
+			action:add_depend( dependency )
+		end
+		return self -- for chaining
+	end
+
+-- ../src/class/controller.nw:11
+	
+-- ../src/main.nw:617
+	function Controller:error (value)
+		if not self.is_recording then
+			error( "Error called during replay.", 2 )
+		end
+		local action = self:get_last_action()
+		if action.has_returnvalue or action.throws_error then
+			error( "Returns and/or Error called twice for same action.", 2 )
+		end
+		action.throws_error = true
+		action.errorvalue = value
+		return self -- for chaining
+	end
+-- ../src/class/controller.nw:12
+	
+-- ../src/restrictions.nw:158
+	function Controller:label (...)
+	if not self.is_recording then
+		error( "Can not add labels in replay mode.", 2 )
+	end
+	local action = self:get_last_action()
+	for _, label in ipairs{ ... } do
+		action:add_label( label )
+	end
+	return self -- for chaining
+	end
+-- ../src/class/controller.nw:13
+	
+-- ../src/main.nw:462
+	function Controller:mock ()
+		if not self.is_recording then
+			error( "New mock during replay.", 2 )
+		end
+		local m = object( Mock.record )
+		mock_controller_map[m] = self
+		return m
+	end
+-- ../src/class/controller.nw:14
+	
+-- ../src/main.nw:421
+	function Controller:new ()
+		local mc = object( self )
+		mc.actionlist   = {}
+		mc.is_recording = true
+		return mc
+	end
+-- ../src/class/controller.nw:15
+	
+-- ../src/main.nw:671
+	function Controller:replay ()
+		if not self.is_recording then
+			error( "Replay called twice.", 2 )
+		end
+		self.is_recording = false
+		for m, mc in pairs( mock_controller_map ) do
+			if mc == self then
+				setmetatable( m, Mock.replay )
+			end
+		end
+		self:update_dependencies()
+		self:assert_no_dependency_cycles()
+	end
+-- ../src/class/controller.nw:16
+	
+-- ../src/main.nw:571
+	function Controller:returns (...)
+		if not self.is_recording then
+			error( "Returns called during replay.", 2 )
+		end
+		local action = self:get_last_action()
+		assert( not action.is_callable, "lemock internal error" )
+		if not action.can_return then
+			error( "Previous action can not return anything.", 2 )
+		end
+		if action.has_returnvalue or action.throws_error then
+			error( "Returns and/or Error called twice for same action.", 2 )
+		end
+		action:set_returnvalue(...)
+		return self -- for chaining
+	end
+-- ../src/class/controller.nw:17
+	
+-- ../src/restrictions.nw:74
+	function Controller:times (min, max)
+		if not self.is_recording then
+			error( "Can not set times in replay mode.", 0 )
+		end
+		self:get_last_action():set_times( min, max )
+		return self -- for chaining
+	end
+	-- convenience functions
+	function Controller:anytimes()    return self:times( 0, math.huge ) end
+	function Controller:atleastonce() return self:times( 1, math.huge ) end
+-- ../src/class/controller.nw:18
+	
+-- ../src/main.nw:754
+	function Controller:verify ()
+		if self.is_recording then
+			error( "Verify called during record.", 2 )
+		end
+		for a in self:actions() do
+			a:assert_satisfied()
+		end
+	end
+-- ../src/class/controller.nw:19
+	
+	-- Protected methods
+	
+-- ../src/main.nw:145
+	function Controller:actions (q)
+		local l = self.actionlist
+		local i = 0
+		return function ()
+			i = i + 1
+			return l[i]
+		end				
+	end
+-- ../src/class/controller.nw:22
+	
+-- ../src/main.nw:56
+	function Controller:add_action (a)
+		assert( a ~= nil, "lemock internal error" ) -- breaks array property
+		table.insert( self.actionlist, a )
+	end
+-- ../src/class/controller.nw:23
+	
+-- ../src/restrictions.nw:489
+	function Controller:assert_no_dependency_cycles ()
+		local function is_in_path (label, path)
+			if not path then return false end -- is root
+			for _, l in ipairs( path ) do
+				if l == label then return true end
+			end
+			if path.prev then return is_in_path( label, path.prev ) end
+			return false
+		end
+		local function can_block (action, node)
+			for _, label in ipairs( node ) do
+				if action:has_label( label ) then return true end
+			end
+			return false
+		end
+		local function step (action, path)
+			local new_head
+			for label in action:depends() do
+				if is_in_path( label, path ) then
+					error( "Detected dependency cycle", 0 )
+				end
+				-- only create table if needed to reduce garbage
+				if not new_head then new_head = { prev=path } end
+				new_head[#new_head+1] = label
+			end
+			return new_head
+		end
+		local function search_depth_first (path)
+			for action in self:actions() do
+				if can_block( action, path ) then
+					local new_head = step( action, path )
+					if new_head then
+						search_depth_first( new_head )
+					end
+				end
+			end
+		end
+		for action in self:actions() do
+			local root = step( action, nil )
+			if root then search_depth_first( root ) end
+		end
+	end
+-- ../src/class/controller.nw:24
+	
+-- ../src/restrictions.nw:616
+	function Controller:close_actions( ... ) -- takes iterator
+		for label in ... do
+			for candidate in self:actions() do
+				if candidate:has_label( label ) then
+					if not candidate:is_satisfied() then
+						error( "Closes unsatisfied action: "..candidate:tostring(), 0 )
+					end
+					candidate.is_closed = true
+				end
+			end
+		end
+	end
+
+-- ../src/class/controller.nw:25
+	
+-- ../src/main.nw:177
+	function Controller:get_last_action ()
+		local l = self.actionlist
+		if #l == 0 then
+			error( "No action is recorded yet.", 0 )
+		end
+		return l[#l]
+	end
+-- ../src/class/controller.nw:26
+	
+-- ../src/main.nw:88
+	function Controller:lookup (actual)
+		for action in self:actions() do
+			if action:match( actual ) then
+				return action
+			end
+		end
+		
+-- ../src/main.nw:111
+	local expected = {}
+	for _, a in ipairs( self.actionlist ) do
+		if a:is_expected() and not a.is_callable then
+			expected[#expected+1] = a:tostring()
+		end
+	end
+	table.sort( expected )
+	if #expected == 0 then
+		expected[1] = "(Nothing)"
+	end
+-- ../src/main.nw:95
+		error( sfmt( "Unexpected action %s, expected:\n%s\n"
+		             , actual:tostring()
+		             , table.concat(expected,'\n')
+		       )
+		       , 0
+		)
+	end
+-- ../src/class/controller.nw:27
+	
+-- ../src/main.nw:531
+	function Controller:make_callable (action)
+		if action.has_returnvalue then
+			error( "Can not call "..action.key..". It has a returnvalue.", 0 )
+		end
+		action.is_callable = true
+		action.min_replays = 0
+		action.max_replays = math.huge
+	end
+-- ../src/class/controller.nw:28
+	
+-- ../src/main.nw:421
+	function Controller:new ()
+		local mc = object( self )
+		mc.actionlist   = {}
+		mc.is_recording = true
+		return mc
+	end
+-- ../src/class/controller.nw:29
+	
+-- ../src/main.nw:297
+	function Controller:replay_action ( action )
+		assert( action:is_expected(), "lemock internal error" )
+		assert( action.replay_count < action.max_replays, "lemock internal error" )
+		local was_satisfied = action:is_satisfied()
+		action.replay_count = action.replay_count + 1
+		if not was_satisfied and action.labellist and action:is_satisfied() then
+			self:update_dependencies()
+		end
+		if action.closelist then
+			self:close_actions( action:closes() )
+		end
+	end
+-- ../src/class/controller.nw:30
+	
+-- ../src/restrictions.nw:457
+	function Controller:update_dependencies ()
+		local blocked = {}
+		for action in self:actions() do
+			for label in action:blocks() do
+				blocked[label] = true
+			end
+		end
+		local function is_blocked (action)
+			for label in action:depends() do
+				if blocked[label] then return true end
+			end
+			return false
+		end
+		for action in self:actions() do
+			action.is_blocked = is_blocked( action )
+		end
+	end
+-- ../src/unittestfiles.nw:60
+	
+-- ../src/class/action.nw:24
+	Action = {}
+	
+	-- abstract
+	
+-- ../src/class/action.nw:41
+	Action.generic = class()
+	
+	
+-- ../src/restrictions.nw:607
+	function Action.generic:add_close (label)
+		add_to_set( self, 'closelist', label )
+	end
+-- ../src/class/action.nw:44
+	
+-- ../src/restrictions.nw:443
+	function Action.generic:add_depend (d)
+		add_to_set( self, 'dependlist', d )
+	end
+
+-- ../src/class/action.nw:45
+	
+-- ../src/restrictions.nw:207
+	function Action.generic:add_label (label)
+		add_to_set( self, 'labellist', label )
+	end
+
+-- ../src/class/action.nw:46
+	
+-- ../src/main.nw:338
+	function Action.generic:assert_satisfied ()
+		assert( self.replay_count <= self.max_replays, "lemock internal error" )
+		if not (
+-- ../src/main.nw:330
+	self.min_replays <= self.replay_count
+
+-- ../src/main.nw:340
+                                  ) then
+			error( sfmt( "Wrong replay count %d (expected %d..%d) for %s"
+			             , self.replay_count
+			             , self.min_replays, self.max_replays
+			             , self:tostring()
+			       )
+			       , 0
+			)
+		end
+	end
+-- ../src/class/action.nw:47
+	
+-- ../src/restrictions.nw:220
+	function Action.generic:blocks ()
+		if self:is_satisfied() then
+			return function () end
+		end
+		return elements_of_set( self, 'labellist' )
+	end
+-- ../src/class/action.nw:48
+	
+-- ../src/restrictions.nw:630
+	function Action.generic:closes ()
+		return elements_of_set( self, 'closelist' )
+	end
+-- ../src/class/action.nw:49
+	
+-- ../src/restrictions.nw:448
+	function Action.generic:depends ()
+		return elements_of_set( self, 'dependlist' )
+	end
+-- ../src/class/action.nw:50
+	
+-- ../src/restrictions.nw:212
+	function Action.generic:has_label (l)
+		for x in elements_of_set( self, 'labellist' ) do
+			if x == l then return true end
+		end
+		return false
+	end
+
+-- ../src/class/action.nw:51
+	
+-- ../src/main.nw:247
+	function Action.generic:is_expected ()
+		return self.replay_count < self.max_replays
+		   and not self.is_blocked
+		   and not self.is_closed
+	end
+
+-- ../src/class/action.nw:52
+	
+-- ../src/main.nw:333
+	function Action.generic:is_satisfied ()
+		return 
+-- ../src/main.nw:330
+	self.min_replays <= self.replay_count
+
+-- ../src/main.nw:335
+	end
+
+-- ../src/class/action.nw:53
+	
+-- ../src/main.nw:269
+	function Action.generic:match (key)
+		if getmetatable(self) ~= getmetatable(key)  then return false end
+		if self.mock ~= key.mock                    then return false end
+		return self:is_expected()
+	end
+-- ../src/class/action.nw:54
+	
+-- ../src/main.nw:219
+	function Action.generic:new (mock)
+		local a = object( self )
+		a.mock         = mock
+		a.replay_count = 0
+		a.min_replays  = 1
+		a.max_replays  = 1
+		return a
+	end
+-- ../src/class/action.nw:55
+	
+-- ../src/restrictions.nw:102
+	function Action.generic:set_times (a, b)
+		min = a or 1
+		max = b or min
+		min, max = tonumber(min), tonumber(max)
+		if (not min) or (not max) or (min >= math.huge)
+		             or (min ~= min) or (max ~= max) -- NaN
+		             or (min < 0) or (max <= 0) or (min > max) then
+			error( sfmt( "Unrealistic time arguments (%s, %s)"
+			           , qtostring( min )
+			           , qtostring( max )
+			           )
+			     , 0
+			     )
+		end
+		self.min_replays = min
+		self.max_replays = max
+	end
+
+
+-- ../src/class/action.nw:28
+	
+-- ../src/class/action.nw:59
+	Action.generic_call = class( Action.generic )
+	
+	Action.generic_call.can_return = true
+	
+-- ../src/action/generic_call.nw:76
+	function Action.generic_call:get_returnvalue ()
+		if self.has_returnvalue then
+			return self.returnvalue:unpack()
+		end
+	end
+-- ../src/class/action.nw:63
+	
+-- ../src/action/generic_call.nw:56
+	function Action.generic_call:set_returnvalue (...)
+		self.returnvalue = Argv:new(...)
+		self.has_returnvalue = true
+	end
+-- ../src/class/action.nw:64
+	
+	
+-- ../src/action/generic_call.nw:45
+	function Action.generic_call:match (q)
+		if not Action.generic.match( self, q )  then return false end
+		if not self.argv:equal( q.argv )        then return false end
+		return true
+	end
+-- ../src/class/action.nw:66
+	
+-- ../src/action/generic_call.nw:32
+	function Action.generic_call:new (m, ...)
+		local a = Action.generic.new( self, m )
+		a.argv   = Argv:new(...)
+		return a
+	end
+-- ../src/class/action.nw:29
+	
+	-- concrete
+	
+-- ../src/class/action.nw:93
+	Action.call = class( Action.generic_call )
+	
+	
+-- ../src/action/call.nw:118
+	function Action.call:match (q)
+		if not Action.generic_call.match( self, q )  then return false end
+		if self.key ~= q.key                         then return false end
+		return true
+	end
+-- ../src/class/action.nw:96
+	
+-- ../src/action/call.nw:82
+	function Action.call:new (m, key, ...)
+		local a = Action.generic_call.new( self, m, ... )
+		a.key = key
+		return a
+	end
+-- ../src/class/action.nw:97
+	
+-- ../src/tostring.nw:101
+	function Action.call:tostring ()
+		if self.has_returnvalue then
+			return sfmt( "call %s(%s) => %s"
+			             , tostring(self.key)
+			             , self.argv:tostring()
+			             , self.returnvalue:tostring()
+			       )
+		else
+			return sfmt( "call %s(%s)"
+			             , tostring(self.key)
+			             , self.argv:tostring()
+			       )
+		end
+	end
+
+
+-- ../src/class/action.nw:32
+	
+-- ../src/class/action.nw:81
+	Action.index = class( Action.generic )
+	
+	Action.index.can_return = true
+	
+-- ../src/action/index.nw:134
+	function Action.index:get_returnvalue ()
+		return self.returnvalue
+	end
+-- ../src/class/action.nw:85
+	
+-- ../src/action/index.nw:85
+	function Action.index:set_returnvalue (v)
+		self.returnvalue = v
+		self.has_returnvalue = true
+	end
+-- ../src/class/action.nw:86
+	
+	
+-- ../src/action/index.nw:123
+	function Action.index:match (q)
+		if not Action.generic.match( self, q )  then return false end
+		if self.key ~= q.key                    then return false end
+		return true
+	end
+-- ../src/class/action.nw:88
+	
+-- ../src/action/index.nw:67
+	function Action.index:new (m, key)
+		local a = Action.generic.new( self, m )
+		a.key = key
+		return a
+	end
+-- ../src/class/action.nw:89
+	
+-- ../src/tostring.nw:70
+	function Action.index:tostring ()
+		local key = 'index '..tostring( self.key )
+		if self.has_returnvalue then
+			return sfmt( "index %s => %s"
+			             , tostring( self.key )
+			             , qtostring( self.returnvalue )
+			       )
+		elseif self.is_callable then
+			return sfmt( "index %s()"
+			             , tostring( self.key )
+			       )
+		else
+			return sfmt( "index %s"
+			             , tostring( self.key )
+			       )
+		end
+	end
+
+
+-- ../src/class/action.nw:33
+	
+-- ../src/class/action.nw:73
+	Action.newindex = class( Action.generic )
+	
+	
+-- ../src/action/newindex.nw:102
+	function Action.newindex:match (q)
+		if not Action.generic.match( self, q )  then return false end
+		if self.key ~= q.key                    then return false end
+		if not value_equal( self.val, q.val )
+		   and self.val ~= Argv.ANYARG
+		   and q.val    ~= Argv.ANYARG          then return false end
+		return true
+	end
+-- ../src/class/action.nw:76
+	
+-- ../src/action/newindex.nw:54
+	function Action.newindex:new (m, key, val)
+		local a = Action.generic.new( self, m )
+		a.key    = key
+		a.val    = val
+		return a
+	end
+-- ../src/class/action.nw:77
+	
+-- ../src/tostring.nw:45
+	function Action.newindex:tostring ()
+		return sfmt( "newindex %s = %s"
+		             , tostring(self.key)
+		             , qtostring(self.val)
+		       )
+	end
+
+
+-- ../src/class/action.nw:34
+	
+-- ../src/class/action.nw:101
+	Action.selfcall = class( Action.generic_call )
+	
+	
+-- ../src/action/selfcall.nw:93
+	function Action.selfcall:match (q)
+		return Action.generic_call.match( self, q )
+	end
+-- ../src/class/action.nw:104
+	
+-- ../src/action/selfcall.nw:61
+	function Action.selfcall:new (m, ...)
+		local a = Action.generic_call.new( self, m, ... )
+		return a
+	end
+-- ../src/class/action.nw:105
+	
+-- ../src/tostring.nw:129
+	function Action.selfcall:tostring ()
+		if self.has_returnvalue then
+			return sfmt( "selfcall (%s) => %s"
+			             , self.argv:tostring()
+			             , self.returnvalue:tostring()
+			       )
+		else
+			return sfmt( "selfcall (%s)"
+			             , self.argv:tostring()
+			       )
+		end
+	end
+-- ../src/unittestfiles.nw:61
+	
+	local A = Action.generic
+	Action = nil -- only allow generic action
+	function A:tostring () return '<dummy>' end
+	
+	local mc
+	
+	function setup ()
+		mc = Controller:new()
+	end
+	
+	
+-- ../src/main.nw:125
+	function actions_dont_iterate_empty_list_test ()
+		for a in mc:actions() do
+			fail( "iterates on empty list" )
+		end
+	end
+	function actions_iterate_over_entire_list_exactly_once_test ()
+		local l = { {},{},{} }
+		for _, a in ipairs( l ) do
+			mc:add_action( a )
+		end
+		for a in mc:actions() do
+			assert_nil( a.check )
+			a.check = true
+		end
+		for _, a in ipairs( l ) do
+			assert_true( a.check )
+		end
+	end
+
+-- ../src/unittestfiles.nw:73
+	
+-- ../src/main.nw:48
+	function add_action_at_the_end_test ()
+		mc:add_action( 7 )
+		mc:add_action( mc )
+		assert_equal( 7, mc.actionlist[1] )
+		assert_equal( mc, mc.actionlist[2] )
+	end
+
+-- ../src/unittestfiles.nw:74
+	
+-- ../src/main.nw:162
+	function get_last_action_returns_last_element_test ()
+		local l = { 'a', 'foo', 17 }
+		for i = 1, #l do
+			mc:add_action( l[i] )
+			local res = mc:get_last_action()
+			assert_equal( l[i], res )
+		end
+	end
+	function get_last_action_fails_on_empty_list_test ()
+		local ok, err = pcall( function() mc:get_last_action() end )
+		assert_false( ok, "Found last action in empty list" )
+		assert_match( "No action is recorded yet", err )
+	end
+
+-- ../src/unittestfiles.nw:75
+	
+-- ../src/restrictions.nw:143
+	function label_test ()
+		mc:add_action( A:new() )
+		mc:label( 'a', 'b' ):label( 'c', 'b' )
+		local a = mc:get_last_action()
+		local seen = {}
+		for l in a:blocks() do
+			seen[l] = true
+		end
+		assert_true( seen['a'] )
+		assert_true( seen['b'] )
+		assert_true( seen['c'] )
+		assert_nil(  seen['d'] )
+	end
+
+-- ../src/unittestfiles.nw:76
+	
+-- ../src/main.nw:71
+	function lookup_returns_first_matching_action_test ()
+		local Fake_action
+		
+-- ../src/misc.nw:12
+	Fake_action = class()
+	function Fake_action:new (x)
+		local a = object(Fake_action)
+		a.x = x
+		return a
+	end
+	function Fake_action:match (q)
+		return self.x < q.x
+	end
+	function Fake_action:is_expected ()
+		return true
+	end
+	function Fake_action:tostring ()
+		return '<faked action>'
+	end
+	function Fake_action:blocks ()
+		return function () end
+	end
+	Fake_action.depends = Fake_action.blocks
+-- ../src/main.nw:74
+		local a1 = Fake_action:new(1)
+		local a2 = Fake_action:new(2)
+		local a3 = Fake_action:new(1)
+		local ok, err = pcall( function() mc:lookup( a1 ) end )
+		assert_false( ok, "match in empty list" )
+		assert_match( "Unexpected action <faked action>", err )
+		mc:add_action( a1 ) mc:add_action( a2 ) mc:add_action( a3 )
+		local ok, err = pcall( function() mc:lookup( a1 ) end )
+		assert_false( ok, "should not match any action" )
+		assert_match( "Unexpected action <faked action>", err )
+		assert_equal( a1, mc:lookup( a2 ), "did not find first match" )
+	end
+
+-- ../src/unittestfiles.nw:77
+	
+-- ../src/main.nw:664
+	function replay_test ()
+		assert_true( mc.is_recording )
+		mc:replay()
+		assert_false( mc.is_recording )
+	end
+
+-- ../src/unittestfiles.nw:78
+	
+-- ../src/main.nw:285
+	function replay_action_test ()
+		local a = A:new()
+		mc:add_action( a )
+		assert_true( a:is_expected() )
+		assert_false( a:is_satisfied() )
+		mc:replay_action( a )
+		assert_false( a:is_expected() )
+		assert_true( a:is_satisfied() )
+		assert_equal( 1, a.replay_count )
+	end
+
diff --git a/build/unit/module.lua b/build/unit/module.lua
new file mode 100644
index 0000000..79bf8c1
--- /dev/null
+++ b/build/unit/module.lua
@@ -0,0 +1,601 @@
+-- ../src/unittestfiles.nw:10
+	
+-- ../src/misc.nw:7
+	------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------
+	-- Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+	-- See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+
+-- ../src/unittestfiles.nw:11
+	
+	require 'lunit'
+	module( 'unit.module', lunit.testcase, package.seeall )
+	
+	require 'lemock'
+	
+	local mc, m
+	
+	function setup ()
+		mc = lemock.controller()
+		m  = mc:mock()
+	end
+
+	
+-- ../src/restrictions.nw:537
+	function close_test ()
+		local t
+		t = m.foo ;mc:times(0,1/0):returns( 1 ) :label(1)
+		t = m.foo ;mc:times(0,1/0):returns( 2 ) :label(2)
+		t = m.foo ;mc:times(0,1/0):returns( 3 )
+		m.bar(1) ;mc:close(1)
+		m.bar(2) ;mc:close(2)
+		mc:replay()
+		m.bar(1)
+		assert_equal( 2, m.foo )
+		assert_equal( 2, m.foo )
+		assert_equal( 2, m.foo )
+		m.bar(2)
+		assert_equal( 3, m.foo )
+		mc:verify()
+	end
+	function close_unsatisfied_action_fails_test ()
+		m.a = 1 ;mc:label(1)
+		m.b = 2 ;mc:close(1)
+		mc:replay()
+		local ok, err = pcall( function() m.b = 2 end )
+		assert_false( ok, "Undetected close of unsatisfied action" )
+		assert_match( "Closes unsatisfied action", err )
+	end
+	function close_multiple_test ()
+		m.foo(1) ;mc:label(1) :times(0,1)
+		m.foo(1) ;mc:label(2) :times(0,1)
+		m.foo(1)
+		m.bar() ;mc:close(1,2)
+		mc:replay()
+		m.bar()
+		m.foo(1)
+		mc:verify()
+	end
+
+-- ../src/restrictions.nw:573
+	function close_chaining_test ()
+		m.a = 1 ;mc:label 'A'
+		m.b = 1 ;mc:label 'B'
+		m.c = 1 ;mc:close('A'):close('B')
+	end
+	function close_in_replay_mode_fails_test ()
+		mc:replay()
+		local ok, err = pcall( function() mc:close( 'foo' ) end )
+		assert_false( ok, "accepted close in replay mode" )
+		assert_match( "Can not insert close in replay mode", err )
+	end
+	function close_on_empty_actionlist_fails_test ()
+		local ok, err = pcall( function() mc:close( 'bar' ) end )
+		assert_false( ok, "accepted close with empty action list" )
+		assert_match( "No action is recorded yet", err )
+	end
+-- ../src/unittestfiles.nw:25
+	
+-- ../src/restrictions.nw:240
+	function depend_fulfilled_test ()
+		m.foo = 1 ;mc:label 'A'
+		m.bar = 2 ;mc:depend 'A'
+		mc:replay()
+		m.foo = 1
+		m.bar = 2
+		mc:verify()
+	end
+	function depend_unfulfilled_fails_test ()
+		m.foo = 1 ;mc:label 'A'
+		m.bar = 2 ;mc:depend 'A'
+		mc:replay()
+		local ok, err = pcall( function() m.bar = 2 end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action newindex", err )
+	end
+	function depend_fulfilled_any_order_test ()
+		local tmp
+		m.a = 1 ;mc:label 'A'
+		tmp = m.b ;mc:returns(2):depend 'A'
+		tmp = m.b ;mc:returns(3)
+		mc:replay()
+		assert_equal( 3, m.b, "replayed wrong b" )
+		m.a = 1
+		assert_equal( 2, m.b, "replayed wrong b" )
+		mc:verify()
+	end
+	function depend_serial_blocks_test ()
+		local tmp
+		tmp = m:a() ;mc:label 'a'
+		tmp = m:c() ;mc:label 'c' :depend 'b'
+		tmp = m:b() ;mc:label 'b' :depend 'a'
+		mc:replay()
+		local ok, err = pcall( function() tmp = m:b() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:a()
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:b()
+		m:c()
+		mc:verify()
+	end
+	function depend_on_many_labels_test ()
+		local tmp
+		tmp = m:b() ;mc:label 'b'
+		tmp = m:c() ;mc:label 'c' :depend( 'a', 'b' )
+		tmp = m:a() ;mc:label 'a'
+		mc:replay()
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:a()
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:b()
+		m:c()
+		mc:verify()
+	end
+	function depend_on_many_labels_test2_test ()
+		-- swap order, in case whole list is not checked
+		local tmp
+		tmp = m:b() ;mc:label 'b'
+		tmp = m:c() ;mc:label 'c' :depend( 'b', 'a' )
+		tmp = m:a() ;mc:label 'a'
+		mc:replay()
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:a()
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:b()
+		m:c()
+		mc:verify()
+	end
+	function depend_on_many_bloskers_with_same_label_test ()
+		tmp = m:c() ;mc:label 'c' :depend 'b'
+		tmp = m:a() ;mc:label 'b'
+		tmp = m:b() ;mc:label 'b'
+		mc:replay()
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:a()
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:b()
+		m:c()
+		mc:verify()
+	end
+-- ../src/restrictions.nw:344
+	function depend_ignors_unknown_label_test ()
+		m.foo = 1 ;mc:label 'A'
+		m.bar = 2 ;mc:depend 'B'
+		mc:replay()
+		m.foo = 1
+		m.bar = 2
+		mc:verify()
+	end
+-- ../src/restrictions.nw:361
+	function depend_detect_cycle_test ()
+		local ok, err = pcall( function()
+			m.foo = 1 ;mc:label 'A' :depend 'B'
+			m.bar = 2 ;mc:label 'B' :depend 'A'
+			mc:replay()
+			m.foo = 1
+		end )
+		assert_false( ok, "replayed cyclically blocked action" )
+		assert_match( "dependency cycle", err )
+	end
+
+-- ../src/restrictions.nw:373
+	function depend_chaining_test ()
+		m.a = 1 ;mc:label 'A'
+		m.b = 1 ;mc:label 'B'
+		m.c = 1 ;mc:depend('A'):depend('B')
+	end
+	function depend_in_replay_mode_fails_test ()
+		mc:replay()
+		local ok, err = pcall( function() mc:depend( 'foo' ) end )
+		assert_false( ok, "set dependency in replay mode" )
+		assert_match( "Can not add dependency in replay mode", err )
+	end
+	function depend_on_empty_actionlist_fails_test ()
+		local ok, err = pcall( function() mc:depend( 'bar' ) end )
+		assert_false( ok, "set dependency with empty action list" )
+		assert_match( "No action is recorded yet", err )
+	end
+	function depend_reports_expected_actions_on_faliure_test ()
+		local tmp
+		tmp = m.foo ;mc:depend 'B'
+		tmp = m.bar ;mc:label 'B'
+		mc:replay()
+		local ok, err = pcall( function() tmp = m.foo end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "expected:.*index bar", err )
+		assert_not_match( "expected:.*index foo", err )
+		tmp = m.bar
+		local ok, err = pcall( function() tmp = m.bar end )
+		assert_false( ok, "expected:.*replayed blocked action" )
+		assert_not_match( "expected:.*index bar", err )
+		assert_match( "index foo", err )
+	end
+-- ../src/unittestfiles.nw:26
+	
+-- ../src/restrictions.nw:130
+	function label_in_replay_mode_fails_test ()
+		mc:replay()
+		local ok, err = pcall( function() mc:label( 'foo' ) end )
+		assert_false( ok, "set label in replay mode" )
+		assert_match( "Can not add labels in replay mode", err )
+	end
+	function label_on_empty_actionlist_fails_test ()
+		local ok, err = pcall( function() mc:label( 'bar' ) end )
+		assert_false( ok, "set label with empty action list" )
+		assert_match( "No action is recorded yet", err )
+	end
+
+-- ../src/unittestfiles.nw:27
+	
+-- ../src/main.nw:510
+	function returns_on_empty_list_fails_test ()
+		local ok, err = pcall( function() mc:returns(nil) end )
+		assert_false( ok, "returns called on nothing" )
+		assert_match( "No action is recorded yet.", err )
+	end
+	function returns_make_call_fail_test ()
+		local tmp = m.foo ;mc:returns(1)
+		local ok, err = pcall( function() tmp(2) end )
+		assert_false( ok, "called index with returnvalue" )
+		assert_match( "Can not call foo. It has a returnvalue.", err )
+	end
+	function callable_index_replays_anytimes_test ()
+		local tmp = m.foo()
+		mc:replay()
+		tmp = m.foo
+		tmp = m.foo
+		tmp = m.foo()
+		mc:verify()
+	end
+
+-- ../src/unittestfiles.nw:28
+	
+-- ../src/main.nw:449
+	function create_completely_empty_mock_test ()
+		for k, v in pairs( m ) do
+			fail( "Mock should be empty but contains "..tostring(k) )
+		end
+	end
+	function create_mock_during_replay_fails_test ()
+		mc:replay()
+		local ok, err = pcall( function() mc:mock() end )
+		assert_false( ok, "mock() succeeded" )
+		assert_match( "New mock during replay.", err )
+	end
+
+-- ../src/unittestfiles.nw:29
+	
+-- ../src/main.nw:692
+	function replay_in_any_order_test ()
+		m.a = 1
+		m.b = 2
+		m.c = 3
+		mc:replay()
+		m.c = 3
+		m.a = 1
+		m.b = 2
+		mc:verify()
+	end
+	function replaying_unexpected_action_fails_test ()
+		mc:replay()
+		local ok, err = pcall( function() m:somethingelse() end )
+		assert_false( ok, "unexpected replay succeeded" )
+		assert_match( "Unexpected action index somethingelse", err )
+	end
+-- ../src/main.nw:718
+	function cached_recording_callable_fails_during_replay_test ()
+		local tmp = m.foo ; tmp()
+		mc:replay()
+		local ok, err = pcall( function() tmp() end )
+		assert_false( ok, "Cached callable not detected" )
+		assert_match( "client uses cached callable from recording", err )
+	end
+-- ../src/unittestfiles.nw:30
+	
+-- ../src/main.nw:642
+	function replay_twice_fails_test ()
+		mc:replay()
+		local ok, err = pcall( function() mc:replay() end )
+		assert_false( ok, "replay succeeded twice" )
+		assert_match( "Replay called twice.", err )
+	end
+	function multiple_controllers_test ()
+		local mc2 = lemock.controller()
+		local m2  = mc2:mock()
+		
+		-- m --         -- m2 --
+		m.foo = 1
+		mc:replay()
+						m2.bar = 2
+		m.foo = 1
+						mc2:replay()
+		mc:verify()
+						m2.bar = 2
+						mc2:verify()
+	end
+
+-- ../src/unittestfiles.nw:31
+	
+-- ../src/restrictions.nw:38
+	function times_test ()
+		local tmp = m.foo ;mc:returns( 2 ):times( 2, 3 )
+		mc:replay()
+		-- 1
+		local tmp = m.foo
+		local ok, err = pcall( function() mc:verify() end )
+		assert_false( ok, "verified unsatisfied action" )
+		assert_match( "Wrong replay count 1 ", err )
+		-- 2
+		local tmp = m.foo
+		mc:verify()
+		-- 3
+		local tmp = m.foo
+		mc:verify()
+		-- 4
+		local ok, err = pcall( function() local tmp = m.foo end )
+		assert_false( ok, "replaied finished action" )
+		assert_match( "Unexpected action index foo", err )
+	end
+	function times_called_twice_test ()
+		m.foo = 1 ;mc:times( 0, math.huge ):times( 1 )
+	end
+	function times_in_replay_mode_fails_test ()
+		mc:replay()
+		local ok, err = pcall( function() mc:times(1) end )
+		assert_false( ok, "changed times in replay mode" )
+		assert_match( "Can not set times in replay mode.", err )
+	end
+	function unrealistic_times_fails_with_message_test ()
+		m.a = 'a'
+		local ok, err = pcall( function() mc:times(0) end )
+		assert_false( ok, "accepted unrealistic time arguments" )
+		assert_match( "Unrealistic time arguments", err )
+	end
+
+-- ../src/unittestfiles.nw:32
+	
+-- ../src/main.nw:736
+	function verify_during_record_phase_fails_test ()
+		local ok, err = pcall( function() mc:verify() end )
+		assert_false( ok, "Verify succeeded" )
+		assert_match( "Verify called during record.", err )
+	end
+	function verify_replayed_actionlist_test ()
+		mc:replay()
+		mc:verify()
+	end
+	function verify_unreplyed_actionlist_fails_test ()
+		local tmp = m.foo
+		mc:replay()
+		local ok, err = pcall( function() mc:verify() end )
+		assert_false( ok, "Verify succeeded" )
+		assert_match( "Wrong replay count 0 ", err )
+	end
+
+-- ../src/unittestfiles.nw:33
+	
+	
+-- ../src/action/call.nw:13
+	function call_test ()
+		m.foo(1,2,3)
+		mc:replay()
+		local tmp = m.foo(1,2,3)
+		assert_nil( tmp )
+		mc:verify()
+	end
+	function call_anyarg_test ()
+		m.foo(1,mc.ANYARG,3)
+		mc:replay()
+		local tmp = m.foo(1,2,3)
+		mc:verify()
+	end
+	function call_anyargs_test ()
+		m.foo(mc.ANYARGS)
+		mc:replay()
+		local tmp = m.foo(1,2,3)
+		mc:verify()
+	end
+	function call_anyargs_bad_fails_test ()
+		local ok, err = pcall( function() m.foo(mc.ANYARGS, 1) end )
+		assert_false( ok, "ANYARGS misused" )
+		assert_match( "ANYARGS not at end", err )
+	end
+	function call_return_test ()
+		m.foo(1,2,3) ;mc:returns( 0, 9 )
+		mc:replay()
+		local tmp1, tmp2 = m.foo(1,2,3)
+		assert_equal( 0, tmp1 )
+		assert_equal( 9, tmp2 )
+		mc:verify()
+	end
+	function call_wrong_name_fails_test ()
+		m.foo(1,2,3) ;mc:returns( 0 )
+		mc:replay()
+		local ok, err = pcall( function() m:bar(1,2,3) end )
+		assert_false( ok, "replay wrong index" )
+		assert_match( "Unexpected action index bar", err )
+	end
+	function call_wrong_arg_fails_test ()
+		m.foo(1,2,3) ;mc:returns( 0 )
+		mc:replay()
+		local ok, err = pcall( function() m.foo(1) end )
+		assert_false( ok, "replay succeeded" )
+		assert_match( "Unexpected action call foo", err )
+	end
+	function call_throws_error_test ()
+		m.boo('Ba') ;mc:error( "Call throws error" )
+		mc:replay()
+		local ok, err = pcall( function() m.boo('Ba') end )
+		assert_false( ok, "did not throw error" )
+		assert_match( "Call throws error", err )
+	end
+-- ../src/unittestfiles.nw:35
+	
+-- ../src/main.nw:596
+	function error_during_replay_fails_test ()
+		local tmp = m.foo
+		mc:replay()
+		local ok, err = pcall( function() mc:error(1) end )
+		assert_false( ok, "error() succeeded during replay" )
+		assert_match( "Error called during replay.", err )
+	end
+	function error_twice_fails_test ()
+		local tmp = m.foo ;mc:error(1)
+		local ok, err = pcall( function() mc:error(2) end )
+		assert_false( ok, "duplicate error() succeeded" )
+		assert_match( "Returns and/or Error called twice for same action.", err )
+	end
+	function error_plus_returns_fails_test ()
+		local tmp = m.foo ;mc:returns(1)
+		local ok, err = pcall( function() mc:error(2) end )
+		assert_false( ok, "both error and returns succeeded" )
+		assert_match( "Returns and/or Error called twice for same action.", err )
+	end
+
+-- ../src/unittestfiles.nw:36
+	
+-- ../src/action/index.nw:13
+	function index_test ()
+		local tmp = m.foo
+		mc:replay()
+		local tmp = m.foo
+		assert_nil( tmp )
+		mc:verify()
+	end
+	function index_returns_test ()
+		local tmp = m.foo ;mc:returns( 1 )
+		mc:replay()
+		local tmp = m.foo
+		assert_equal( 1, tmp )
+		mc:verify()
+	end
+	function index_wrong_key_fails_test ()
+		local tmp = m.foo ;mc:returns( 1 )
+		mc:replay()
+		local ok, err = pcall( function() local tmp = m.bar end )
+		assert_false( ok, "replay succeeded" )
+		assert_match( "Unexpected action index bar", err )
+	end
+	function index_throws_error_test ()
+		local tmp = m.foo ;mc:error( "Index throws error" )
+		mc:replay()
+		local ok, err = pcall( function() tmp = m.foo end )
+		assert_false( ok, "did not throw error" )
+		assert_match( "Index throws error", err )
+	end
+-- ../src/unittestfiles.nw:37
+	
+-- ../src/action/newindex.nw:9
+	function newindex_test ()
+		m.foo = 1
+		mc:replay()
+		m.foo = 1
+		mc:verify()
+	end
+	function newindex_anyarg_test ()
+		m.foo = mc.ANYARG
+		mc:replay()
+		m.foo = 1
+		mc:verify()
+	end
+	function newindex_wrong_key_fails_test ()
+		m.foo = 1
+		mc:replay()
+		local ok, err = pcall( function() m.bar = 1 end )
+		assert_false( ok, "replay succeeded" )
+		assert_match( "Unexpected action newindex", err )
+	end
+	function newindex_wrong_value_fails_test ()
+		m.foo = 1
+		mc:replay()
+		local ok, err = pcall( function() m.foo = 0 end )
+		assert_false( ok, "replay succeeded" )
+		assert_match( "Unexpected action newindex foo", err )
+	end
+	function newindex_throws_error_test ()
+		m.foo = 1 ;mc:error( "newindex throws error" )
+		mc:replay()
+		local ok, err = pcall( function() m.foo = 1 end )
+		assert_false( ok, "did not throw error" )
+		assert_match( "newindex throws error", err )
+	end
+-- ../src/unittestfiles.nw:38
+	
+-- ../src/main.nw:550
+	function returns_during_replay_fails_test ()
+		local tmp = m.foo
+		mc:replay()
+		local ok, err = pcall( function() mc:returns(1) end )
+		assert_false( ok, "returns() succeeded during replay" )
+		assert_match( "Returns called during replay.", err )
+	end
+	function returns_on_nonreturning_action_fails_test ()
+		m.foo = 1 -- assignments can't return
+		local ok, err = pcall( function() mc:returns(0) end )
+		assert_false( ok, "returns() succeeded on non-returning action" )
+		assert_match( "Previous action can not return anything.", err )
+	end
+	function returns_twice_fails_test ()
+		local tmp = m.foo ;mc:returns(1)
+		local ok, err = pcall( function() mc:returns(2) end )
+		assert_false( ok, "duplicate returns() succeeded" )
+		assert_match( "Returns and/or Error called twice for same action.", err )
+	end
+
+-- ../src/unittestfiles.nw:39
+	
+-- ../src/action/selfcall.nw:12
+	function selfcall_test ()
+		m(11)
+		mc:replay()
+		local tmp = m(11)
+		assert_nil( tmp )
+		mc:verify()
+	end
+	function selfcall_returns_test ()
+		m(99) ;mc:returns(1,nil,'foo')
+		mc:replay()
+		local a,b,c = m(99)
+		assert_equal( 1, a )
+		assert_equal( nil, b )
+		assert_equal( 'foo', c )
+		mc:verify()
+	end
+	function selfcall_wrong_argument_fails_test ()
+		m(99) ;mc:returns('a','b','c')
+		mc:replay()
+		local ok, err = pcall( function() m(90) end )
+		assert_false( ok, "replay succeeded" )
+		assert_match( "Unexpected action selfcall", err )
+	end
+	function selfcall_wrong_number_of_arguments_fails_test ()
+		m(1,2,3)
+		mc:replay()
+		local ok, err = pcall( function() m(1,2,3,4) end )
+		assert_false( ok, "replay succeeded" )
+		assert_match( "Unexpected action selfcall", err )
+	end
+	function selfcall_throws_error_test ()
+		m('Ba') ;mc:error( "Selfcall throws error" )
+		mc:replay()
+		local ok, err = pcall( function() m('Ba') end )
+		assert_false( ok, "did not throw error" )
+		assert_match( "Selfcall throws error", err )
+	end
diff --git a/build/unit/userguide.lua b/build/unit/userguide.lua
new file mode 100644
index 0000000..4ebd22d
--- /dev/null
+++ b/build/unit/userguide.lua
@@ -0,0 +1,264 @@
+-- ../src/doc/userguide/unittests.nw:7
+	
+-- ../src/misc.nw:7
+	------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------
+	-- Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+	-- See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+
+-- ../src/doc/userguide/unittests.nw:8
+	
+	require 'lunit'
+	module( 'unit.userguide', lunit.testcase, package.seeall )
+	
+	
+-- ../src/doc/userguide/section_actions.nw:32
+	function actions_test ()
+		
+-- ../src/doc/userguide/section_actions.nw:20
+require 'lemock'
+local mc = lemock.controller()
+local m = mc:mock()
+
+m.x = 17    -- assignment
+r = m.x     -- indexing
+m.x(1,2,3)  -- method call
+m:x(1,2,3)  -- method call
+m(1,2,3)    -- self call
+-- ../src/doc/userguide/section_actions.nw:34
+	end
+-- ../src/doc/userguide/unittests.nw:13
+	
+-- ../src/doc/userguide/section_anyargs.nw:42
+	function example_anyargs_test ()
+		package.loaded.foo = nil
+		package.preload.foo = function ()
+			foo = {}
+			function foo.fetch_data (con)
+				local res = con:poll()
+				while not res do
+					con:sleep( 10 )
+					res = con:poll()
+				end
+				con.lasttime = os.time()
+				return tonumber( res )
+			end
+		end
+		
+-- ../src/doc/userguide/section_anyargs.nw:24
+require 'lemock'
+local mc = lemock.controller()
+local con = mc:mock()
+
+con:poll()           ;mc :returns(nil)
+con:sleep(mc.ANYARG)
+con:poll()           ;mc :returns('123.45')
+con.lasttime = mc.ANYARG
+
+mc:replay()
+require 'foo'
+local res = foo.fetch_data(con)
+assert( math.abs(res-123.45) < 0.0005 )
+
+mc:verify()
+-- ../src/doc/userguide/section_anyargs.nw:57
+	end
+-- ../src/doc/userguide/unittests.nw:14
+	
+-- ../src/doc/userguide/section_close.nw:53
+	function close_test ()
+		package.loaded.foo = nil
+		package.preload.foo = function ()
+			foo = {}
+			function foo.dump (xio, name, len)
+				local f = xio.open( name, 'r' )
+				f:read( len )
+				f:close()
+			end
+		end
+		
+-- ../src/doc/userguide/section_close.nw:31
+require 'lemock'
+local mc = lemock.controller()
+local myio = mc:mock()
+local fs   = mc:mock()
+
+myio.open('abc', 'r') ;mc :returns(fs)
+mc :label('open')
+
+fs:read(mc.ANYARG) ;mc :returns('data')
+mc :atleastonce() :label('read') :depend('open')
+
+fs:close() ;mc :returns(true)
+mc :depend('open') :close('read')
+
+mc:replay()
+require 'foo'
+foo.dump(myio, 'abc', 128)
+
+mc:verify()
+-- ../src/doc/userguide/section_close.nw:64
+	end
+-- ../src/doc/userguide/unittests.nw:15
+	
+-- ../src/doc/userguide/section_label_depend.nw:57
+	function example_depend_test ()
+		package.loaded.foo = nil
+		package.preload.foo = function ()
+			foo = {}
+			function foo.draw_square (sq)
+				sq:botright() sq:topright() sq:rightedge()
+				sq:botleft()  sq:topleft()  sq:leftedge()
+				sq:topedge() sq:botedge()
+				sq:fill()
+			end
+		end
+		
+-- ../src/doc/userguide/section_label_depend.nw:35
+require 'lemock'
+local mc = lemock.controller()
+local square = mc:mock()
+
+square:topleft()   ;mc :label('tl')
+square:topright()  ;mc :label('tr')
+square:botleft()   ;mc :label('bl')
+square:botright()  ;mc :label('br')
+square:leftedge()  ;mc :label('edge') :depend('tl', 'bl')
+square:rightedge() ;mc :label('edge') :depend('tr', 'br')
+square:topedge()   ;mc :label('edge') :depend('tl', 'tr')
+square:botedge()   ;mc :label('edge') :depend('bl', 'br')
+square:fill()      ;mc                :depend('edge')
+
+mc:replay()
+require 'foo'
+foo.draw_square( square )
+
+mc:verify()
+-- ../src/doc/userguide/section_label_depend.nw:69
+	end
+-- ../src/doc/userguide/unittests.nw:16
+	
+-- ../src/doc/userguide/chapter_tricks.nw:65
+	function overloading_test ()
+		
+-- ../src/doc/userguide/chapter_tricks.nw:39
+require 'lemock'
+local mc = lemock.controller()
+local m = mc:mock()
+
+do
+local function add (a, b)
+    if type(a) == 'number' then
+        return m.add_number(a, b)
+    else
+        return m.add_string(a, b)
+    end
+end
+rawset( m, 'add', add ) -- not recorded
+end -- do
+
+m.add_number(1, 2)         ;mc :returns(3)
+m.add_string('foo', 'bar') ;mc :returns('foobar')
+
+mc:replay()
+assert_equal( 3, m.add(1, 2) )
+assert_equal( 'foobar', m.add('foo', 'bar') )
+
+mc:verify()
+-- ../src/doc/userguide/chapter_tricks.nw:67
+	end
+-- ../src/doc/userguide/unittests.nw:17
+	
+-- ../src/doc/userguide/section_returns_error.nw:36
+	function returns_error_test ()
+		
+-- ../src/doc/userguide/section_returns_error.nw:27
+require 'lemock'
+local mc = lemock.controller()
+local m = mc:mock()
+
+m:foo(17)  ;mc :returns(nil, "index out of range")
+m:bar(-1)  ;mc :error("invalid index")
+-- ../src/doc/userguide/section_returns_error.nw:38
+	end
+-- ../src/doc/userguide/unittests.nw:18
+	
+-- ../src/doc/userguide/chapter_introduction.nw:71
+	function example_simple_test ()
+		package.loaded.foo = nil
+		package.preload.foo = function ()
+			foo = {}
+			q = require 'luasql.sqlite3'
+			function foo.insert_data()
+				local env = q()
+				local con = env:connect( '/data/base' )
+				local ok, err = pcall( con.execute, con, 'insert foo bar' )
+				con:close()
+				env:close()
+				return ok
+			end
+			return foo
+		end
+		
+-- ../src/doc/userguide/chapter_introduction.nw:40
+-- Setup
+require 'lemock'
+local mc = lemock.controller()
+local sqlite3 = mc:mock()
+local env     = mc:mock()
+local con     = mc:mock()
+package.loaded.luasql = nil
+package.preload['luasql.sqlite3'] = function ()
+    luasql = {}
+    luasql.sqlite3 = sqlite3
+    return sqlite3
+end
+
+-- Record
+sqlite3()                 ;mc :returns(env)
+env:connect('/data/base') ;mc :returns(con)
+con:execute(mc.ANYARGS)   ;mc :error('LuaSQL: no such table')
+con:close()
+env:close()
+
+-- Replay
+mc:replay()
+require 'foo'
+local res = foo.insert_data(17)
+assert(res==false)
+
+--Verify
+mc:verify()
+-- ../src/doc/userguide/chapter_introduction.nw:87
+	end
+-- ../src/doc/userguide/unittests.nw:19
+	
+-- ../src/doc/userguide/section_times.nw:52
+	function example_times_test ()
+		package.loaded.foo = nil
+		package.preload.foo = function ()
+			foo = {}
+			function foo.mk_watcher ( con )
+				local o = {}
+				function o:set ( key, val )
+					con:update( key, val )
+				end
+				return o
+			end
+		end
+		
+-- ../src/doc/userguide/section_times.nw:36
+require 'lemock'
+local mc = lemock.controller()
+local con = mc:mock()
+
+con:log(mc.ANYARGS) ;mc                :anytimes()
+con:update('x',3)   ;mc :returns(true) :atleastonce()
+
+mc:replay()
+require 'foo'
+local watcher = foo.mk_watcher( con )
+watcher:set( 'x', 3 )
+
+mc:verify()
+-- ../src/doc/userguide/section_times.nw:65
+	end
diff --git a/build/userguide.t2t b/build/userguide.t2t
new file mode 100644
index 0000000..0dca50f
--- /dev/null
+++ b/build/userguide.t2t
@@ -0,0 +1,352 @@
+LeMock User Guide
+v 0.6
+2009-05-30
+
+%!postproc(html): – &ndash;
+%!postproc(tex):  – --
+
+= Introduction =
+
+Mock objects replace difficult external objects during unit testing by
+simulating the behaviors of the replaced objects. This is done by first
+recording actions and their responses with the mock objects, and then
+switching to replay mode. During replay mode the mock objects simulate the
+replaced objects by looking up actions and replaying the recorded
+responses, and finally verifying that all expected actions where completely
+replayed.
+
+Actions are stored in a list in a special controller object. During replay
+the list is searched in recording order for the first matching action that
+can be replayed.
+
+Restrictions on the actions can be inserted during the recording phase. An
+action can have a maximum count of how many times it will be replayed, and
+a minimum count of how many times it must be replayed to be satisfied. An
+action can depend on any set of other actions, and can not be replayed
+before all of its depended actions are satisfied. An action can close any
+set of actions when it is replayed, which stops all further replaying of
+the closed actions. This is good for simulating state changes.
+
+=== Example ===
+
+This example tests that the insert_data function of the foo module handles
+a missing data base table gracefully.
+
+```
+-- Setup
+require 'lemock'
+local mc = lemock.controller()
+local sqlite3 = mc:mock()
+local env     = mc:mock()
+local con     = mc:mock()
+package.loaded.luasql = nil
+package.preload['luasql.sqlite3'] = function ()
+    luasql = {}
+    luasql.sqlite3 = sqlite3
+    return sqlite3
+end
+
+-- Record
+sqlite3()                 ;mc :returns(env)
+env:connect('/data/base') ;mc :returns(con)
+con:execute(mc.ANYARGS)   ;mc :error('LuaSQL: no such table')
+con:close()
+env:close()
+
+-- Replay
+mc:replay()
+require 'foo'
+local res = foo.insert_data(17)
+assert(res==false)
+
+--Verify
+mc:verify()
+```
+
+First a controller is created. Then three mock objects are created, one for
+the sqlite3 module, and two for objects returned by the (simulated) module.
+
+Then a preloader for the sqlite3 module is installed, which returns the
+sqlite3 mock object instead of the actual sqlite3 module.
+
+In the record phase the expected calls and their return values (or thrown
+errors) are recorded. The order is not significant, so this simplified test
+will not detect if the close method is called before the execute method.
+
+In the replay phase the tested module is loaded and executed. It will use
+the mock objects instead of the real data base, and if it makes any
+unrecorded calls, an error is thrown.
+
+The verify phase asserts that all recorded actions have been replayed. If
+the foo module for example forgets to call the close method, verify throws
+an error.
+
+= The Mock Object =
+
+Mock objects are empty objects with special Lua meta methods that detect
+actions performed with the object. What happens depends on the state
+(recording or replaying) of the controller which created the mock object.
+During recording the mock object adds the action to the controller's list
+of recorded actions. During replay the mock object looks for a matching
+recorded action that can be replayed, and simulates the action.
+
+Some action attributes can not be inferred by the mock objects, for example
+return values. These attributes have to be added afterwards with special
+controller methods, and always affect the last recorded action.
+
+== Actions ==
+
+Mock objects detect four types of actions: assignment, indexing, method
+call, and self call. During replay an action will only match if it is the
+very same action, that is, the same type of action performed on the same
+mock object with all the same arguments. There are however
+[special arguments #anyargs] that can be used during recording.
+
+```
+require 'lemock'
+local mc = lemock.controller()
+local m = mc:mock()
+
+m.x = 17    -- assignment
+r = m.x     -- indexing
+m.x(1,2,3)  -- method call
+m:x(1,2,3)  -- method call
+m(1,2,3)    -- self call
+```
+== Anyargs ==[anyargs]
+
+
+An //anyarg// is a special argument used when recording, that will match
+any argument during replay. It can appear anywhere and any times in an
+argument list, or as the argument in an assignment, to replace real
+arguments. There is also //anyargs//, which will match any number
+(including zero) of any arguments. Anyargs can only appear as the last
+argument of an argument list. Anyarg and anyargs are handy when the actual
+values of the arguments during replay are unimportant or unknown.
+
+Anyarg and anyargs are constants defined in the controller object.
+
+=== Example ===
+
+This example tests that the fetch_data function of module foo waits a while
+and retries when no data is immediately available, and that it updates the
+value of lasttime.
+
+```
+require 'lemock'
+local mc = lemock.controller()
+local con = mc:mock()
+
+con:poll()           ;mc :returns(nil)
+con:sleep(mc.ANYARG)
+con:poll()           ;mc :returns('123.45')
+con.lasttime = mc.ANYARG
+
+mc:replay()
+require 'foo'
+local res = foo.fetch_data(con)
+assert( math.abs(res-123.45) < 0.0005 )
+
+mc:verify()
+```
+= The Controller =
+
+The controller's main purpose is to store the recorded actions, create mock
+objects, switch to replay mode, and verify the completion of the replay
+phase. But it is also needed to set or change special action attributes
+during recording.
+
+It is possible, although doubtfully useful, to use several controllers in
+parallel during a single unit test. Each controller maintains its own
+action list and state, and mock objects remember which controller they
+belong to.
+
+== Returns & Error ==
+
+The by far most useful special action attribute is the return value.
+Indexing actions can return a single value, while call actions and self
+call actions can return a list of values. The return value is set with the
+//returns// method, and it is an error to set the return value twice for
+the same action.
+
+For purposes of unit testing it is often useful to simulate errors. All
+actions can raise an error, and return an error value (usually a string).
+The return value is set with the //error// method. An action can not have
+both a return value and raise an error.
+
+=== Example ===
+```
+require 'lemock'
+local mc = lemock.controller()
+local m = mc:mock()
+
+m:foo(17)  ;mc :returns(nil, "index out of range")
+m:bar(-1)  ;mc :error("invalid index")
+```
+== Label & Depend ==
+
+Dependencies block actions from replaying until other actions have replayed
+first. They can be used to verify that actions are being replayed in a
+valid order.
+
+To add dependencies, actions must first be labeled with one or more
+//labels//. The same label can be given to several actions. As long as some
+action with the label remains unsatisfied, that label is blocked, and all
+actions depending on that label will not replay.
+
+=== Example ===
+
+This (contrived) example tests that function draw_square in module foo
+calls all the necessary drawing methods of a square object in a correct
+order. Note that there can be more than one correct order.
+
+```
+require 'lemock'
+local mc = lemock.controller()
+local square = mc:mock()
+
+square:topleft()   ;mc :label('tl')
+square:topright()  ;mc :label('tr')
+square:botleft()   ;mc :label('bl')
+square:botright()  ;mc :label('br')
+square:leftedge()  ;mc :label('edge') :depend('tl', 'bl')
+square:rightedge() ;mc :label('edge') :depend('tr', 'br')
+square:topedge()   ;mc :label('edge') :depend('tl', 'tr')
+square:botedge()   ;mc :label('edge') :depend('bl', 'br')
+square:fill()      ;mc                :depend('edge')
+
+mc:replay()
+require 'foo'
+foo.draw_square( square )
+
+mc:verify()
+```
+
+This example demonstrates two different ways of using dependencies. All the
+corners have unique labels, because each edge depend on a set of specific
+corners. But all the edges have the same label, because the fill operation
+only depends on //all// edges have been satisfied.
+== Times ==
+
+The default for a recorded action is to be replayed exactly once.
+``times(2)`` changes that to exactly two times, and ``times(1,2)`` changes
+it to at least one time and at most two times.
+
+When the action has been replayed the least count times it is
+//satisfied//, which means verify will not complain about it, and it no
+longer blocks actions that depend on this action from being replayed. If
+the least count is zero the action is automatically satisfied and need not
+be replayed at all, i.e., it is optional.
+
+When the action has been replayed the most count times it will not replay
+any more. The most replay count can be set to infinity (``math.huge`` or
+``1/0``), in which case the action will never stop replaying.
+
+``anytimes()`` can be used as an alias for ``times(0,1/0)``, and
+``atleastonce()`` can be used as an alias for ``times(1,1/0)``.
+
+=== Example ===
+
+This example tests that method update is called at least once.
+
+```
+require 'lemock'
+local mc = lemock.controller()
+local con = mc:mock()
+
+con:log(mc.ANYARGS) ;mc                :anytimes()
+con:update('x',3)   ;mc :returns(true) :atleastonce()
+
+mc:replay()
+require 'foo'
+local watcher = foo.mk_watcher( con )
+watcher:set( 'x', 3 )
+
+mc:verify()
+```
+== Close ==
+
+Close can be used to simulate state changes in a limited way. When an
+action with a close statement is replayed for the first time, it will
+permanently block all labels in its close statement, so that actions with
+these labels no longer replays. This passes on matching to later actions in
+the action list, which may for example have different return values.
+
+The closing simply blocks the labels, and it has nothing to do with max
+replay counts or if closed actions have been satisfied or not. Closing an
+unsatisfied action however results in an immediate failure.
+
+=== Example ===
+
+This example tests that the dump function of module foo calls the myio
+functions in a correct order. The read function can be called any number of
+times, until it is closed by the close function.
+
+```
+require 'lemock'
+local mc = lemock.controller()
+local myio = mc:mock()
+local fs   = mc:mock()
+
+myio.open('abc', 'r') ;mc :returns(fs)
+mc :label('open')
+
+fs:read(mc.ANYARG) ;mc :returns('data')
+mc :atleastonce() :label('read') :depend('open')
+
+fs:close() ;mc :returns(true)
+mc :depend('open') :close('read')
+
+mc:replay()
+require 'foo'
+foo.dump(myio, 'abc', 128)
+
+mc:verify()
+```
+= Tricks =
+
+Mock objects are completely empty, and do not contain any methods or
+properties of their own. If they did, that would risk shadowing a name of a
+simulated object's method or property. There is however nothing preventing
+users from defining methods and properties in mock objects. This way mock
+objects can be turned into stubs, or a kind of mock–stub hybrid.
+
+== Method Overloading ==
+
+Lua does not support method overloading, but it can be (and sometimes is)
+implemented manually by testing of function arguments. This presents a
+problem to LeMock, because it matches exact arguments, and anyargs in not
+sufficient. In this case the mock object can be extended with a dispatcher
+function.
+
+=== Example ===
+
+This example shows a mock object with an overloaded add function. The stub
+function can not be defined in the usual way, because that would record an
+assignment action; it needs to be defined with //rawset//.
+
+```
+require 'lemock'
+local mc = lemock.controller()
+local m = mc:mock()
+
+do
+local function add (a, b)
+    if type(a) == 'number' then
+        return m.add_number(a, b)
+    else
+        return m.add_string(a, b)
+    end
+end
+rawset( m, 'add', add ) -- not recorded
+end -- do
+
+m.add_number(1, 2)         ;mc :returns(3)
+m.add_string('foo', 'bar') ;mc :returns('foobar')
+
+mc:replay()
+assert_equal( 3, m.add(1, 2) )
+assert_equal( 'foobar', m.add('foo', 'bar') )
+
+mc:verify()
+```
diff --git a/build/www/COPYRIGHT.t2t b/build/www/COPYRIGHT.t2t
new file mode 100644
index 0000000..01d741d
--- /dev/null
+++ b/build/www/COPYRIGHT.t2t
@@ -0,0 +1,11 @@
+LeMock
+
+
+%!includeconf: config.rc
+%!preproc: COPYRIGHT_ "[COPYRIGHT COPYRIGHT.html]"
+%!preproc: DEVEL_     "[DEVEL DEVEL.html]"
+%!preproc: "build/htdocs/userguide.html" "[the user guide userguide.html]"
+%!postproc(html): 'ID="body"' 'ID="page-COPYRIGHT"'
+%!include(html): ''menubar.html''
+= License =
+%!include: ../../COPYRIGHT
diff --git a/build/www/DEVEL.t2t b/build/www/DEVEL.t2t
new file mode 100644
index 0000000..51b8413
--- /dev/null
+++ b/build/www/DEVEL.t2t
@@ -0,0 +1,13 @@
+LeMock
+
+
+%!includeconf: config.rc
+%!preproc: COPYRIGHT_ "[COPYRIGHT COPYRIGHT.html]"
+%!preproc: DEVEL_     "[DEVEL DEVEL.html]"
+%!preproc: "build/htdocs/userguide.html" "[the user guide userguide.html]"
+%!postproc(html): 'ID="body"' 'ID="page-DEVEL"'
+%!include(html): ''menubar.html''
+= Developer Notes =
+%!include: ../../DEVEL
+--------------------
+%%Date(%Y-%m-%d)
diff --git a/build/www/HISTORY.t2t b/build/www/HISTORY.t2t
new file mode 100644
index 0000000..f29f930
--- /dev/null
+++ b/build/www/HISTORY.t2t
@@ -0,0 +1,13 @@
+LeMock
+
+
+%!includeconf: config.rc
+%!preproc: COPYRIGHT_ "[COPYRIGHT COPYRIGHT.html]"
+%!preproc: DEVEL_     "[DEVEL DEVEL.html]"
+%!preproc: "build/htdocs/userguide.html" "[the user guide userguide.html]"
+%!postproc(html): 'ID="body"' 'ID="page-HISTORY"'
+%!include(html): ''menubar.html''
+= History =
+%!include: ../../HISTORY
+--------------------
+%%Date(%Y-%m-%d)
diff --git a/build/www/README.t2t b/build/www/README.t2t
new file mode 100644
index 0000000..f2c0c70
--- /dev/null
+++ b/build/www/README.t2t
@@ -0,0 +1,13 @@
+LeMock
+
+
+%!includeconf: config.rc
+%!preproc: COPYRIGHT_ "[COPYRIGHT COPYRIGHT.html]"
+%!preproc: DEVEL_     "[DEVEL DEVEL.html]"
+%!preproc: "build/htdocs/userguide.html" "[the user guide userguide.html]"
+%!postproc(html): 'ID="body"' 'ID="page-README"'
+%!include(html): ''menubar.html''
+= Readme =
+%!include: ../../README
+--------------------
+%%Date(%Y-%m-%d)
diff --git a/build/www/config.rc b/build/www/config.rc
new file mode 100644
index 0000000..5938508
--- /dev/null
+++ b/build/www/config.rc
@@ -0,0 +1,3 @@
+%!options: --no-rc
+%!style(html): style.css
+%!options(html): --css-sugar 
diff --git a/build/www/index.t2t b/build/www/index.t2t
new file mode 100644
index 0000000..46eeada
--- /dev/null
+++ b/build/www/index.t2t
@@ -0,0 +1,9 @@
+LeMock
+
+
+%!includeconf: config.rc
+%!preproc: COPYRIGHT_ "[COPYRIGHT COPYRIGHT.html]"
+%!preproc: DEVEL_     "[DEVEL DEVEL.html]"
+%!preproc: "build/htdocs/userguide.html" "[the user guide userguide.html]"
+%!postproc(html): 'ID="body"' 'ID="page-index"'
+%!include(html): ''menubar.html''
diff --git a/build/www/menubar.html b/build/www/menubar.html
new file mode 100644
index 0000000..4c3e4d3
--- /dev/null
+++ b/build/www/menubar.html
@@ -0,0 +1,7 @@
+<ul id="main_menu">
+  <li id="main_menu-README"><a    href="README.html"   >Readme</a></li>
+  <li id="main_menu-COPYRIGHT"><a href="COPYRIGHT.html">License</a></li>
+  <li id="main_menu-userguide"><a href="userguide.html">Userguide</a></li>
+  <li id="main_menu-HISTORY"><a   href="HISTORY.html"  >History</a></li>
+  <li id="main_menu-DEVEL"><a     href="DEVEL.html"    >Devel</a></li>
+</ul>
diff --git a/build/www/userguide.t2t b/build/www/userguide.t2t
new file mode 100644
index 0000000..600f959
--- /dev/null
+++ b/build/www/userguide.t2t
@@ -0,0 +1,13 @@
+LeMock
+
+
+%!includeconf: config.rc
+%!preproc: COPYRIGHT_ "[COPYRIGHT COPYRIGHT.html]"
+%!preproc: DEVEL_     "[DEVEL DEVEL.html]"
+%!preproc: "build/htdocs/userguide.html" "[the user guide userguide.html]"
+%!postproc(html): 'ID="body"' 'ID="page-userguide"'
+%!include(html): ''menubar.html''
+%%toc
+%!include: ../userguide.t2t
+--------------------
+%%Date(%Y-%m-%d)
diff --git a/cmake/FindLua.cmake b/cmake/FindLua.cmake
new file mode 100644
index 0000000..7fb7ca3
--- /dev/null
+++ b/cmake/FindLua.cmake
@@ -0,0 +1,118 @@
+# Locate Lua library
+# This module defines
+#  LUA_EXECUTABLE, if found
+#  LUA_FOUND, if false, do not try to link to Lua 
+#  LUA_LIBRARIES
+#  LUA_INCLUDE_DIR, where to find lua.h
+#  LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8)
+#
+# Note that the expected include convention is
+#  #include "lua.h"
+# and not
+#  #include <lua/lua.h>
+# This is because, the lua location is not standardized and may exist
+# in locations other than lua/
+
+#=============================================================================
+# Copyright 2007-2009 Kitware, Inc.
+# Modified to support Lua 5.2 by LuaDist 2012
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+#
+# The required version of Lua can be specified using the
+# standard syntax, e.g. FIND_PACKAGE(Lua 5.1)
+# Otherwise the module will search for any available Lua implementation
+
+# Always search for non-versioned lua first (recommended)
+SET(_POSSIBLE_LUA_INCLUDE include include/lua)
+SET(_POSSIBLE_LUA_EXECUTABLE lua)
+SET(_POSSIBLE_LUA_LIBRARY lua)
+
+# Determine possible naming suffixes (there is no standard for this)
+IF(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR)
+  SET(_POSSIBLE_SUFFIXES "${Lua_FIND_VERSION_MAJOR}${Lua_FIND_VERSION_MINOR}" "${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR}" "-${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR}")
+ELSE(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR)
+  SET(_POSSIBLE_SUFFIXES "52" "5.2" "-5.2" "51" "5.1" "-5.1")
+ENDIF(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR)
+
+# Set up possible search names and locations
+FOREACH(_SUFFIX ${_POSSIBLE_SUFFIXES})
+  LIST(APPEND _POSSIBLE_LUA_INCLUDE "include/lua${_SUFFIX}")
+  LIST(APPEND _POSSIBLE_LUA_EXECUTABLE "lua${_SUFFIX}")
+  LIST(APPEND _POSSIBLE_LUA_LIBRARY "lua${_SUFFIX}")
+ENDFOREACH(_SUFFIX)
+
+# Find the lua executable
+FIND_PROGRAM(LUA_EXECUTABLE
+  NAMES ${_POSSIBLE_LUA_EXECUTABLE}
+)
+
+# Find the lua header
+FIND_PATH(LUA_INCLUDE_DIR lua.h
+  HINTS
+  $ENV{LUA_DIR}
+  PATH_SUFFIXES ${_POSSIBLE_LUA_INCLUDE}
+  PATHS
+  ~/Library/Frameworks
+  /Library/Frameworks
+  /usr/local
+  /usr
+  /sw # Fink
+  /opt/local # DarwinPorts
+  /opt/csw # Blastwave
+  /opt
+)
+
+# Find the lua library
+FIND_LIBRARY(LUA_LIBRARY 
+  NAMES ${_POSSIBLE_LUA_LIBRARY}
+  HINTS
+  $ENV{LUA_DIR}
+  PATH_SUFFIXES lib64 lib
+  PATHS
+  ~/Library/Frameworks
+  /Library/Frameworks
+  /usr/local
+  /usr
+  /sw
+  /opt/local
+  /opt/csw
+  /opt
+)
+
+IF(LUA_LIBRARY)
+  # include the math library for Unix
+  IF(UNIX AND NOT APPLE)
+    FIND_LIBRARY(LUA_MATH_LIBRARY m)
+    SET( LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}" CACHE STRING "Lua Libraries")
+  # For Windows and Mac, don't need to explicitly include the math library
+  ELSE(UNIX AND NOT APPLE)
+    SET( LUA_LIBRARIES "${LUA_LIBRARY}" CACHE STRING "Lua Libraries")
+  ENDIF(UNIX AND NOT APPLE)
+ENDIF(LUA_LIBRARY)
+
+# Determine Lua version
+IF(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h")
+  FILE(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"")
+
+  STRING(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}")
+  UNSET(lua_version_str)
+ENDIF()
+
+INCLUDE(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if 
+# all listed variables are TRUE
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua
+                                  REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR
+                                  VERSION_VAR LUA_VERSION_STRING)
+
+MARK_AS_ADVANCED(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY LUA_EXECUTABLE)
+
diff --git a/cmake/dist.cmake b/cmake/dist.cmake
new file mode 100644
index 0000000..310ef94
--- /dev/null
+++ b/cmake/dist.cmake
@@ -0,0 +1,321 @@
+# LuaDist CMake utility library.
+# Provides sane project defaults and macros common to LuaDist CMake builds.
+# 
+# Copyright (C) 2007-2012 LuaDist.
+# by David Manura, Peter Drahoš
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# For details see the COPYRIGHT file distributed with LuaDist.
+# Please note that the package source code is licensed under its own license.
+
+## Extract information from dist.info
+if ( NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/dist.info )
+  message ( FATAL_ERROR
+    "Missing dist.info file (${CMAKE_CURRENT_SOURCE_DIR}/dist.info)." )
+endif ()
+file ( READ ${CMAKE_CURRENT_SOURCE_DIR}/dist.info DIST_INFO )
+if ( "${DIST_INFO}" STREQUAL "" )
+  message ( FATAL_ERROR "Failed to load dist.info." )
+endif ()
+# Reads field `name` from dist.info string `DIST_INFO` into variable `var`.
+macro ( _parse_dist_field name var )
+  string ( REGEX REPLACE ".*${name}[ \t]?=[ \t]?[\"']([^\"']+)[\"'].*" "\\1"
+           ${var} "${DIST_INFO}" )
+  if ( ${var} STREQUAL DIST_INFO )
+    message ( FATAL_ERROR "Failed to extract \"${var}\" from dist.info" )
+  endif ()
+endmacro ()
+#
+_parse_dist_field ( name DIST_NAME )
+_parse_dist_field ( version DIST_VERSION )
+_parse_dist_field ( license DIST_LICENSE )
+_parse_dist_field ( author DIST_AUTHOR )
+_parse_dist_field ( maintainer DIST_MAINTAINER )
+_parse_dist_field ( url DIST_URL )
+_parse_dist_field ( desc DIST_DESC )
+message ( "DIST_NAME: ${DIST_NAME}")
+message ( "DIST_VERSION: ${DIST_VERSION}")
+message ( "DIST_LICENSE: ${DIST_LICENSE}")
+message ( "DIST_AUTHOR: ${DIST_AUTHOR}")
+message ( "DIST_MAINTAINER: ${DIST_MAINTAINER}")
+message ( "DIST_URL: ${DIST_URL}")
+message ( "DIST_DESC: ${DIST_DESC}")
+string ( REGEX REPLACE ".*depends[ \t]?=[ \t]?[\"']([^\"']+)[\"'].*" "\\1"
+         DIST_DEPENDS ${DIST_INFO} )
+if ( DIST_DEPENDS STREQUAL DIST_INFO )
+  set ( DIST_DEPENDS "" )
+endif ()
+message ( "DIST_DEPENDS: ${DIST_DEPENDS}")
+## 2DO: Parse DIST_DEPENDS and try to install Dependencies with automatically using externalproject_add
+
+
+## INSTALL DEFAULTS (Relative to CMAKE_INSTALL_PREFIX)
+# Primary paths
+set ( INSTALL_BIN bin CACHE PATH "Where to install binaries to." )
+set ( INSTALL_LIB lib CACHE PATH "Where to install libraries to." )
+set ( INSTALL_INC include CACHE PATH "Where to install headers to." )
+set ( INSTALL_ETC etc CACHE PATH "Where to store configuration files" )
+set ( INSTALL_SHARE share CACHE PATH "Directory for shared data." )
+
+# Secondary paths
+option ( INSTALL_VERSION
+      "Install runtime libraries and executables with version information." OFF)
+set ( INSTALL_DATA ${INSTALL_SHARE}/${DIST_NAME} CACHE PATH
+      "Directory the package can store documentation, tests or other data in.")  
+set ( INSTALL_DOC  ${INSTALL_DATA}/doc CACHE PATH
+      "Recommended directory to install documentation into.")
+set ( INSTALL_EXAMPLE ${INSTALL_DATA}/example CACHE PATH
+      "Recommended directory to install examples into.")
+set ( INSTALL_TEST ${INSTALL_DATA}/test CACHE PATH
+      "Recommended directory to install tests into.")
+set ( INSTALL_FOO  ${INSTALL_DATA}/etc CACHE PATH
+      "Where to install additional files")
+
+# Tweaks and other defaults
+# Setting CMAKE to use loose block and search for find modules in source directory
+set ( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true )
+set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH} )
+option ( BUILD_SHARED_LIBS "Build shared libraries" ON )
+
+# In MSVC, prevent warnings that can occur when using standard libraries.
+if ( MSVC )
+  add_definitions ( -D_CRT_SECURE_NO_WARNINGS )
+endif ()
+
+# RPath and relative linking
+option ( USE_RPATH "Use relative linking." ON)
+if ( USE_RPATH )
+  string ( REGEX REPLACE "[^!/]+" ".." UP_DIR ${INSTALL_BIN} )
+  set ( CMAKE_SKIP_BUILD_RPATH FALSE CACHE STRING "" FORCE )
+  set ( CMAKE_BUILD_WITH_INSTALL_RPATH FALSE CACHE STRING "" FORCE )
+  set ( CMAKE_INSTALL_RPATH $ORIGIN/${UP_DIR}/${INSTALL_LIB}
+        CACHE STRING "" FORCE )
+  set ( CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE CACHE STRING "" FORCE )
+  set ( CMAKE_INSTALL_NAME_DIR @executable_path/${UP_DIR}/${INSTALL_LIB}
+        CACHE STRING "" FORCE )
+endif ()
+
+## MACROS
+# Parser macro
+macro ( parse_arguments prefix arg_names option_names)
+  set ( DEFAULT_ARGS )
+  foreach ( arg_name ${arg_names} )
+    set ( ${prefix}_${arg_name} )
+  endforeach ()
+  foreach ( option ${option_names} )
+    set ( ${prefix}_${option} FALSE )
+  endforeach ()
+
+  set ( current_arg_name DEFAULT_ARGS )
+  set ( current_arg_list )
+  foreach ( arg ${ARGN} )            
+    set ( larg_names ${arg_names} )    
+    list ( FIND larg_names "${arg}" is_arg_name )                   
+    if ( is_arg_name GREATER -1 )
+      set ( ${prefix}_${current_arg_name} ${current_arg_list} )
+      set ( current_arg_name ${arg} )
+      set ( current_arg_list )
+    else ()
+      set ( loption_names ${option_names} )    
+      list ( FIND loption_names "${arg}" is_option )            
+      if ( is_option GREATER -1 )
+        set ( ${prefix}_${arg} TRUE )
+      else ()
+        set ( current_arg_list ${current_arg_list} ${arg} )
+      endif ()
+    endif ()
+  endforeach ()
+  set ( ${prefix}_${current_arg_name} ${current_arg_list} )
+endmacro ()
+
+
+# install_executable ( executable_targets )
+# Installs any executables generated using "add_executable".
+# USE: install_executable ( lua )
+# NOTE: subdirectories are NOT supported
+set ( CPACK_COMPONENT_RUNTIME_DISPLAY_NAME "${DIST_NAME} Runtime" )
+set ( CPACK_COMPONENT_RUNTIME_DESCRIPTION
+      "Executables and runtime libraries. Installed into ${INSTALL_BIN}." )
+macro ( install_executable )
+  foreach ( _file ${ARGN} )
+    if ( INSTALL_VERSION )
+      set_target_properties ( ${_file} PROPERTIES VERSION ${DIST_VERSION}
+                              SOVERSION ${DIST_VERSION} )
+    endif ()
+    install ( TARGETS ${_file} RUNTIME DESTINATION ${INSTALL_BIN}
+              COMPONENT Runtime )
+  endforeach()
+endmacro ()
+
+# install_library ( library_targets )
+# Installs any libraries generated using "add_library" into apropriate places.
+# USE: install_library ( libexpat )
+# NOTE: subdirectories are NOT supported
+set ( CPACK_COMPONENT_LIBRARY_DISPLAY_NAME "${DIST_NAME} Development Libraries" )
+set ( CPACK_COMPONENT_LIBRARY_DESCRIPTION
+  "Static and import libraries needed for development. Installed into ${INSTALL_LIB} or ${INSTALL_BIN}." )
+macro ( install_library )
+  foreach ( _file ${ARGN} )
+    if ( INSTALL_VERSION )
+      set_target_properties ( ${_file} PROPERTIES VERSION ${DIST_VERSION}
+                              SOVERSION ${DIST_VERSION} )
+    endif ()
+    install ( TARGETS ${_file}
+              RUNTIME DESTINATION ${INSTALL_BIN} COMPONENT Runtime
+              LIBRARY DESTINATION ${INSTALL_LIB} COMPONENT Runtime 
+              ARCHIVE DESTINATION ${INSTALL_LIB} COMPONENT Library )
+  endforeach()
+endmacro ()
+
+# helper function for various install_* functions, for PATTERN/REGEX args.
+macro ( _complete_install_args )
+  if ( NOT("${_ARG_PATTERN}" STREQUAL "") )
+    set ( _ARG_PATTERN PATTERN ${_ARG_PATTERN} )
+  endif ()
+  if ( NOT("${_ARG_REGEX}" STREQUAL "") )
+    set ( _ARG_REGEX REGEX ${_ARG_REGEX} )
+  endif ()
+endmacro ()
+
+# install_header ( files/directories [INTO destination] )
+# Install a directories or files into header destination.
+# USE: install_header ( lua.h luaconf.h ) or install_header ( GL )
+# USE: install_header ( mylib.h INTO mylib )
+# For directories, supports optional PATTERN/REGEX arguments like install().
+set ( CPACK_COMPONENT_HEADER_DISPLAY_NAME "${DIST_NAME} Development Headers" )
+set ( CPACK_COMPONENT_HEADER_DESCRIPTION
+      "Headers needed for development. Installed into ${INSTALL_INC}." )
+macro ( install_header )
+  parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} )
+  _complete_install_args()
+  foreach ( _file ${_ARG_DEFAULT_ARGS} )
+    if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" )
+      install ( DIRECTORY ${_file} DESTINATION ${INSTALL_INC}/${_ARG_INTO}
+                COMPONENT Header ${_ARG_PATTERN} ${_ARG_REGEX} )
+    else ()
+      install ( FILES ${_file} DESTINATION ${INSTALL_INC}/${_ARG_INTO}
+                COMPONENT Header )
+    endif ()
+  endforeach()
+endmacro ()
+
+# install_data ( files/directories [INTO destination] )
+# This installs additional data files or directories.
+# USE: install_data ( extra data.dat )
+# USE: install_data ( image1.png image2.png INTO images )
+# For directories, supports optional PATTERN/REGEX arguments like install().
+set ( CPACK_COMPONENT_DATA_DISPLAY_NAME "${DIST_NAME} Data" )
+set ( CPACK_COMPONENT_DATA_DESCRIPTION
+      "Application data. Installed into ${INSTALL_DATA}." )
+macro ( install_data )
+  parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} )
+  _complete_install_args()
+  foreach ( _file ${_ARG_DEFAULT_ARGS} )
+    if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" )
+      install ( DIRECTORY ${_file}
+                DESTINATION ${INSTALL_DATA}/${_ARG_INTO}
+                COMPONENT Data ${_ARG_PATTERN} ${_ARG_REGEX} )
+    else ()
+      install ( FILES ${_file} DESTINATION ${INSTALL_DATA}/${_ARG_INTO}
+                COMPONENT Data )
+    endif ()
+  endforeach()
+endmacro ()
+
+# INSTALL_DOC ( files/directories [INTO destination] )
+# This installs documentation content
+# USE: install_doc ( doc/ doc.pdf )
+# USE: install_doc ( index.html INTO html )
+# For directories, supports optional PATTERN/REGEX arguments like install().
+set ( CPACK_COMPONENT_DOCUMENTATION_DISPLAY_NAME "${DIST_NAME} Documentation" )
+set ( CPACK_COMPONENT_DOCUMENTATION_DESCRIPTION
+      "Application documentation. Installed into ${INSTALL_DOC}." )
+macro ( install_doc )
+  parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} )
+  _complete_install_args()
+  foreach ( _file ${_ARG_DEFAULT_ARGS} )
+    if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" )
+      install ( DIRECTORY ${_file} DESTINATION ${INSTALL_DOC}/${_ARG_INTO}
+                COMPONENT Documentation ${_ARG_PATTERN} ${_ARG_REGEX} )
+    else ()
+      install ( FILES ${_file} DESTINATION ${INSTALL_DOC}/${_ARG_INTO}
+                COMPONENT Documentation )
+    endif ()
+  endforeach()
+endmacro ()
+
+# install_example ( files/directories [INTO destination]  )
+# This installs additional examples
+# USE: install_example ( examples/ exampleA )
+# USE: install_example ( super_example super_data INTO super)
+# For directories, supports optional PATTERN/REGEX argument like install().
+set ( CPACK_COMPONENT_EXAMPLE_DISPLAY_NAME "${DIST_NAME} Examples" )
+set ( CPACK_COMPONENT_EXAMPLE_DESCRIPTION
+    "Examples and their associated data. Installed into ${INSTALL_EXAMPLE}." )
+macro ( install_example )
+  parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} )
+  _complete_install_args()
+  foreach ( _file ${_ARG_DEFAULT_ARGS} )
+    if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" )
+      install ( DIRECTORY ${_file} DESTINATION ${INSTALL_EXAMPLE}/${_ARG_INTO}
+                COMPONENT Example ${_ARG_PATTERN} ${_ARG_REGEX} )
+    else ()
+      install ( FILES ${_file} DESTINATION ${INSTALL_EXAMPLE}/${_ARG_INTO}
+                COMPONENT Example )
+    endif ()
+  endforeach()
+endmacro ()
+
+# install_test ( files/directories [INTO destination] )
+# This installs tests and test files, DOES NOT EXECUTE TESTS
+# USE: install_test ( my_test data.sql )
+# USE: install_test ( feature_x_test INTO x )
+# For directories, supports optional PATTERN/REGEX argument like install().
+set ( CPACK_COMPONENT_TEST_DISPLAY_NAME "${DIST_NAME} Tests" )
+set ( CPACK_COMPONENT_TEST_DESCRIPTION
+      "Tests and associated data. Installed into ${INSTALL_TEST}." )
+macro ( install_test )
+  parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} )
+  _complete_install_args()
+  foreach ( _file ${_ARG_DEFAULT_ARGS} )
+    if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" )
+      install ( DIRECTORY ${_file} DESTINATION ${INSTALL_TEST}/${_ARG_INTO}
+                COMPONENT Test ${_ARG_PATTERN} ${_ARG_REGEX} )
+    else ()
+      install ( FILES ${_file} DESTINATION ${INSTALL_TEST}/${_ARG_INTO}
+                COMPONENT Test )
+    endif ()
+  endforeach()
+endmacro ()
+
+# install_foo ( files/directories [INTO destination] )
+# This installs optional or otherwise unneeded content
+# USE: install_foo ( etc/ example.doc )
+# USE: install_foo ( icon.png logo.png INTO icons)
+# For directories, supports optional PATTERN/REGEX argument like install().
+set ( CPACK_COMPONENT_OTHER_DISPLAY_NAME "${DIST_NAME} Unspecified Content" )
+set ( CPACK_COMPONENT_OTHER_DESCRIPTION
+      "Other unspecified content. Installed into ${INSTALL_FOO}." )
+macro ( install_foo )
+  parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} )
+  _complete_install_args()
+  foreach ( _file ${_ARG_DEFAULT_ARGS} )
+    if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" )
+      install ( DIRECTORY ${_file} DESTINATION ${INSTALL_FOO}/${_ARG_INTO}
+                COMPONENT Other ${_ARG_PATTERN} ${_ARG_REGEX} )
+    else ()
+      install ( FILES ${_file} DESTINATION ${INSTALL_FOO}/${_ARG_INTO}
+                COMPONENT Other )
+    endif ()
+  endforeach()
+endmacro ()
+
+## CTest defaults
+
+## CPack defaults
+set ( CPACK_GENERATOR "ZIP" )
+set ( CPACK_STRIP_FILES TRUE )
+set ( CPACK_PACKAGE_NAME "${DIST_NAME}" )
+set ( CPACK_PACKAGE_VERSION "${DIST_VERSION}")
+set ( CPACK_PACKAGE_VENDOR "LuaDist" )
+set ( CPACK_COMPONENTS_ALL Runtime Library Header Data Documentation Example Other )
+include ( CPack )
diff --git a/cmake/lua.cmake b/cmake/lua.cmake
new file mode 100644
index 0000000..80bbc5f
--- /dev/null
+++ b/cmake/lua.cmake
@@ -0,0 +1,293 @@
+# LuaDist CMake utility library for Lua.
+# 
+# Copyright (C) 2007-2012 LuaDist.
+# by David Manura, Peter Drahos
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# For details see the COPYRIGHT file distributed with LuaDist.
+# Please note that the package source code is licensed under its own license.
+
+set ( INSTALL_LMOD ${INSTALL_LIB}/lua
+      CACHE PATH "Directory to install Lua modules." )
+set ( INSTALL_CMOD ${INSTALL_LIB}/lua
+      CACHE PATH "Directory to install Lua binary modules." )
+
+option ( SKIP_LUA_WRAPPER
+         "Do not build and install Lua executable wrappers." OFF)
+
+# List of (Lua module name, file path) pairs.
+# Used internally by add_lua_test.  Built by add_lua_module.
+set ( _lua_modules )
+
+# utility function: appends path `path` to path `basepath`, properly
+# handling cases when `path` may be relative or absolute.
+macro ( _append_path basepath path result )
+  if ( IS_ABSOLUTE "${path}" )
+    set ( ${result} "${path}" )
+  else ()
+    set ( ${result} "${basepath}/${path}" )
+  endif ()
+endmacro ()
+
+# install_lua_executable ( target source )
+# Automatically generate a binary if srlua package is available
+# The application or its source will be placed into /bin 
+# If the application source did not have .lua suffix then it will be added
+# USE: lua_executable ( sputnik src/sputnik.lua )
+macro ( install_lua_executable _name _source )
+  get_filename_component ( _source_name ${_source} NAME_WE )
+  # Find srlua and glue
+  find_program( SRLUA_EXECUTABLE NAMES srlua )
+  find_program( GLUE_EXECUTABLE NAMES glue )
+  # Executable output
+  set ( _exe ${CMAKE_CURRENT_BINARY_DIR}/${_name}${CMAKE_EXECUTABLE_SUFFIX} )
+  if ( NOT SKIP_LUA_WRAPPER AND SRLUA_EXECUTABLE AND GLUE_EXECUTABLE )
+    # Generate binary gluing the lua code to srlua, this is a robuust approach for most systems
+    add_custom_command(
+      OUTPUT ${_exe}
+      COMMAND ${GLUE_EXECUTABLE} 
+      ARGS ${SRLUA_EXECUTABLE} ${_source} ${_exe}
+      DEPENDS ${_source}
+      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+      VERBATIM
+    )
+    # Make sure we have a target associated with the binary
+    add_custom_target(${_name} ALL
+        DEPENDS ${_exe}
+    )
+    # Install with run permissions
+    install ( PROGRAMS ${_exe} DESTINATION ${INSTALL_BIN} COMPONENT Runtime)
+	# Also install source as optional resurce
+	install ( FILES ${_source} DESTINATION ${INSTALL_FOO} COMPONENT Other )
+  else()
+    # Install into bin as is but without the lua suffix, we assume the executable uses UNIX shebang/hash-bang magic
+    install ( PROGRAMS ${_source} DESTINATION ${INSTALL_BIN}
+            RENAME ${_source_name}
+            COMPONENT Runtime
+    )
+  endif()
+endmacro ()
+
+macro ( _lua_module_helper is_install _name ) 
+  parse_arguments ( _MODULE "LINK;ALL_IN_ONE" "" ${ARGN} )
+  # _target is CMake-compatible target name for module (e.g. socket_core).
+  # _module is relative path of target (e.g. socket/core),
+  #   without extension (e.g. .lua/.so/.dll).
+  # _MODULE_SRC is list of module source files (e.g. .lua and .c files).
+  # _MODULE_NAMES is list of module names (e.g. socket.core).
+  if ( _MODULE_ALL_IN_ONE )
+    string ( REGEX REPLACE "\\..*" "" _target "${_name}" )
+    string ( REGEX REPLACE "\\..*" "" _module "${_name}" )
+    set ( _target "${_target}_all_in_one")
+    set ( _MODULE_SRC ${_MODULE_ALL_IN_ONE} )
+    set ( _MODULE_NAMES ${_name} ${_MODULE_DEFAULT_ARGS} )
+  else ()
+    string ( REPLACE "." "_" _target "${_name}" )
+    string ( REPLACE "." "/" _module "${_name}" )
+    set ( _MODULE_SRC ${_MODULE_DEFAULT_ARGS} )
+    set ( _MODULE_NAMES ${_name} )
+  endif ()
+  if ( NOT _MODULE_SRC )
+    message ( FATAL_ERROR "no module sources specified" )
+  endif ()
+  list ( GET _MODULE_SRC 0 _first_source )
+  
+  get_filename_component ( _ext ${_first_source} EXT )
+  if ( _ext STREQUAL ".lua" )  # Lua source module
+    list ( LENGTH _MODULE_SRC _len )
+    if ( _len GREATER 1 )
+      message ( FATAL_ERROR "more than one source file specified" )
+    endif ()
+  
+    set ( _module "${_module}.lua" )
+
+    get_filename_component ( _module_dir ${_module} PATH )
+    get_filename_component ( _module_filename ${_module} NAME )
+    _append_path ( "${CMAKE_CURRENT_SOURCE_DIR}" "${_first_source}" _module_path )
+    list ( APPEND _lua_modules "${_name}" "${_module_path}" )
+
+    if ( ${is_install} )
+      install ( FILES ${_first_source} DESTINATION ${INSTALL_LMOD}/${_module_dir}
+                RENAME ${_module_filename} 
+                COMPONENT Runtime
+      )
+    endif ()
+  else ()  # Lua C binary module
+    enable_language ( C )
+    find_package ( Lua REQUIRED )
+    include_directories ( ${LUA_INCLUDE_DIR} )
+
+    set ( _module "${_module}${CMAKE_SHARED_MODULE_SUFFIX}" )
+
+    get_filename_component ( _module_dir ${_module} PATH )
+    get_filename_component ( _module_filenamebase ${_module} NAME_WE )
+    foreach ( _thisname ${_MODULE_NAMES} )
+      list ( APPEND _lua_modules "${_thisname}"
+             "${CMAKE_CURRENT_BINARY_DIR}/\${CMAKE_CFG_INTDIR}/${_module}" )
+    endforeach ()
+   
+    add_library( ${_target} MODULE ${_MODULE_SRC})
+    target_link_libraries ( ${_target} ${LUA_LIBRARY} ${_MODULE_LINK} )
+    set_target_properties ( ${_target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY
+                "${_module_dir}" PREFIX "" OUTPUT_NAME "${_module_filenamebase}" )
+    if ( ${is_install} )
+      install ( TARGETS ${_target} DESTINATION ${INSTALL_CMOD}/${_module_dir} COMPONENT Runtime)
+    endif ()
+  endif ()
+endmacro ()
+
+# add_lua_module
+# Builds a Lua source module into a destination locatable by Lua
+# require syntax.
+# Binary modules are also supported where this function takes sources and
+# libraries to compile separated by LINK keyword.
+# USE: add_lua_module ( socket.http src/http.lua )
+# USE2: add_lua_module ( mime.core src/mime.c )
+# USE3: add_lua_module ( socket.core ${SRC_SOCKET} LINK ${LIB_SOCKET} )
+# USE4: add_lua_module ( ssl.context ssl.core ALL_IN_ONE src/context.c src/ssl.c )
+#   This form builds an "all-in-one" module (e.g. ssl.so or ssl.dll containing
+#   both modules ssl.context and ssl.core).  The CMake target name will be
+#   ssl_all_in_one.
+# Also sets variable _module_path (relative path where module typically
+# would be installed).
+macro ( add_lua_module )
+  _lua_module_helper ( 0 ${ARGN} )
+endmacro ()
+
+
+# install_lua_module
+# This is the same as `add_lua_module` but also installs the module.
+# USE: install_lua_module ( socket.http src/http.lua )
+# USE2: install_lua_module ( mime.core src/mime.c )
+# USE3: install_lua_module ( socket.core ${SRC_SOCKET} LINK ${LIB_SOCKET} )
+macro ( install_lua_module )
+  _lua_module_helper ( 1 ${ARGN} )
+endmacro ()
+
+# Builds string representing Lua table mapping Lua modules names to file
+# paths.  Used internally.
+macro ( _make_module_table _outvar )
+  set ( ${_outvar} )
+  list ( LENGTH _lua_modules _n )
+  if ( ${_n} GREATER 0 ) # avoids cmake complaint
+  foreach ( _i RANGE 1 ${_n} 2 )
+    list ( GET _lua_modules ${_i} _path )
+    math ( EXPR _ii ${_i}-1 )
+    list ( GET _lua_modules ${_ii} _name )
+    set ( ${_outvar} "${_table}  ['${_name}'] = '${_path}'\;\n")
+  endforeach ()
+  endif ()
+  set ( ${_outvar}
+"local modules = {
+${_table}}" )
+endmacro ()
+
+# add_lua_test ( _testfile [ WORKING_DIRECTORY _working_dir ] )
+# Runs Lua script `_testfile` under CTest tester.
+# Optional named argument `WORKING_DIRECTORY` is current working directory to
+# run test under (defaults to ${CMAKE_CURRENT_BINARY_DIR}).
+# Both paths, if relative, are relative to ${CMAKE_CURRENT_SOURCE_DIR}.
+# Any modules previously defined with install_lua_module are automatically
+# preloaded (via package.preload) prior to running the test script.
+# Under LuaDist, set test=true in config.lua to enable testing.
+# USE: add_lua_test ( test/test1.lua [args...] [WORKING_DIRECTORY dir])
+macro ( add_lua_test _testfile )
+  if ( NOT SKIP_TESTING )
+    parse_arguments ( _ARG "WORKING_DIRECTORY" "" ${ARGN} )
+    include ( CTest )
+    find_program ( LUA NAMES lua lua.bat )
+    get_filename_component ( TESTFILEABS ${_testfile} ABSOLUTE )
+    get_filename_component ( TESTFILENAME ${_testfile} NAME )
+    get_filename_component ( TESTFILEBASE ${_testfile} NAME_WE )
+
+    # Write wrapper script.
+    # Note: One simple way to allow the script to find modules is
+    # to just put them in package.preload.
+    set ( TESTWRAPPER ${CMAKE_CURRENT_BINARY_DIR}/${TESTFILENAME} )
+    _make_module_table ( _table )
+    set ( TESTWRAPPERSOURCE
+"local CMAKE_CFG_INTDIR = ... or '.'
+${_table}
+local function preload_modules(modules)
+  for name, path in pairs(modules) do
+    if path:match'%.lua' then
+      package.preload[name] = assert(loadfile(path))
+    else
+      local name = name:gsub('.*%-', '') -- remove any hyphen prefix
+      local symbol = 'luaopen_' .. name:gsub('%.', '_')
+          --improve: generalize to support all-in-one loader?
+      local path = path:gsub('%$%{CMAKE_CFG_INTDIR%}', CMAKE_CFG_INTDIR)
+      package.preload[name] = assert(package.loadlib(path, symbol))
+    end
+  end
+end
+preload_modules(modules)
+arg[0] = '${TESTFILEABS}'
+table.remove(arg, 1)
+return assert(loadfile '${TESTFILEABS}')(unpack(arg))
+"    )
+    if ( _ARG_WORKING_DIRECTORY )
+      get_filename_component (
+         TESTCURRENTDIRABS ${_ARG_WORKING_DIRECTORY} ABSOLUTE )
+      # note: CMake 2.6 (unlike 2.8) lacks WORKING_DIRECTORY parameter.
+      set ( _pre ${CMAKE_COMMAND} -E chdir "${TESTCURRENTDIRABS}" )
+    endif ()
+    file ( WRITE ${TESTWRAPPER} ${TESTWRAPPERSOURCE})
+    add_test ( NAME ${TESTFILEBASE} COMMAND ${_pre} ${LUA}
+               ${TESTWRAPPER} "${CMAKE_CFG_INTDIR}"
+               ${_ARG_DEFAULT_ARGS} )
+  endif ()
+  # see also http://gdcm.svn.sourceforge.net/viewvc/gdcm/Sandbox/CMakeModules/UsePythonTest.cmake
+  # Note: ${CMAKE_CFG_INTDIR} is a command-line argument to allow proper
+  # expansion by the native build tool.
+endmacro ()
+
+
+# Converts Lua source file `_source` to binary string embedded in C source
+# file `_target`.  Optionally compiles Lua source to byte code (not available
+# under LuaJIT2, which doesn't have a bytecode loader).  Additionally, Lua
+# versions of bin2c [1] and luac [2] may be passed respectively as additional
+# arguments.
+#
+# [1] http://lua-users.org/wiki/BinToCee
+# [2] http://lua-users.org/wiki/LuaCompilerInLua
+function ( add_lua_bin2c _target _source )
+  find_program ( LUA NAMES lua lua.bat )
+  execute_process ( COMMAND ${LUA} -e "string.dump(function()end)"
+                    RESULT_VARIABLE _LUA_DUMP_RESULT ERROR_QUIET )
+  if ( NOT ${_LUA_DUMP_RESULT} )
+    SET ( HAVE_LUA_DUMP true )
+  endif ()
+  message ( "-- string.dump=${HAVE_LUA_DUMP}" )
+
+  if ( ARGV2 )
+    get_filename_component ( BIN2C ${ARGV2} ABSOLUTE )
+    set ( BIN2C ${LUA} ${BIN2C} )
+  else ()
+    find_program ( BIN2C NAMES bin2c bin2c.bat )
+  endif ()
+  if ( HAVE_LUA_DUMP )
+    if ( ARGV3 )
+      get_filename_component ( LUAC ${ARGV3} ABSOLUTE )
+      set ( LUAC ${LUA} ${LUAC} )
+    else ()
+      find_program ( LUAC NAMES luac luac.bat )
+    endif ()
+  endif ( HAVE_LUA_DUMP )
+  message ( "-- bin2c=${BIN2C}" )
+  message ( "-- luac=${LUAC}" )
+
+  get_filename_component ( SOURCEABS ${_source} ABSOLUTE )
+  if ( HAVE_LUA_DUMP )
+    get_filename_component ( SOURCEBASE ${_source} NAME_WE )
+    add_custom_command (
+      OUTPUT  ${_target} DEPENDS ${_source}
+      COMMAND ${LUAC} -o ${CMAKE_CURRENT_BINARY_DIR}/${SOURCEBASE}.lo
+              ${SOURCEABS}
+      COMMAND ${BIN2C} ${CMAKE_CURRENT_BINARY_DIR}/${SOURCEBASE}.lo
+              ">${_target}" )
+  else ()
+    add_custom_command (
+      OUTPUT  ${_target} DEPENDS ${SOURCEABS}
+      COMMAND ${BIN2C} ${_source} ">${_target}" )
+  endif ()
+endfunction()
diff --git a/dist.info b/dist.info
new file mode 100644
index 0000000..f797f89
--- /dev/null
+++ b/dist.info
@@ -0,0 +1,14 @@
+--- This file is part of LuaDist project
+
+name = "lemock"
+version = "0.6"
+
+desc = "Mock creation module intended for use together with a unit test framework such as lunit or lunity."
+author = "Tommy Petterson"
+license = "MIT"
+url = "http://lemock.luaforge.net"
+maintainer = "Peter Drahos"
+
+depends = {
+	"lua ~> 5.1"
+}
\ No newline at end of file
diff --git a/src/action/call.nw b/src/action/call.nw
new file mode 100644
index 0000000..52217a9
--- /dev/null
+++ b/src/action/call.nw
@@ -0,0 +1,122 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+@
+
+The Call Action
+###############
+
+The index action returns a Callable object, which will catch calls. The
+catching of the call will record a call action, and modify the index action
+to record the fact that it should return a Callable object during replay.
+
+<<Unit test for module mock call>>=
+	function call_test ()
+		m.foo(1,2,3)
+		mc:replay()
+		local tmp = m.foo(1,2,3)
+		assert_nil( tmp )
+		mc:verify()
+	end
+	function call_anyarg_test ()
+		m.foo(1,mc.ANYARG,3)
+		mc:replay()
+		local tmp = m.foo(1,2,3)
+		mc:verify()
+	end
+	function call_anyargs_test ()
+		m.foo(mc.ANYARGS)
+		mc:replay()
+		local tmp = m.foo(1,2,3)
+		mc:verify()
+	end
+	function call_anyargs_bad_fails_test ()
+		local ok, err = pcall( function() m.foo(mc.ANYARGS, 1) end )
+		assert_false( ok, "ANYARGS misused" )
+		assert_match( "ANYARGS not at end", err )
+	end
+	function call_return_test ()
+		m.foo(1,2,3) ;mc:returns( 0, 9 )
+		mc:replay()
+		local tmp1, tmp2 = m.foo(1,2,3)
+		assert_equal( 0, tmp1 )
+		assert_equal( 9, tmp2 )
+		mc:verify()
+	end
+	function call_wrong_name_fails_test ()
+		m.foo(1,2,3) ;mc:returns( 0 )
+		mc:replay()
+		local ok, err = pcall( function() m:bar(1,2,3) end )
+		assert_false( ok, "replay wrong index" )
+		assert_match( "Unexpected action index bar", err )
+	end
+	function call_wrong_arg_fails_test ()
+		m.foo(1,2,3) ;mc:returns( 0 )
+		mc:replay()
+		local ok, err = pcall( function() m.foo(1) end )
+		assert_false( ok, "replay succeeded" )
+		assert_match( "Unexpected action call foo", err )
+	end
+	function call_throws_error_test ()
+		m.boo('Ba') ;mc:error( "Call throws error" )
+		mc:replay()
+		local ok, err = pcall( function() m.boo('Ba') end )
+		assert_false( ok, "did not throw error" )
+		assert_match( "Call throws error", err )
+	end
+@
+
+Record Phase
+============
+
+<<Class Callable.record call>>=
+	function Callable.record:__call (...)
+		local index_action = self.action
+		local m = index_action.mock
+		local mc = mock_controller_map[m]
+		assert( mc.is_recording, "client uses cached callable from recording" )
+		mc:make_callable( index_action )
+		mc:add_action( Action.call:new( m, index_action.key, ... ))
+	end
+
+<<Class Action.call method new>>=
+	function Action.call:new (m, key, ...)
+		local a = Action.generic_call.new( self, m, ... )
+		a.key = key
+		return a
+	end
+@
+
+Replay Phase
+============
+
+<<Class Callable.replay call>>=
+	function Callable.replay:__call (...)
+		local index_action = self.action
+		local m = index_action.mock
+		local mc = mock_controller_map[m]
+		local call_action = mc:lookup( Action.call:new( m, index_action.key, ... ))
+		mc:replay_action( call_action )
+		if call_action.throws_error then
+			error( call_action.errorvalue, 2 )
+		end
+		return call_action:get_returnvalue()
+	end
+
+<<Unit test for class Action.call method match>>=
+	function call_match_test ()
+		local m = {}
+		local a = Action.call:new( m, 'foo', 4, 'bb' )
+		assert_true(  a:match( Action.call:new( m, 'foo', 4, 'bb' )))
+		assert_false( a:match( Action.call:new( {}, 'foo', 4, 'bb' )))
+		assert_false( a:match( Action.call:new( m, 'bar', 4, 'bb' )))
+		assert_false( a:match( Action.call:new( m, 'foo', 1, 'bb' )))
+		assert_false( a:match( Action.call:new( m, 'foo', 4, 'b' )))
+		assert_false( a:match( Action.call:new( m, 'foo', 4, 'bb', 'cc' )))
+	end
+
+<<Class Action.call method match>>=
+	function Action.call:match (q)
+		if not Action.generic_call.match( self, q )  then return false end
+		if self.key ~= q.key                         then return false end
+		return true
+	end
diff --git a/src/action/generic_call.nw b/src/action/generic_call.nw
new file mode 100644
index 0000000..491fc79
--- /dev/null
+++ b/src/action/generic_call.nw
@@ -0,0 +1,80 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+@
+
+Class Action.generic_call
+#########################
+
+The generic_call action class implements the common tasks of the two
+different call action types.
+
+There are two types of calls in Lua: a call of a function, and a call of
+the [[__call]] meta method for something else (e.g., a table). It is
+normally not necessary to differentiate the two types in the mock, because
+only the behavior is simulated so it does not matter what the simulated
+object would return. The mock always returns a Callable, which records a
+call action. The exception is when the mock object itself is called, which
+records a selfcall action.
+
+Note: a special case is if the mock contains another mock that can be
+called. This is awkward, but possible, to simulate by first referencing the
+inner mock object from the outer (an index action), and then recording the
+inner mock object as the returned value of that index action, and finally
+calling the second mock object.
+
+
+new
+---
+
+This method is extended by the concrete Action classes.
+
+<<Class Action.generic_call method new>>=
+	function Action.generic_call:new (m, ...)
+		local a = Action.generic.new( self, m )
+		a.argv   = Argv:new(...)
+		return a
+	end
+@
+
+match
+-----
+
+This method is extended by the concrete Action classes.
+
+<<Class Action.generic_call method match>>=
+	function Action.generic_call:match (q)
+		if not Action.generic.match( self, q )  then return false end
+		if not self.argv:equal( q.argv )        then return false end
+		return true
+	end
+@
+
+set_returnvalue
+---------------
+
+<<Class Action.generic_call method set_returnvalue>>=
+	function Action.generic_call:set_returnvalue (...)
+		self.returnvalue = Argv:new(...)
+		self.has_returnvalue = true
+	end
+@
+
+get_returnvalue
+---------------
+
+<<Unit test for class Action.generic_call method get_returnvalue>>=
+	function generic_call_set_and_get_returnvalue_test ()
+		local a = Action.generic_call:new()
+		assert_equal( 0, select('#', a:get_returnvalue() ))
+		a:set_returnvalue( nil, false )
+		local r1, r2 = a:get_returnvalue()
+		assert_equal( nil, r1 )
+		assert_equal( false, r2 )
+	end
+
+<<Class Action.generic_call method get_returnvalue>>=
+	function Action.generic_call:get_returnvalue ()
+		if self.has_returnvalue then
+			return self.returnvalue:unpack()
+		end
+	end
diff --git a/src/action/index.nw b/src/action/index.nw
new file mode 100644
index 0000000..80869ff
--- /dev/null
+++ b/src/action/index.nw
@@ -0,0 +1,136 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+@
+
+The Index Action
+################
+
+The index action can either be "called" (via the returned Callable) or be
+given a return value, or neither in which case it will return nil during
+replay.
+
+<<Unit test for module mock index>>=
+	function index_test ()
+		local tmp = m.foo
+		mc:replay()
+		local tmp = m.foo
+		assert_nil( tmp )
+		mc:verify()
+	end
+	function index_returns_test ()
+		local tmp = m.foo ;mc:returns( 1 )
+		mc:replay()
+		local tmp = m.foo
+		assert_equal( 1, tmp )
+		mc:verify()
+	end
+	function index_wrong_key_fails_test ()
+		local tmp = m.foo ;mc:returns( 1 )
+		mc:replay()
+		local ok, err = pcall( function() local tmp = m.bar end )
+		assert_false( ok, "replay succeeded" )
+		assert_match( "Unexpected action index bar", err )
+	end
+	function index_throws_error_test ()
+		local tmp = m.foo ;mc:error( "Index throws error" )
+		mc:replay()
+		local ok, err = pcall( function() tmp = m.foo end )
+		assert_false( ok, "did not throw error" )
+		assert_match( "Index throws error", err )
+	end
+@
+
+Record Phase
+============
+
+<<Class Mock.record index>>=
+	function Mock.record:__index (key)
+		local mc = mock_controller_map[self]
+		local action = Action.index:new( self, key )
+		mc:add_action( action )
+		return Callable.record:new( action )
+	end
+@
+
+Action new
+----------
+
+<<Unit test for class Action.index method new>>=
+	function create_index_action_test ()
+		local m = {}
+		local a = Action.index:new( m, 'foo' )
+		assert_equal( m, a.mock )
+		assert_equal( 'foo', a.key )
+	end
+
+<<Class Action.index method new>>=
+	function Action.index:new (m, key)
+		local a = Action.generic.new( self, m )
+		a.key = key
+		return a
+	end
+@
+
+Action set_returnvalue
+----------------------
+
+<<Unit test for class Action.index method set_returnvalue>>=
+	function index_returnvalue_test ()
+		local a = Action.index:new( {}, -3 )
+		a:set_returnvalue( 'foo' )
+		assert_equal( 'foo', a:get_returnvalue() )
+	end
+
+<<Class Action.index method set_returnvalue>>=
+	function Action.index:set_returnvalue (v)
+		self.returnvalue = v
+		self.has_returnvalue = true
+	end
+@
+
+Replay Phase
+============
+
+<<Class Mock.replay index>>=
+	function Mock.replay:__index (key)
+		local mc = mock_controller_map[self]
+		local index_action = mc:lookup( Action.index:new( self, key ))
+		mc:replay_action( index_action )
+		if index_action.throws_error then
+			error( index_action.errorvalue, 2 )
+		end
+		if index_action.is_callable then
+			return Callable.replay:new( index_action )
+		else
+			return index_action:get_returnvalue()
+		end
+	end
+@
+
+Action match
+------------
+
+<<Unit test for class Action.index method match>>=
+	function index_match_test ()
+		local m = {}
+		local a = Action.index:new( m, -1 )
+		assert_true(  a:match( Action.index:new( m, -1 )))
+		assert_false( a:match( Action.index:new( {}, -1 )))
+		assert_false( a:match( Action.index:new( m, 'a' )))
+	end
+
+<<Class Action.index method match>>=
+	function Action.index:match (q)
+		if not Action.generic.match( self, q )  then return false end
+		if self.key ~= q.key                    then return false end
+		return true
+	end
+@
+
+Action get_returnvalue
+----------------------
+
+<<Class Action.index method get_returnvalue>>=
+	function Action.index:get_returnvalue ()
+		return self.returnvalue
+	end
diff --git a/src/action/newindex.nw b/src/action/newindex.nw
new file mode 100644
index 0000000..b54cf2a
--- /dev/null
+++ b/src/action/newindex.nw
@@ -0,0 +1,109 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+@
+
+The Newindex Action
+###################
+
+<<Unit test for module mock newindex>>=
+	function newindex_test ()
+		m.foo = 1
+		mc:replay()
+		m.foo = 1
+		mc:verify()
+	end
+	function newindex_anyarg_test ()
+		m.foo = mc.ANYARG
+		mc:replay()
+		m.foo = 1
+		mc:verify()
+	end
+	function newindex_wrong_key_fails_test ()
+		m.foo = 1
+		mc:replay()
+		local ok, err = pcall( function() m.bar = 1 end )
+		assert_false( ok, "replay succeeded" )
+		assert_match( "Unexpected action newindex", err )
+	end
+	function newindex_wrong_value_fails_test ()
+		m.foo = 1
+		mc:replay()
+		local ok, err = pcall( function() m.foo = 0 end )
+		assert_false( ok, "replay succeeded" )
+		assert_match( "Unexpected action newindex foo", err )
+	end
+	function newindex_throws_error_test ()
+		m.foo = 1 ;mc:error( "newindex throws error" )
+		mc:replay()
+		local ok, err = pcall( function() m.foo = 1 end )
+		assert_false( ok, "did not throw error" )
+		assert_match( "newindex throws error", err )
+	end
+@
+
+Record Phase
+============
+
+<<Class Mock.record newindex>>=
+	function Mock.record:__newindex (key, val)
+		local mc = mock_controller_map[self]
+		mc:add_action( Action.newindex:new( self, key, val ))
+	end
+
+<<Class Action.newindex method new>>=
+	function Action.newindex:new (m, key, val)
+		local a = Action.generic.new( self, m )
+		a.key    = key
+		a.val    = val
+		return a
+	end
+@
+
+Replay Phase
+============
+
+<<Class Mock.replay newindex>>=
+	function Mock.replay:__newindex (key, val)
+		local mc = mock_controller_map[self]
+		local newindex_action = mc:lookup( Action.newindex:new( self, key, val ))
+		mc:replay_action( newindex_action )
+		if newindex_action.throws_error then
+			error( newindex_action.errorvalue, 2 )
+		end
+	end
+
+<<Unit test for class Action.newindex method match>>=
+	function newindex_match_test ()
+		local m = {}
+		local a = Action.newindex:new( m, 'foo', 17 )
+		assert_true(  a:match( Action.newindex:new( m, 'foo', 17 )))
+		assert_false( a:match( Action.newindex:new( {}, 'foo', 17 )))
+		assert_false( a:match( Action.newindex:new( m, 'fo', 17 )))
+		assert_false( a:match( Action.newindex:new( m, 'foo', 7 )))
+	end
+	function newindex_anyarg_test ()
+		local m = {}
+		local a = Action.newindex:new( m, 'foo', Argv.ANYARG )
+		local b = Action.newindex:new( m, 'foo', 33 )
+		local c = Action.newindex:new( m, 'foo', nil )
+		assert_true( a:match(b) )
+		assert_true( b:match(a) )
+		assert_true( a:match(c) )
+		assert_true( c:match(a) )
+	end
+	function newindex_NaN_test ()
+		local m = {}
+		local nan = 0/0
+		local a = Action.newindex:new( m, m, nan )
+		assert_true( a:match( Action.newindex:new( m, m, nan )))
+	end
+
+<<Class Action.newindex method match>>=
+	function Action.newindex:match (q)
+		if not Action.generic.match( self, q )  then return false end
+		if self.key ~= q.key                    then return false end
+		if not value_equal( self.val, q.val )
+		   and self.val ~= Argv.ANYARG
+		   and q.val    ~= Argv.ANYARG          then return false end
+		return true
+	end
diff --git a/src/action/selfcall.nw b/src/action/selfcall.nw
new file mode 100644
index 0000000..91fe6d1
--- /dev/null
+++ b/src/action/selfcall.nw
@@ -0,0 +1,95 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+@
+
+The Call Action
+###############
+
+The selfcall action is made to the Mock object itself, so no Callable or
+index action is needed.
+
+<<Unit test for module mock selfcall>>=
+	function selfcall_test ()
+		m(11)
+		mc:replay()
+		local tmp = m(11)
+		assert_nil( tmp )
+		mc:verify()
+	end
+	function selfcall_returns_test ()
+		m(99) ;mc:returns(1,nil,'foo')
+		mc:replay()
+		local a,b,c = m(99)
+		assert_equal( 1, a )
+		assert_equal( nil, b )
+		assert_equal( 'foo', c )
+		mc:verify()
+	end
+	function selfcall_wrong_argument_fails_test ()
+		m(99) ;mc:returns('a','b','c')
+		mc:replay()
+		local ok, err = pcall( function() m(90) end )
+		assert_false( ok, "replay succeeded" )
+		assert_match( "Unexpected action selfcall", err )
+	end
+	function selfcall_wrong_number_of_arguments_fails_test ()
+		m(1,2,3)
+		mc:replay()
+		local ok, err = pcall( function() m(1,2,3,4) end )
+		assert_false( ok, "replay succeeded" )
+		assert_match( "Unexpected action selfcall", err )
+	end
+	function selfcall_throws_error_test ()
+		m('Ba') ;mc:error( "Selfcall throws error" )
+		mc:replay()
+		local ok, err = pcall( function() m('Ba') end )
+		assert_false( ok, "did not throw error" )
+		assert_match( "Selfcall throws error", err )
+	end
+@
+
+Record Phase
+============
+
+<<Class Mock.record selfcall>>=
+	function Mock.record:__call (...)
+		local mc = mock_controller_map[self]
+		mc:add_action( Action.selfcall:new( self, ... ))
+	end
+
+<<Class Action.selfcall method new>>=
+	function Action.selfcall:new (m, ...)
+		local a = Action.generic_call.new( self, m, ... )
+		return a
+	end
+@
+
+Replay Phase
+============
+
+<<Class Mock.replay selfcall>>=
+	function Mock.replay:__call (...)
+		local mc = mock_controller_map[self]
+		local selfcall_action = mc:lookup( Action.selfcall:new( self, ... ))
+		mc:replay_action( selfcall_action )
+		if selfcall_action.throws_error then
+			error( selfcall_action.errorvalue, 2 )
+		end
+		return selfcall_action:get_returnvalue()
+	end
+
+<<Unit test for class Action.selfcall method match>>=
+	function selfcall_match_test ()
+		local m = {}
+		local a = Action.selfcall:new( m, 5, nil, false )
+		assert_true(  a:match( Action.selfcall:new( m, 5, nil, false )))
+		assert_false( a:match( Action.selfcall:new( {}, 5, nil, false )))
+		assert_false( a:match( Action.selfcall:new( m, nil, nil, false )))
+		assert_false( a:match( Action.selfcall:new( m, 5, false, false )))
+		assert_false( a:match( Action.selfcall:new( m, 5, nil, nil )))
+	end
+
+<<Class Action.selfcall method match>>=
+	function Action.selfcall:match (q)
+		return Action.generic_call.match( self, q )
+	end
diff --git a/src/argv.nw b/src/argv.nw
new file mode 100644
index 0000000..17fe98d
--- /dev/null
+++ b/src/argv.nw
@@ -0,0 +1,158 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+Class Argv
+##########
+
+It is convenient to handle argument lists and return lists as an abstract
+type.
+
+<<Userguide Anyargs>>=
+
+An //anyarg// is a special argument used when recording, that will match
+any argument during replay. It can appear anywhere and any times in an
+argument list, or as the argument in an assignment, to replace real
+arguments. There is also //anyargs//, which will match any number
+(including zero) of any arguments. Anyargs can only appear as the last
+argument of an argument list. Anyarg and anyargs are handy when the actual
+values of the arguments during replay are unimportant or unknown.
+@
+
+new
+---
+
+<<Unit test for class Argv method new>>=
+	function new_test ()
+		Argv:new( Argv.ANYARGS )
+		Argv:new( 1, Argv.ANYARGS )
+		Argv:new( 1, 2, Argv.ANYARGS )
+	end
+	function new_anyargs_with_extra_arguments_fails_test ()
+		local l = {}
+		l['ANYARGS,1']         = { Argv.ANYARGS, 1 }
+		l['ANYARGS,ANYARGS'  ] = { Argv.ANYARGS, Argv.ANYARGS }
+		l['1,ANYARGS,1']       = { 1, Argv.ANYARGS, 1 }
+		l['1,ANYARGS,ANYARGS'] = { 1, Argv.ANYARGS, Argv.ANYARGS }
+		for msg, args in pairs( l ) do
+			local ok, err = pcall( function() Argv:new( unpack(args) ) end )
+			assert_false( ok, "Bad ANYARGS accepted for "..msg )
+			assert_match( "ANYARGS not at end", err )
+		end
+	end
+
+<<Class Argv method new>>=
+	function Argv:new (...)
+		local av = object( self )
+		av.v = {...}
+		av.len = select('#',...)
+		for i = 1, av.len - 1 do
+			if av.v[i] == Argv.ANYARGS then
+				error( "ANYARGS not at end.", 0 )
+			end
+		end
+		return av
+	end
+@
+
+equal
+-----
+
+<<Unit test for class Argv method equal>>=
+	local l = {}
+	local function p (...) l[#l+1] = { n=select('#',...), ... } end
+	p() p(nil) p(nil,nil) p(false) p({}) p(false,nil,{},nil) p(nil,p)
+	p(true) p(0.1,'','a') p(1/0,nil,0/0) p(0/0) p(0/0, true) p(0/0, false)
+	function equal_test ()
+		local a1, a2, f, op
+		for i = 1, #l do
+			ai = Argv:new( unpack( l[i], 1, l[i].n ))
+			for j = 1, #l do
+				aj = Argv:new( unpack( l[j], 1, l[j].n ))
+				if i == j then
+					f, op = assert_true,  ') ~= ('
+				else
+					f, op = assert_false, ') == ('
+				end
+				f( ai:equal(aj), '('..ai:tostring()..op..aj:tostring()..')' )
+			end
+		end
+	end
+	function equal_anyargs_test ()
+		local a, b = {}, {}
+		a[1] = Argv:new( Argv.ANYARGS )
+		a[2] = Argv:new( 6, Argv.ANYARGS )
+		a[3] = Argv:new( 6, 5, Argv.ANYARGS )
+		for i = 1, #l do
+			b[1] = Argv:new( unpack( l[i], 1, l[i].n ))
+			b[2] = Argv:new( 6, unpack( l[i], 1, l[i].n ))
+			b[3] = Argv:new( 6, 5, unpack( l[i], 1, l[i].n ))
+			for j = 1, 3 do
+				local astr = '('..a[j]:tostring()..')'
+				local bstr = '('..b[j]:tostring()..')'
+				assert_true( a[j]:equal(b[j]), astr..' ~= '..bstr )
+				assert_true( b[j]:equal(a[j]), bstr..' ~= '..astr )
+			end
+		end
+	end
+	function equal_anyarg_test ()
+		local l = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }
+		local a1 = Argv:new( unpack(l) )
+		for i = 1, 9 do
+			l[i] = Argv.ANYARG
+			local a2 = Argv:new( unpack(l) )
+			assert_true( a1:equal(a2) )
+			assert_true( a2:equal(a1) )
+			l[i] = i
+		end
+	end
+@
+The comparison with ANYARGS is a bit tricky, because it must match the
+empty list. The list //excluding// the final ANYARGS argument (its length
+minus one) must match the other list.
+
+ANYARG and ANYARGS are created as unique identifiers, with local aliases
+for speed.
+
+<<Class Argv method equal>>=
+	Argv.ANYARGS = newproxy()  local ANYARGS = Argv.ANYARGS
+	Argv.ANYARG  = newproxy()  local ANYARG  = Argv.ANYARG
+	function Argv:equal (other)
+		local a1, n1 = self.v,  self.len
+		local a2, n2 = other.v, other.len
+		if n1-1 <= n2 and a1[n1] == ANYARGS then
+			n1 = n1-1
+			n2 = n1
+		elseif n2-1 <= n1 and a2[n2] == ANYARGS then
+			n2 = n2-1
+			n1 = n2
+		end
+		if n1 ~= n2 then
+			return false
+		end
+		for i = 1, n1 do
+			local v1, v2 = a1[i], a2[i]
+			if not value_equal(v1,v2) and v1 ~= ANYARG and v2 ~= ANYARG then
+				return false
+			end
+		end
+		return true
+	end
+@
+
+unpack
+------
+
+<<Unit test for class Argv method unpack>>=
+	function unpack_test ()
+		local a, b, c = Argv:new( false, nil, 7 ):unpack()
+		assert_equal( false, a )
+		assert_equal( nil,   b )
+		assert_equal( 7,     c )
+	end
+
+<<Class Argv method unpack>>=
+	function Argv:unpack ()
+		return unpack( self.v, 1, self.len )
+	end
diff --git a/src/class/action.nw b/src/class/action.nw
new file mode 100644
index 0000000..52ab2bf
--- /dev/null
+++ b/src/class/action.nw
@@ -0,0 +1,105 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+@
+
+Class Inheritance
+=================
+
+      ABSTRACT         CONCRETE
+ 
+ generic
+  |
+  `------------------  newindex
+  |
+  `------------------  index
+  |
+  `--  generic_call
+        |
+        `------------  call
+        |
+        `------------  selfcall
+
+
+<<Class Action>>=
+	Action = {}
+	
+	-- abstract
+	<<Class Action.generic>>
+	<<Class Action.generic_call>>
+	
+	-- concrete
+	<<Class Action.call>>
+	<<Class Action.index>>
+	<<Class Action.newindex>>
+	<<Class Action.selfcall>>
+@
+
+Abstract Action Classes
+=======================
+
+<<Class Action.generic>>=
+	Action.generic = class()
+	
+	<<Class Action.generic method add_close>>
+	<<Class Action.generic method add_depend>>
+	<<Class Action.generic method add_label>>
+	<<Class Action.generic method assert_satisfied>>
+	<<Class Action.generic method blocks>>
+	<<Class Action.generic method closes>>
+	<<Class Action.generic method depends>>
+	<<Class Action.generic method has_label>>
+	<<Class Action.generic method is_expected>>
+	<<Class Action.generic method is_satisfied>>
+	<<Class Action.generic method match>>
+	<<Class Action.generic method new>>
+	<<Class Action.generic method set_times>>
+
+
+<<Class Action.generic_call>>=
+	Action.generic_call = class( Action.generic )
+	
+	Action.generic_call.can_return = true
+	<<Class Action.generic_call method get_returnvalue>>
+	<<Class Action.generic_call method set_returnvalue>>
+	
+	<<Class Action.generic_call method match>>
+	<<Class Action.generic_call method new>>
+@
+
+Concrete Action Classes
+=======================
+
+<<Class Action.newindex>>=
+	Action.newindex = class( Action.generic )
+	
+	<<Class Action.newindex method match>>
+	<<Class Action.newindex method new>>
+	<<Class Action.newindex method tostring>>
+
+
+<<Class Action.index>>=
+	Action.index = class( Action.generic )
+	
+	Action.index.can_return = true
+	<<Class Action.index method get_returnvalue>>
+	<<Class Action.index method set_returnvalue>>
+	
+	<<Class Action.index method match>>
+	<<Class Action.index method new>>
+	<<Class Action.index method tostring>>
+
+
+<<Class Action.call>>=
+	Action.call = class( Action.generic_call )
+	
+	<<Class Action.call method match>>
+	<<Class Action.call method new>>
+	<<Class Action.call method tostring>>
+
+
+<<Class Action.selfcall>>=
+	Action.selfcall = class( Action.generic_call )
+	
+	<<Class Action.selfcall method match>>
+	<<Class Action.selfcall method new>>
+	<<Class Action.selfcall method tostring>>
diff --git a/src/class/argv.nw b/src/class/argv.nw
new file mode 100644
index 0000000..56d2aa8
--- /dev/null
+++ b/src/class/argv.nw
@@ -0,0 +1,11 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+@
+
+<<Class Argv>>=
+	Argv = class()
+	
+	<<Class Argv method equal>>
+	<<Class Argv method new>>
+	<<Class Argv method tostring>>
+	<<Class Argv method unpack>>
diff --git a/src/class/callable.nw b/src/class/callable.nw
new file mode 100644
index 0000000..1fd9506
--- /dev/null
+++ b/src/class/callable.nw
@@ -0,0 +1,13 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+@
+
+<<Class Callable>>=
+	Callable = {}
+	Callable.generic = class()
+	Callable.record  = class( Callable.generic )
+	Callable.replay  = class( Callable.generic )
+	
+	<<Class Callable.generic method new>>
+	<<Class Callable.record call>>
+	<<Class Callable.replay call>>
diff --git a/src/class/controller.nw b/src/class/controller.nw
new file mode 100644
index 0000000..40ed6c3
--- /dev/null
+++ b/src/class/controller.nw
@@ -0,0 +1,30 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+@
+
+<<Class Controller>>=
+	Controller = class()
+	
+	-- Exported methods
+	<<Class Controller method close>>
+	<<Class Controller method depend>>
+	<<Class Controller method error>>
+	<<Class Controller method label>>
+	<<Class Controller method mock>>
+	<<Class Controller method new>>
+	<<Class Controller method replay>>
+	<<Class Controller method returns>>
+	<<Class Controller method times>>
+	<<Class Controller method verify>>
+	
+	-- Protected methods
+	<<Class Controller method actions>>
+	<<Class Controller method add_action>>
+	<<Class Controller method assert_no_dependency_cycles>>
+	<<Class Controller method close_actions>>
+	<<Class Controller method get_last_action>>
+	<<Class Controller method lookup>>
+	<<Class Controller method make_callable>>
+	<<Class Controller method new>>
+	<<Class Controller method replay_action>>
+	<<Class Controller method update_dependencies>>
diff --git a/src/class/mock.nw b/src/class/mock.nw
new file mode 100644
index 0000000..ed10e43
--- /dev/null
+++ b/src/class/mock.nw
@@ -0,0 +1,13 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+@
+
+<<Class Mock>>=
+	<<Class Mock meta tables Mock.record and Mock.replay>>
+	
+	<<Class Mock.record index>>
+	<<Class Mock.record newindex>>
+	<<Class Mock.record selfcall>>
+	<<Class Mock.replay index>>
+	<<Class Mock.replay newindex>>
+	<<Class Mock.replay selfcall>>
diff --git a/src/doc/userguide/chapter_controller.nw b/src/doc/userguide/chapter_controller.nw
new file mode 100644
index 0000000..7c78d98
--- /dev/null
+++ b/src/doc/userguide/chapter_controller.nw
@@ -0,0 +1,23 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+<<Userguide Chapter The Controller>>=
+= The Controller =
+
+The controller's main purpose is to store the recorded actions, create mock
+objects, switch to replay mode, and verify the completion of the replay
+phase. But it is also needed to set or change special action attributes
+during recording.
+
+It is possible, although doubtfully useful, to use several controllers in
+parallel during a single unit test. Each controller maintains its own
+action list and state, and mock objects remember which controller they
+belong to.
+
+<<Userguide Section Returns & Error>>
+<<Userguide Section Label & Depend>>
+<<Userguide Section Times>>
+<<Userguide Section Close>>
+@
diff --git a/src/doc/userguide/chapter_introduction.nw b/src/doc/userguide/chapter_introduction.nw
new file mode 100644
index 0000000..33f3434
--- /dev/null
+++ b/src/doc/userguide/chapter_introduction.nw
@@ -0,0 +1,87 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+<<Userguide Chapter Introduction>>=
+= Introduction =
+<<Userguide Introduction>>
+
+=== Example ===
+
+This example tests that the insert_data function of the foo module handles
+a missing data base table gracefully.
+
+```
+<<Userguide Example simple>>
+```
+
+First a controller is created. Then three mock objects are created, one for
+the sqlite3 module, and two for objects returned by the (simulated) module.
+
+Then a preloader for the sqlite3 module is installed, which returns the
+sqlite3 mock object instead of the actual sqlite3 module.
+
+In the record phase the expected calls and their return values (or thrown
+errors) are recorded. The order is not significant, so this simplified test
+will not detect if the close method is called before the execute method.
+
+In the replay phase the tested module is loaded and executed. It will use
+the mock objects instead of the real data base, and if it makes any
+unrecorded calls, an error is thrown.
+
+The verify phase asserts that all recorded actions have been replayed. If
+the foo module for example forgets to call the close method, verify throws
+an error.
+
+@
+
+<<Userguide Example simple>>=
+-- Setup
+require 'lemock'
+local mc = lemock.controller()
+local sqlite3 = mc:mock()
+local env     = mc:mock()
+local con     = mc:mock()
+package.loaded.luasql = nil
+package.preload['luasql.sqlite3'] = function ()
+    luasql = {}
+    luasql.sqlite3 = sqlite3
+    return sqlite3
+end
+
+-- Record
+sqlite3()                 ;mc :returns(env)
+env:connect('/data/base') ;mc :returns(con)
+con:execute(mc.ANYARGS)   ;mc :error('LuaSQL: no such table')
+con:close()
+env:close()
+
+-- Replay
+mc:replay()
+require 'foo'
+local res = foo.insert_data(17)
+assert(res==false)
+
+--Verify
+mc:verify()
+@
+
+<<Unit test for Userguide Example simple>>=
+	function example_simple_test ()
+		package.loaded.foo = nil
+		package.preload.foo = function ()
+			foo = {}
+			q = require 'luasql.sqlite3'
+			function foo.insert_data()
+				local env = q()
+				local con = env:connect( '/data/base' )
+				local ok, err = pcall( con.execute, con, 'insert foo bar' )
+				con:close()
+				env:close()
+				return ok
+			end
+			return foo
+		end
+		<<Userguide Example simple>>
+	end
diff --git a/src/doc/userguide/chapter_mock.nw b/src/doc/userguide/chapter_mock.nw
new file mode 100644
index 0000000..f16779a
--- /dev/null
+++ b/src/doc/userguide/chapter_mock.nw
@@ -0,0 +1,21 @@
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+<<Userguide Chapter The Mock Object>>=
+= The Mock Object =
+
+Mock objects are empty objects with special Lua meta methods that detect
+actions performed with the object. What happens depends on the state
+(recording or replaying) of the controller which created the mock object.
+During recording the mock object adds the action to the controller's list
+of recorded actions. During replay the mock object looks for a matching
+recorded action that can be replayed, and simulates the action.
+
+Some action attributes can not be inferred by the mock objects, for example
+return values. These attributes have to be added afterwards with special
+controller methods, and always affect the last recorded action.
+
+<<Userguide Section Actions>>
+<<Userguide Section Anyargs>>
+@
diff --git a/src/doc/userguide/chapter_tricks.nw b/src/doc/userguide/chapter_tricks.nw
new file mode 100644
index 0000000..8091270
--- /dev/null
+++ b/src/doc/userguide/chapter_tricks.nw
@@ -0,0 +1,67 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+<<Userguide Chapter Tricks>>=
+= Tricks =
+
+Mock objects are completely empty, and do not contain any methods or
+properties of their own. If they did, that would risk shadowing a name of a
+simulated object's method or property. There is however nothing preventing
+users from defining methods and properties in mock objects. This way mock
+objects can be turned into stubs, or a kind of mock–stub hybrid.
+
+<<Userguide Section Overloading>>
+@
+
+<<Userguide Section Overloading>>=
+== Method Overloading ==
+
+Lua does not support method overloading, but it can be (and sometimes is)
+implemented manually by testing of function arguments. This presents a
+problem to LeMock, because it matches exact arguments, and anyargs in not
+sufficient. In this case the mock object can be extended with a dispatcher
+function.
+
+=== Example ===
+
+This example shows a mock object with an overloaded add function. The stub
+function can not be defined in the usual way, because that would record an
+assignment action; it needs to be defined with //rawset//.
+
+```
+<<Userguide Example overloading>>
+```
+@
+
+<<Userguide Example overloading>>=
+require 'lemock'
+local mc = lemock.controller()
+local m = mc:mock()
+
+do
+local function add (a, b)
+    if type(a) == 'number' then
+        return m.add_number(a, b)
+    else
+        return m.add_string(a, b)
+    end
+end
+rawset( m, 'add', add ) -- not recorded
+end -- do
+
+m.add_number(1, 2)         ;mc :returns(3)
+m.add_string('foo', 'bar') ;mc :returns('foobar')
+
+mc:replay()
+assert_equal( 3, m.add(1, 2) )
+assert_equal( 'foobar', m.add('foo', 'bar') )
+
+mc:verify()
+@
+
+<<Unit test for Userguide Example overloading>>=
+	function overloading_test ()
+		<<Userguide Example overloading>>
+	end
diff --git a/src/doc/userguide/main.nw b/src/doc/userguide/main.nw
new file mode 100644
index 0000000..c65b5d0
--- /dev/null
+++ b/src/doc/userguide/main.nw
@@ -0,0 +1,23 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+<<userguide.t2t>>=
+LeMock User Guide
+v 0.6
+2009-05-30
+
+%!postproc(html): – &ndash;
+%!postproc(tex):  – --
+
+<<Userguide Chapter Introduction>>
+<<Userguide Chapter The Mock Object>>
+<<Userguide Chapter The Controller>>
+<<Userguide Chapter Tricks>>
+@
+
+TODO
+	method reference with syntax
+	errors and their messages
+	limitations & future work
diff --git a/src/doc/userguide/section_actions.nw b/src/doc/userguide/section_actions.nw
new file mode 100644
index 0000000..ec061a9
--- /dev/null
+++ b/src/doc/userguide/section_actions.nw
@@ -0,0 +1,34 @@
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+<<Userguide Section Actions>>=
+== Actions ==
+
+Mock objects detect four types of actions: assignment, indexing, method
+call, and self call. During replay an action will only match if it is the
+very same action, that is, the same type of action performed on the same
+mock object with all the same arguments. There are however
+[special arguments #anyargs] that can be used during recording.
+
+```
+<<Userguide Example actions>>
+```
+@
+
+<<Userguide Example actions>>=
+require 'lemock'
+local mc = lemock.controller()
+local m = mc:mock()
+
+m.x = 17    -- assignment
+r = m.x     -- indexing
+m.x(1,2,3)  -- method call
+m:x(1,2,3)  -- method call
+m(1,2,3)    -- self call
+@
+
+<<Unit test for Userguide Example actions>>=
+	function actions_test ()
+		<<Userguide Example actions>>
+	end
diff --git a/src/doc/userguide/section_anyargs.nw b/src/doc/userguide/section_anyargs.nw
new file mode 100644
index 0000000..c19e2d7
--- /dev/null
+++ b/src/doc/userguide/section_anyargs.nw
@@ -0,0 +1,57 @@
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+<<Userguide Section Anyargs>>=
+== Anyargs ==[anyargs]
+
+<<Userguide Anyargs>>
+
+Anyarg and anyargs are constants defined in the controller object.
+
+=== Example ===
+
+This example tests that the fetch_data function of module foo waits a while
+and retries when no data is immediately available, and that it updates the
+value of lasttime.
+
+```
+<<Userguide Example anyargs>>
+```
+@
+
+<<Userguide Example anyargs>>=
+require 'lemock'
+local mc = lemock.controller()
+local con = mc:mock()
+
+con:poll()           ;mc :returns(nil)
+con:sleep(mc.ANYARG)
+con:poll()           ;mc :returns('123.45')
+con.lasttime = mc.ANYARG
+
+mc:replay()
+require 'foo'
+local res = foo.fetch_data(con)
+assert( math.abs(res-123.45) < 0.0005 )
+
+mc:verify()
+@
+
+<<Unit test for Userguide Example anyargs>>=
+	function example_anyargs_test ()
+		package.loaded.foo = nil
+		package.preload.foo = function ()
+			foo = {}
+			function foo.fetch_data (con)
+				local res = con:poll()
+				while not res do
+					con:sleep( 10 )
+					res = con:poll()
+				end
+				con.lasttime = os.time()
+				return tonumber( res )
+			end
+		end
+		<<Userguide Example anyargs>>
+	end
diff --git a/src/doc/userguide/section_close.nw b/src/doc/userguide/section_close.nw
new file mode 100644
index 0000000..2f2e6a6
--- /dev/null
+++ b/src/doc/userguide/section_close.nw
@@ -0,0 +1,64 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+<<Userguide Section Close>>=
+== Close ==
+
+Close can be used to simulate state changes in a limited way. When an
+action with a close statement is replayed for the first time, it will
+permanently block all labels in its close statement, so that actions with
+these labels no longer replays. This passes on matching to later actions in
+the action list, which may for example have different return values.
+
+The closing simply blocks the labels, and it has nothing to do with max
+replay counts or if closed actions have been satisfied or not. Closing an
+unsatisfied action however results in an immediate failure.
+
+=== Example ===
+
+This example tests that the dump function of module foo calls the myio
+functions in a correct order. The read function can be called any number of
+times, until it is closed by the close function.
+
+```
+<<Userguide Example close>>
+```
+@
+
+<<Userguide Example close>>=
+require 'lemock'
+local mc = lemock.controller()
+local myio = mc:mock()
+local fs   = mc:mock()
+
+myio.open('abc', 'r') ;mc :returns(fs)
+mc :label('open')
+
+fs:read(mc.ANYARG) ;mc :returns('data')
+mc :atleastonce() :label('read') :depend('open')
+
+fs:close() ;mc :returns(true)
+mc :depend('open') :close('read')
+
+mc:replay()
+require 'foo'
+foo.dump(myio, 'abc', 128)
+
+mc:verify()
+@
+
+<<Unit test for Userguide Example close>>=
+	function close_test ()
+		package.loaded.foo = nil
+		package.preload.foo = function ()
+			foo = {}
+			function foo.dump (xio, name, len)
+				local f = xio.open( name, 'r' )
+				f:read( len )
+				f:close()
+			end
+		end
+		<<Userguide Example close>>
+	end
diff --git a/src/doc/userguide/section_label_depend.nw b/src/doc/userguide/section_label_depend.nw
new file mode 100644
index 0000000..fca2581
--- /dev/null
+++ b/src/doc/userguide/section_label_depend.nw
@@ -0,0 +1,69 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+<<Userguide Section Label & Depend>>=
+== Label & Depend ==
+
+Dependencies block actions from replaying until other actions have replayed
+first. They can be used to verify that actions are being replayed in a
+valid order.
+
+To add dependencies, actions must first be labeled with one or more
+//labels//. The same label can be given to several actions. As long as some
+action with the label remains unsatisfied, that label is blocked, and all
+actions depending on that label will not replay.
+
+=== Example ===
+
+This (contrived) example tests that function draw_square in module foo
+calls all the necessary drawing methods of a square object in a correct
+order. Note that there can be more than one correct order.
+
+```
+<<Userguide Example depend>>
+```
+
+This example demonstrates two different ways of using dependencies. All the
+corners have unique labels, because each edge depend on a set of specific
+corners. But all the edges have the same label, because the fill operation
+only depends on //all// edges have been satisfied.
+@
+
+<<Userguide Example depend>>=
+require 'lemock'
+local mc = lemock.controller()
+local square = mc:mock()
+
+square:topleft()   ;mc :label('tl')
+square:topright()  ;mc :label('tr')
+square:botleft()   ;mc :label('bl')
+square:botright()  ;mc :label('br')
+square:leftedge()  ;mc :label('edge') :depend('tl', 'bl')
+square:rightedge() ;mc :label('edge') :depend('tr', 'br')
+square:topedge()   ;mc :label('edge') :depend('tl', 'tr')
+square:botedge()   ;mc :label('edge') :depend('bl', 'br')
+square:fill()      ;mc                :depend('edge')
+
+mc:replay()
+require 'foo'
+foo.draw_square( square )
+
+mc:verify()
+@
+
+<<Unit test for Userguide Example depend>>=
+	function example_depend_test ()
+		package.loaded.foo = nil
+		package.preload.foo = function ()
+			foo = {}
+			function foo.draw_square (sq)
+				sq:botright() sq:topright() sq:rightedge()
+				sq:botleft()  sq:topleft()  sq:leftedge()
+				sq:topedge() sq:botedge()
+				sq:fill()
+			end
+		end
+		<<Userguide Example depend>>
+	end
diff --git a/src/doc/userguide/section_returns_error.nw b/src/doc/userguide/section_returns_error.nw
new file mode 100644
index 0000000..33110b5
--- /dev/null
+++ b/src/doc/userguide/section_returns_error.nw
@@ -0,0 +1,38 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+<<Userguide Section Returns & Error>>=
+== Returns & Error ==
+
+The by far most useful special action attribute is the return value.
+Indexing actions can return a single value, while call actions and self
+call actions can return a list of values. The return value is set with the
+//returns// method, and it is an error to set the return value twice for
+the same action.
+
+For purposes of unit testing it is often useful to simulate errors. All
+actions can raise an error, and return an error value (usually a string).
+The return value is set with the //error// method. An action can not have
+both a return value and raise an error.
+
+=== Example ===
+```
+<<Userguide Example returns & error>>
+```
+@
+
+<<Userguide Example returns & error>>=
+require 'lemock'
+local mc = lemock.controller()
+local m = mc:mock()
+
+m:foo(17)  ;mc :returns(nil, "index out of range")
+m:bar(-1)  ;mc :error("invalid index")
+@
+
+<<Unit test for Userguide Example returns & error>>=
+	function returns_error_test ()
+		<<Userguide Example returns & error>>
+	end
diff --git a/src/doc/userguide/section_times.nw b/src/doc/userguide/section_times.nw
new file mode 100644
index 0000000..a05b31e
--- /dev/null
+++ b/src/doc/userguide/section_times.nw
@@ -0,0 +1,65 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+<<Userguide Section Times>>=
+== Times ==
+
+The default for a recorded action is to be replayed exactly once.
+``times(2)`` changes that to exactly two times, and ``times(1,2)`` changes
+it to at least one time and at most two times.
+
+When the action has been replayed the least count times it is
+//satisfied//, which means verify will not complain about it, and it no
+longer blocks actions that depend on this action from being replayed. If
+the least count is zero the action is automatically satisfied and need not
+be replayed at all, i.e., it is optional.
+
+When the action has been replayed the most count times it will not replay
+any more. The most replay count can be set to infinity (``math.huge`` or
+``1/0``), in which case the action will never stop replaying.
+
+``anytimes()`` can be used as an alias for ``times(0,1/0)``, and
+``atleastonce()`` can be used as an alias for ``times(1,1/0)``.
+
+=== Example ===
+
+This example tests that method update is called at least once.
+
+```
+<<Userguide Example times>>
+```
+@
+
+<<Userguide Example times>>=
+require 'lemock'
+local mc = lemock.controller()
+local con = mc:mock()
+
+con:log(mc.ANYARGS) ;mc                :anytimes()
+con:update('x',3)   ;mc :returns(true) :atleastonce()
+
+mc:replay()
+require 'foo'
+local watcher = foo.mk_watcher( con )
+watcher:set( 'x', 3 )
+
+mc:verify()
+@
+
+<<Unit test for Userguide Example times>>=
+	function example_times_test ()
+		package.loaded.foo = nil
+		package.preload.foo = function ()
+			foo = {}
+			function foo.mk_watcher ( con )
+				local o = {}
+				function o:set ( key, val )
+					con:update( key, val )
+				end
+				return o
+			end
+		end
+		<<Userguide Example times>>
+	end
diff --git a/src/doc/userguide/unittests.nw b/src/doc/userguide/unittests.nw
new file mode 100644
index 0000000..ab89925
--- /dev/null
+++ b/src/doc/userguide/unittests.nw
@@ -0,0 +1,19 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+<<unit/userguide.lua>>=
+	<<Lua file blurb>>
+	
+	require 'lunit'
+	module( 'unit.userguide', lunit.testcase, package.seeall )
+	
+	<<Unit test for Userguide Example actions>>
+	<<Unit test for Userguide Example anyargs>>
+	<<Unit test for Userguide Example close>>
+	<<Unit test for Userguide Example depend>>
+	<<Unit test for Userguide Example overloading>>
+	<<Unit test for Userguide Example returns & error>>
+	<<Unit test for Userguide Example simple>>
+	<<Unit test for Userguide Example times>>
diff --git a/src/doc/webpages.nw b/src/doc/webpages.nw
new file mode 100644
index 0000000..59aa292
--- /dev/null
+++ b/src/doc/webpages.nw
@@ -0,0 +1,297 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+The sources for the web pages are written as independent t2t documents. To
+form a cohesive web "site", the pages are included in special wrapper t2t
+documents, which use a different set of configurations, and add a header, a
+navigation menu bar, and a footer. The wrappers are tangled into the www
+directory, the userguide is tangled into the build directory, and the other
+sources are unique files in the distribution root directory.
+
+<<mkfile>>=
+MKSHELL = rc
+
+all:V: htdocs
+
+wrappers  = `{find www -name '*.t2t'}
+htmls = ${wrappers:www/%.t2t=htdocs/%.html}
+
+htdocs:V: $htmls
+
+$htmls: www/menubar.html
+htdocs/COPYRIGHT.html: ../COPYRIGHT
+htdocs/DEVEL.html:     ../DEVEL
+htdocs/HISTORY.html:   ../HISTORY
+htdocs/README.html:    ../README
+
+htdocs/%.html: www/%.t2t
+	txt2tags -t html -i www/$stem.t2t -o $target
+
+htdocs/userguide.html: www/userguide.t2t userguide.t2t
+	txt2tags -t html --toc --toc-level 2 -i www/userguide.t2t -o $target
+@
+
+== Wrappers ==
+
+The wrappers assume the source is tangled in a subdirectory, so ../../ is
+the path to the root.
+
+The ID of each page is changed to something unique, so the navigation menu
+can identify them.
+
+<<www/README.t2t>>=
+<<Webpage head>>
+%!postproc(html): 'ID="body"' 'ID="page-README"'
+<<Webpage main menu>>
+= Readme =
+%!include: ../../README
+<<Webpage foot>>
+@
+
+(No footer on copyright page!)
+
+<<www/COPYRIGHT.t2t>>=
+<<Webpage head>>
+%!postproc(html): 'ID="body"' 'ID="page-COPYRIGHT"'
+<<Webpage main menu>>
+= License =
+%!include: ../../COPYRIGHT
+@
+
+<<www/HISTORY.t2t>>=
+<<Webpage head>>
+%!postproc(html): 'ID="body"' 'ID="page-HISTORY"'
+<<Webpage main menu>>
+= History =
+%!include: ../../HISTORY
+<<Webpage foot>>
+@
+
+<<www/DEVEL.t2t>>=
+<<Webpage head>>
+%!postproc(html): 'ID="body"' 'ID="page-DEVEL"'
+<<Webpage main menu>>
+= Developer Notes =
+%!include: ../../DEVEL
+<<Webpage foot>>
+@
+
+(The user guide is tangled into the build directory.)
+
+<<www/userguide.t2t>>=
+<<Webpage head>>
+%!postproc(html): 'ID="body"' 'ID="page-userguide"'
+<<Webpage main menu>>
+%%toc
+%!include: ../userguide.t2t
+<<Webpage foot>>
+@
+
+The index file is just an empty file with the navigation menu. This is
+stupid. FIXME!
+
+<<www/index.t2t>>=
+<<Webpage head>>
+%!postproc(html): 'ID="body"' 'ID="page-index"'
+<<Webpage main menu>>
+@
+
+== Header and Footer ==
+
+The header contains the page's title (all pages get the same title), and
+sets up the configuration. The footer just contains the date for when the
+page was generated.
+
+<<Webpage head>>=
+LeMock
+
+
+%!includeconf: config.rc
+<<Doc reference preprocs>>
+@
+
+<<Webpage foot>>=
+--------------------
+%%Date(%Y-%m-%d)
+@
+
+Use css for layout and navigation menu.
+
+<<www/config.rc>>=
+%!options: --no-rc
+%!style(html): style.css
+%!options(html): --css-sugar 
+@
+
+<<htdocs/style.css>>=
+<<Webpage css>>
+<<Webpage css menu>>
+@
+
+Some t2t pages are written with the intent that they should work as plain
+text documents, and so they refer to other files by name. In the web pages
+real links are preferred, but the words README and DEVEL are too common, so
+a special trick with a trailing underscore is used.
+
+<<Doc reference preprocs>>=
+%!preproc: COPYRIGHT_ "[COPYRIGHT COPYRIGHT.html]"
+%!preproc: DEVEL_     "[DEVEL DEVEL.html]"
+%!preproc: "build/htdocs/userguide.html" "[the user guide userguide.html]"
+@
+
+== Style Sheet ===
+
+<<Webpage css>>=
+	<<Webpage css page>>
+	<<Webpage css title>>
+	<<Webpage css code>>
+	<<Webpage css toc>>
+	<<Webpage css history>>
+
+<<Webpage css page>>=
+	body {
+		color:            #181818;
+		background-color: #E0E4F0;
+		font:             normal 10pt sans-serif;
+		max-width:        30em;
+		margin:           25pt;
+	}
+	.body h1 {
+		margin:           2em 0em 0em 0em;
+		font-size:        14pt;
+	}
+	.body h2 {
+		margin:           1.5em 0em 0em 0em;
+		font-size:        12pt;
+	}
+	.body h3 {
+		margin:           1em 0em 0em 0em;
+		font-size:        10pt;
+	}
+	.body p, .body ul, .body ol {
+		margin-top:       0.5em;
+	}
+	.body li {
+		margin-top:       0.5em;
+	}
+	a {
+		text-decoration:  none;
+	}
+	hr {
+		margin-top:       3em;
+	}
+
+<<Webpage css title>>=
+	.header h1 {
+		text-align:       center;
+		padding:          0.3em;
+		border:           1pt solid black;
+	}
+
+<<Webpage css code>>=
+	code, pre {
+		font-family:      fixed;
+		font-style:       normal;
+		font-size:        9pt;
+		line-height:      9pt;
+		background-color: #E8ECF8;
+	}
+	pre {
+		padding:          2pt;
+	}
+
+<<Webpage css toc>>=
+	div.toc {
+		margin-top:       3em;
+		line-height:      6pt;
+	}
+	.toc ul {
+		padding-left:     1.6em;
+		margin:           0em;
+		line-height:      10pt;
+	}
+	.toc li {
+		margin:           0em;
+		padding:          0em;
+		list-style-type:  none;
+	}
+	.toc a {
+		color:            #091;
+	}
+
+<<Webpage css history>>=
+	#page-HISTORY DL DT {
+		font-weight:      bold;
+		margin-top:       2em;
+	}
+	#page-HISTORY DL DD UL {
+		margin-top:       0pt;
+		padding-left:     0pt;
+	}
+@
+
+== Navigation Menu Bar ==
+
+The navigation menu bar is implemented with css.
+
+<<Webpage main menu>>=
+%!include(html): ''menubar.html''
+@
+
+<<www/menubar.html>>=
+<ul id="main_menu">
+  <li id="main_menu-README"><a    href="README.html"   >Readme</a></li>
+  <li id="main_menu-COPYRIGHT"><a href="COPYRIGHT.html">License</a></li>
+  <li id="main_menu-userguide"><a href="userguide.html">Userguide</a></li>
+  <li id="main_menu-HISTORY"><a   href="HISTORY.html"  >History</a></li>
+  <li id="main_menu-DEVEL"><a     href="DEVEL.html"    >Devel</a></li>
+</ul>
+@
+
+<<Webpage css menu>>=
+	#main_menu {
+		margin:  0;
+		padding: 0;
+	}
+	#main_menu li {
+		margin:  0;
+		padding: 0;
+		display: inline;
+	}
+	#main_menu a {
+		padding:    3px 3px 2px 4px;
+		text-decoration:none;
+		font:bold 8pt/8pt Arial, Helvetica, sans-serif;
+		border:       1px solid #000;
+	}
+	#main_menu a:link,
+	#main_menu a:visited {
+		color:      #fff;
+		background: #777;
+	}
+	#main_menu a:hover {
+		color:      #000;
+		background: #777;
+	}
+	#page-README    #main_menu-README    a,
+	#page-COPYRIGHT #main_menu-COPYRIGHT a,
+	#page-userguide #main_menu-userguide a,
+	#page-HISTORY   #main_menu-HISTORY   a,
+	#page-DEVEL     #main_menu-DEVEL     a {
+		color:      #000;
+		background: #aaa;
+	}
+	#page-README    #main_menu-README    a:hover,
+	#page-COPYRIGHT #main_menu-COPYRIGHT a:hover,
+	#page-userguide #main_menu-userguide a:hover,
+	#page-HISTORY   #main_menu-HISTORY   a:hover,
+	#page-DEVEL     #main_menu-DEVEL     a:hover {
+		color:      #000;
+		background: #aaa;
+	}
+	#nav a:active {
+		color:      #000;
+		background: #aaa;
+	}
diff --git a/src/files.nw b/src/files.nw
new file mode 100644
index 0000000..c26aa6d
--- /dev/null
+++ b/src/files.nw
@@ -0,0 +1,32 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+<<lemock.lua>>=
+	<<Lua file blurb>>
+	
+	module( 'lemock', package.seeall )
+	_VERSION   = "LeMock 0.6"
+	_COPYRIGHT = "Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>"
+	
+	local class, object, qtostring, sfmt, add_to_set
+	local elements_of_set, value_equal
+	<<Helper function class and object>>
+	<<Helper function qtostring and sfmt>>
+	<<Helper function add_to_set and elements_of_set>>
+	<<Helper function value_equal>>
+	
+	<<Module mock private data mock_controller_map>>
+	
+	-- All the classes are private
+	local Action, Argv, Callable, Controller, Mock
+	<<Class Action>>
+	<<Class Argv>>
+	<<Class Callable>>
+	<<Class Controller>>
+	<<Class Mock>>
+	
+	<<Module mock function controller>>
+	
+	return _M
diff --git a/src/helperfunctions.nw b/src/helperfunctions.nw
new file mode 100644
index 0000000..cbb9616
--- /dev/null
+++ b/src/helperfunctions.nw
@@ -0,0 +1,65 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+class and object
+----------------
+
+These functions are mostly to enhance the reading of the code.
+
+<<Helper function class and object>>=
+	function object (class)
+		return setmetatable( {}, class )
+	end
+	function class (parent)
+		local c = object(parent)
+		c.__index = c
+		return c
+	end
+@
+
+value_equal
+-----------
+
+NaN is always numerically not-equal everything, but for arguments and
+return values we want a symbolic comparison.
+
+<<Helper function value_equal>>=
+	function value_equal (a, b)
+		if a == b then return true end
+		if a ~= a and b ~= b then return true end -- NaN == NaN
+		return false
+	end
+@
+
+Sets
+----
+
+Sets are used in Actions to store labels and dependencies, which are
+usually very short, and often not used at all, so it is worth some extra
+trouble to optimize for size.
+
+The implementation uses arrays, and no array (nil) can represent the empty
+set.
+
+<<Helper function add_to_set and elements_of_set>>=
+	function add_to_set (o, setname, element)
+		if not o[setname] then
+			o[setname] = {}
+		end
+		local l = o[setname]
+		
+		for i = 1, #l do
+			if l[i] == element then return end
+		end
+		l[#l+1] = element
+	end
+	function elements_of_set (o, setname)
+		local l = o[setname]
+		local i = l and #l+1 or 0
+		return function ()
+			i = i - 1
+			if i > 0 then return l[i] end
+		end
+	end
diff --git a/src/main.nw b/src/main.nw
new file mode 100644
index 0000000..5fb454b
--- /dev/null
+++ b/src/main.nw
@@ -0,0 +1,761 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+Introduction
+############
+
+<<Userguide Introduction>>=
+
+Mock objects replace difficult external objects during unit testing by
+simulating the behaviors of the replaced objects. This is done by first
+recording actions and their responses with the mock objects, and then
+switching to replay mode. During replay mode the mock objects simulate the
+replaced objects by looking up actions and replaying the recorded
+responses, and finally verifying that all expected actions where completely
+replayed.
+
+Actions are stored in a list in a special controller object. During replay
+the list is searched in recording order for the first matching action that
+can be replayed.
+
+Restrictions on the actions can be inserted during the recording phase. An
+action can have a maximum count of how many times it will be replayed, and
+a minimum count of how many times it must be replayed to be satisfied. An
+action can depend on any set of other actions, and can not be replayed
+before all of its depended actions are satisfied. An action can close any
+set of actions when it is replayed, which stops all further replaying of
+the closed actions. This is good for simulating state changes.
+@
+
+Manage Actions
+##############
+
+The Action List
+===============
+
+Actions are stored in a list in a special Controller object. To keep it
+simple, the list is a simple array table. The controller has an
+[[add_action]] method, and a [[lookup]] method. Actions are added at the
+end, and looked up from the beginning.
+
+
+add_action
+----------
+
+<<Unit test for class Controller method add_action>>=
+	function add_action_at_the_end_test ()
+		mc:add_action( 7 )
+		mc:add_action( mc )
+		assert_equal( 7, mc.actionlist[1] )
+		assert_equal( mc, mc.actionlist[2] )
+	end
+
+<<Class Controller method add_action>>=
+	function Controller:add_action (a)
+		assert( a ~= nil, "lemock internal error" ) -- breaks array property
+		table.insert( self.actionlist, a )
+	end
+@
+
+lookup and actions
+------------------
+
+It should be easy to add new action types, so the [[lookup]] method
+delegates matching to the [[match]] method of the Action objects in the
+list. If there is no match an error is thrown with a list of all actions
+that could have been matched.
+
+<<Unit test for class Controller method lookup>>=
+	function lookup_returns_first_matching_action_test ()
+		local Fake_action
+		<<Simple Fake_action class>>
+		local a1 = Fake_action:new(1)
+		local a2 = Fake_action:new(2)
+		local a3 = Fake_action:new(1)
+		local ok, err = pcall( function() mc:lookup( a1 ) end )
+		assert_false( ok, "match in empty list" )
+		assert_match( "Unexpected action <faked action>", err )
+		mc:add_action( a1 ) mc:add_action( a2 ) mc:add_action( a3 )
+		local ok, err = pcall( function() mc:lookup( a1 ) end )
+		assert_false( ok, "should not match any action" )
+		assert_match( "Unexpected action <faked action>", err )
+		assert_equal( a1, mc:lookup( a2 ), "did not find first match" )
+	end
+
+<<Class Controller method lookup>>=
+	function Controller:lookup (actual)
+		for action in self:actions() do
+			if action:match( actual ) then
+				return action
+			end
+		end
+		<<Find all expected actions>>
+		error( sfmt( "Unexpected action %s, expected:\n%s\n"
+		             , actual:tostring()
+		             , table.concat(expected,'\n')
+		       )
+		       , 0
+		)
+	end
+@
+There is no point in listing index actions for callables, since they will
+just mirror the call actions.
+
+Sorting the list will make it easier for the user to conclude that an
+expected action is "missing", because there will be a definite place in the
+list where the action would have been.
+
+<<Find all expected actions>>=
+	local expected = {}
+	for _, a in ipairs( self.actionlist ) do
+		if a:is_expected() and not a.is_callable then
+			expected[#expected+1] = a:tostring()
+		end
+	end
+	table.sort( expected )
+	if #expected == 0 then
+		expected[1] = "(Nothing)"
+	end
+@
+Many functions iterate over all the actions in the action list.
+
+<<Unit test for class Controller method actions>>=
+	function actions_dont_iterate_empty_list_test ()
+		for a in mc:actions() do
+			fail( "iterates on empty list" )
+		end
+	end
+	function actions_iterate_over_entire_list_exactly_once_test ()
+		local l = { {},{},{} }
+		for _, a in ipairs( l ) do
+			mc:add_action( a )
+		end
+		for a in mc:actions() do
+			assert_nil( a.check )
+			a.check = true
+		end
+		for _, a in ipairs( l ) do
+			assert_true( a.check )
+		end
+	end
+
+<<Class Controller method actions>>=
+	function Controller:actions (q)
+		local l = self.actionlist
+		local i = 0
+		return function ()
+			i = i + 1
+			return l[i]
+		end				
+	end
+@
+
+The Controller object will allow the user to set return values or
+restrictions on the last recorded action.
+
+last
+----
+
+<<Unit test for class Controller method get_last_action>>=
+	function get_last_action_returns_last_element_test ()
+		local l = { 'a', 'foo', 17 }
+		for i = 1, #l do
+			mc:add_action( l[i] )
+			local res = mc:get_last_action()
+			assert_equal( l[i], res )
+		end
+	end
+	function get_last_action_fails_on_empty_list_test ()
+		local ok, err = pcall( function() mc:get_last_action() end )
+		assert_false( ok, "Found last action in empty list" )
+		assert_match( "No action is recorded yet", err )
+	end
+
+<<Class Controller method get_last_action>>=
+	function Controller:get_last_action ()
+		local l = self.actionlist
+		if #l == 0 then
+			error( "No action is recorded yet.", 0 )
+		end
+		return l[#l]
+	end
+@
+
+Actions
+=======
+
+Each Action type is implemented as a specialized class so it is easy to add
+new action types. The action class is responsible for storing information
+and state. The Mock class and Callable class are responsible for catching
+and recording/replaying the action with help from the information in the
+Action object.
+
+Action types differ in what information they need to store, and therefore
+how they are constructed, matched by lookup, and printed as strings. The
+concrete or extended implementations of the methods [[new]], [[match]], and
+[[tostring]], are therefore implemented together with the corresponding
+Mock and Callable meta methods responsible for catching the action,
+arranged in separate source files in the action/ directory.
+
+
+New
+---
+
+New Action objects are created with default [[min_replays]] and
+[[max_replays]] equal to one, which means each recorded action is expected
+to be replayed exactly once. This method will be extended by the the
+concrete Action class types.
+
+<<Unit test for class Action.generic method new>>=
+	function new_action_has_right_default_values_test ()
+		assert_equal( 0, a.replay_count )
+		assert_equal( 1, a.min_replays )
+		assert_equal( 1, a.max_replays )
+	end
+
+<<Class Action.generic method new>>=
+	function Action.generic:new (mock)
+		local a = object( self )
+		a.mock         = mock
+		a.replay_count = 0
+		a.min_replays  = 1
+		a.max_replays  = 1
+		return a
+	end
+@
+
+match and is_expected
+---------------------
+
+The [[match]] method takes an Action object as key for the search, because
+it is a convenient way to pass all the needed properties. The Action
+objects in the action list should compare themselves with the key to see if
+they can replay such an action. The state properties of the key object are
+of course not used, but the state of the actions in the list is important
+for if the actions can be replayed or not. The method [[is_expected]]
+examines if the state allows the action to be replayed. The [[match]]
+method will be extended by the concrete Action class types.
+
+<<Unit test for class Action.generic method is_expected>>=
+	function expect_unreplayed_action_test ()
+		assert_true( a:is_expected() )
+	end
+
+<<Class Action.generic method is_expected>>=
+	function Action.generic:is_expected ()
+		return self.replay_count < self.max_replays
+		   and not self.is_blocked
+		   and not self.is_closed
+	end
+
+<<Unit test for class Action.generic method match>>=
+	function match_unreplayed_test ()
+		assert_true( a:match( a ))
+	end
+	function match_rejects_replayed_action_test ()
+		a.replay_count = 1
+		assert_false( a:match( a ))
+	end
+	function match_rejects_wrong_action_type_test ()
+		-- Fake different type
+		local B = class( A )
+		local b = B:new()
+		assert_false( a:match( b ))
+	end
+
+<<Class Action.generic method match>>=
+	function Action.generic:match (key)
+		if getmetatable(self) ~= getmetatable(key)  then return false end
+		if self.mock ~= key.mock                    then return false end
+		return self:is_expected()
+	end
+@
+
+replay_action
+-------------
+
+The [[replay]] method updates the state of an Action. It has nothing to do
+with performing the action, which is done by the Mock class and Callable
+class. It is an internal error to call this method with an action that is
+not expected.
+
+<<Unit test for class Controller method replay_action>>=
+	function replay_action_test ()
+		local a = A:new()
+		mc:add_action( a )
+		assert_true( a:is_expected() )
+		assert_false( a:is_satisfied() )
+		mc:replay_action( a )
+		assert_false( a:is_expected() )
+		assert_true( a:is_satisfied() )
+		assert_equal( 1, a.replay_count )
+	end
+
+<<Class Controller method replay_action>>=
+	function Controller:replay_action ( action )
+		assert( action:is_expected(), "lemock internal error" )
+		assert( action.replay_count < action.max_replays, "lemock internal error" )
+		local was_satisfied = action:is_satisfied()
+		action.replay_count = action.replay_count + 1
+		if not was_satisfied and action.labellist and action:is_satisfied() then
+			self:update_dependencies()
+		end
+		if action.closelist then
+			self:close_actions( action:closes() )
+		end
+	end
+@
+
+is_satisfied and assert_satisfied
+---------------------------------
+
+When the replay phase is finished the Controller needs to verify that all
+the actions in the action list have been satisfied. If some action is not
+satisfied it is an error, so [[assert_satisfied]] must also throw an
+appropriate error.
+
+<<Unit test for class Action.generic method is_satisfied>>=
+	function unreplayed_action_is_not_satisfied_test ()
+		assert_false( a:is_satisfied() )
+	end
+	function assert_satisfied_unreplayed_action_fails_test ()
+		local ok, err = pcall( function() a:assert_satisfied() end )
+		assert_false( ok, "unreplayed action was satisfied" )
+		assert_match( "Wrong replay count 0", err )
+	end
+
+<<satisfied expression>>=
+	self.min_replays <= self.replay_count
+
+<<Class Action.generic method is_satisfied>>=
+	function Action.generic:is_satisfied ()
+		return <<satisfied expression>>
+	end
+
+<<Class Action.generic method assert_satisfied>>=
+	function Action.generic:assert_satisfied ()
+		assert( self.replay_count <= self.max_replays, "lemock internal error" )
+		if not (<<satisfied expression>>) then
+			error( sfmt( "Wrong replay count %d (expected %d..%d) for %s"
+			             , self.replay_count
+			             , self.min_replays, self.max_replays
+			             , self:tostring()
+			       )
+			       , 0
+			)
+		end
+	end
+@
+
+Catching and Simulating Actions
+###############################
+
+Three classes work in tight connection to catch, record, and replay
+actions. They are [[Controller]], [[Mock]], and [[Callable]].
+
+The Controller is the main class, and it stores the action list with all
+the Actions. The Controller is used to record explicit information that can
+not be caught in an automatic manner by the Mock or Callable objects, such
+as retur values. It is used to record meta information such as replay
+limits and replay order dependencies. It is used to create the Mock
+objects, to switch to replay mode, and to verify the completeness of the
+replay phase.
+
+The Mock must be completely empty of methods and properties, because we
+want to catch all of them, without accidentally shadowing any names. So it
+can only use Lua meta methods, like [[__index]] and [[__newindex]]. Because
+of this limitation it is not possible to store a reference to the
+Controller in the Mock object, so we need a map for this.
+
+<<Module mock private data mock_controller_map>>=
+	local mock_controller_map = setmetatable( {}, {__mode='k'} )
+@
+When a method of a Mock object is called there are actually two actions.
+First the method's name is indexed, and then the returned object is called.
+So the Mock [[__index]] meta method must record the index part, *and* return
+something with a [[__call]] meta method that can record the call part. This
+something is a [[Callable]] object.
+
+
+Setup Phase
+===========
+
+The Controller
+--------------
+
+To keep the user interface clean the Controller class itself is never
+exported. The module function [[controller]] creates a new local controller
+object, and creates and returns a wrapper for it with the exported methods.
+
+<<Module mock function controller>>=
+	function controller ()
+		local exported_methods = {
+			'anytimes',
+			'atleastonce',
+			'close',
+			'depend',
+			'error',
+			'label',
+			'mock',
+			'new',
+			'replay',
+			'returns',
+			'times',
+			'verify',
+		}
+		local mc = Controller:new()
+		local wrapper = {}
+		for _, method in ipairs( exported_methods ) do
+			wrapper[ method ] = function (self, ...)
+				return mc[ method ]( mc, ... )
+			end
+		end
+		wrapper.ANYARG  = Argv.ANYARG
+		wrapper.ANYARGS = Argv.ANYARGS
+		return wrapper
+	end
+
+<<Class Controller method new>>=
+	function Controller:new ()
+		local mc = object( self )
+		mc.actionlist   = {}
+		mc.is_recording = true
+		return mc
+	end
+@
+
+The Mock
+--------
+
+The Mock class has two modes, one for recording and one for replaying.
+These two modes are implemented as two different metatables. The [[class]
+helper functions is not used to create them, because it sets [[__index]] to
+be a self reference. The [[__index]] meta method, and other meta methods,
+of the two Mock metatables are used for catching actions, and are defined
+in the corresponding action source files.
+
+<<Class Mock meta tables Mock.record and Mock.replay>>=
+	Mock = { record={}, replay={} } -- no self-referencing __index!
+@
+Because the Mock must be completely empty it can not have a [[new]] method.
+So the Controller has a [[mock]] method that creates and returns new mock
+objects, and maps them to itself in [[mock_controller_map]]. The Mock is
+created in record mode, but will be switched to replay mode later by the
+Controller.
+
+<<Unit test for module mock; mock creation>>=
+	function create_completely_empty_mock_test ()
+		for k, v in pairs( m ) do
+			fail( "Mock should be empty but contains "..tostring(k) )
+		end
+	end
+	function create_mock_during_replay_fails_test ()
+		mc:replay()
+		local ok, err = pcall( function() mc:mock() end )
+		assert_false( ok, "mock() succeeded" )
+		assert_match( "New mock during replay.", err )
+	end
+
+<<Class Controller method mock>>=
+	function Controller:mock ()
+		if not self.is_recording then
+			error( "New mock during replay.", 2 )
+		end
+		local m = object( Mock.record )
+		mock_controller_map[m] = self
+		return m
+	end
+@
+
+The Callable
+------------
+
+A Callable is only created as the result of an index action. It is not
+known at the time of the index action if the index will be called, but if
+it is, the call action must update the index action with this information,
+and therefore needs a reference to it.
+
+<<Class Callable.generic method new>>=
+	function Callable.generic:new ( index_action )
+		local f = object( self )
+		f.action = index_action
+		return f
+	end
+@
+
+Record Phase
+============
+
+Return Values and Callables
+---------------------------
+
+Index action can either have a return value or be callable, in which case
+they return a Callable object. When the call action is recorded the
+corresponding index action must be marked as [[is_callable]], so that it
+knows it shall return a Callable object during replay mode.
+
+Index actions that return callables have their replay count limits set to
+any-times, because all control adjustments will be made to the call action,
+and it should not matter how many times the callable is retrieved from the
+mock, but only how many times and in what order it is called.
+
+If the retrieval count and/or order is important it is still possible to
+simulate such behavior with an index action returning a mock object. Then
+the index action can be controlled, and the call action can instead be
+recorded with the selfcall action of the returned mock object.
+
+<<Unit test for module mock; make callable>>=
+	function returns_on_empty_list_fails_test ()
+		local ok, err = pcall( function() mc:returns(nil) end )
+		assert_false( ok, "returns called on nothing" )
+		assert_match( "No action is recorded yet.", err )
+	end
+	function returns_make_call_fail_test ()
+		local tmp = m.foo ;mc:returns(1)
+		local ok, err = pcall( function() tmp(2) end )
+		assert_false( ok, "called index with returnvalue" )
+		assert_match( "Can not call foo. It has a returnvalue.", err )
+	end
+	function callable_index_replays_anytimes_test ()
+		local tmp = m.foo()
+		mc:replay()
+		tmp = m.foo
+		tmp = m.foo
+		tmp = m.foo()
+		mc:verify()
+	end
+
+<<Class Controller method make_callable>>=
+	function Controller:make_callable (action)
+		if action.has_returnvalue then
+			error( "Can not call "..action.key..". It has a returnvalue.", 0 )
+		end
+		action.is_callable = true
+		action.min_replays = 0
+		action.max_replays = math.huge
+	end
+@
+Action classes that can return a value have the [[can_return]] property
+set, and they implement the [[set_returnvalue]] and [[get_returnvalue]]
+methods.
+
+If an index action is marked as [[is_callable]] it ought to be followed by
+a call action responsible for making it callable, and since it is no longer
+the last action it should be impossible to set a returnvalue for the index
+action. Doing so is an internal error.
+
+<<Unit test for module mock returnvalue>>=
+	function returns_during_replay_fails_test ()
+		local tmp = m.foo
+		mc:replay()
+		local ok, err = pcall( function() mc:returns(1) end )
+		assert_false( ok, "returns() succeeded during replay" )
+		assert_match( "Returns called during replay.", err )
+	end
+	function returns_on_nonreturning_action_fails_test ()
+		m.foo = 1 -- assignments can't return
+		local ok, err = pcall( function() mc:returns(0) end )
+		assert_false( ok, "returns() succeeded on non-returning action" )
+		assert_match( "Previous action can not return anything.", err )
+	end
+	function returns_twice_fails_test ()
+		local tmp = m.foo ;mc:returns(1)
+		local ok, err = pcall( function() mc:returns(2) end )
+		assert_false( ok, "duplicate returns() succeeded" )
+		assert_match( "Returns and/or Error called twice for same action.", err )
+	end
+
+<<Class Controller method returns>>=
+	function Controller:returns (...)
+		if not self.is_recording then
+			error( "Returns called during replay.", 2 )
+		end
+		local action = self:get_last_action()
+		assert( not action.is_callable, "lemock internal error" )
+		if not action.can_return then
+			error( "Previous action can not return anything.", 2 )
+		end
+		if action.has_returnvalue or action.throws_error then
+			error( "Returns and/or Error called twice for same action.", 2 )
+		end
+		action:set_returnvalue(...)
+		return self -- for chaining
+	end
+@
+
+Throwing Errors
+---------------
+
+Any action can be made to throw a recorded error when replayed. For
+example, a newindex action could simulate an assignment to a userdata och
+table with a metatable that is supposed to throw an error on assignments.
+
+<<Unit test for module mock error>>=
+	function error_during_replay_fails_test ()
+		local tmp = m.foo
+		mc:replay()
+		local ok, err = pcall( function() mc:error(1) end )
+		assert_false( ok, "error() succeeded during replay" )
+		assert_match( "Error called during replay.", err )
+	end
+	function error_twice_fails_test ()
+		local tmp = m.foo ;mc:error(1)
+		local ok, err = pcall( function() mc:error(2) end )
+		assert_false( ok, "duplicate error() succeeded" )
+		assert_match( "Returns and/or Error called twice for same action.", err )
+	end
+	function error_plus_returns_fails_test ()
+		local tmp = m.foo ;mc:returns(1)
+		local ok, err = pcall( function() mc:error(2) end )
+		assert_false( ok, "both error and returns succeeded" )
+		assert_match( "Returns and/or Error called twice for same action.", err )
+	end
+
+<<Class Controller method error>>=
+	function Controller:error (value)
+		if not self.is_recording then
+			error( "Error called during replay.", 2 )
+		end
+		local action = self:get_last_action()
+		if action.has_returnvalue or action.throws_error then
+			error( "Returns and/or Error called twice for same action.", 2 )
+		end
+		action.throws_error = true
+		action.errorvalue = value
+		return self -- for chaining
+	end
+@
+
+Switching from Record Mode to Replay Mode
+=========================================
+
+Switching to replay mode is done by changing all Mock objects' matatables.
+It is an error to call [[replay]] twice on the same Controller.
+
+Dependency information (see restrictions.nw) is not calculated in real
+time. It is updated when needed, for example before starting the replay
+phase. This is also a good point to check for dependency cycles.
+
+<<Unit test for module mock; switching to replay mode>>=
+	function replay_twice_fails_test ()
+		mc:replay()
+		local ok, err = pcall( function() mc:replay() end )
+		assert_false( ok, "replay succeeded twice" )
+		assert_match( "Replay called twice.", err )
+	end
+	function multiple_controllers_test ()
+		local mc2 = lemock.controller()
+		local m2  = mc2:mock()
+		
+		-- m --         -- m2 --
+		m.foo = 1
+		mc:replay()
+						m2.bar = 2
+		m.foo = 1
+						mc2:replay()
+		mc:verify()
+						m2.bar = 2
+						mc2:verify()
+	end
+
+<<Unit test for class Controller method replay>>=
+	function replay_test ()
+		assert_true( mc.is_recording )
+		mc:replay()
+		assert_false( mc.is_recording )
+	end
+
+<<Class Controller method replay>>=
+	function Controller:replay ()
+		if not self.is_recording then
+			error( "Replay called twice.", 2 )
+		end
+		self.is_recording = false
+		for m, mc in pairs( mock_controller_map ) do
+			if mc == self then
+				setmetatable( m, Mock.replay )
+			end
+		end
+		self:update_dependencies()
+		self:assert_no_dependency_cycles()
+	end
+@
+
+Replay Phase
+============
+
+The key point with the replay phase is that unexpected actions should fail.
+
+<<Unit test for module mock; replay>>=
+	function replay_in_any_order_test ()
+		m.a = 1
+		m.b = 2
+		m.c = 3
+		mc:replay()
+		m.c = 3
+		m.a = 1
+		m.b = 2
+		mc:verify()
+	end
+	function replaying_unexpected_action_fails_test ()
+		mc:replay()
+		local ok, err = pcall( function() m:somethingelse() end )
+		assert_false( ok, "unexpected replay succeeded" )
+		assert_match( "Unexpected action index somethingelse", err )
+	end
+@
+There is an error that would be very hard to track down if it is not
+detected. During record mode the Mock returns recording Callables, but
+during replay mode it returns replaying Callables. If the client caches a
+Callable in record mode and uses it during replay mode, it would not fail
+straight away as desired (if undetected), but record a false action which
+would mess up the action list and cause some later action or the final
+verify to pass or fail with a perplexing error message.
+
+<<Unit test for module mock; replay>>=
+	function cached_recording_callable_fails_during_replay_test ()
+		local tmp = m.foo ; tmp()
+		mc:replay()
+		local ok, err = pcall( function() tmp() end )
+		assert_false( ok, "Cached callable not detected" )
+		assert_match( "client uses cached callable from recording", err )
+	end
+@
+
+Verify Completeness Phase
+=========================
+
+Unknown or misplaced actions can be detected during the replay phase, but
+expected actions that are not replayed can not be detected until the replay
+phase is finished. That is why the verify phase is needed, and it simply
+asserts that all recorded actions have been satisfied.
+
+<<Unit test for module mock; verify>>=
+	function verify_during_record_phase_fails_test ()
+		local ok, err = pcall( function() mc:verify() end )
+		assert_false( ok, "Verify succeeded" )
+		assert_match( "Verify called during record.", err )
+	end
+	function verify_replayed_actionlist_test ()
+		mc:replay()
+		mc:verify()
+	end
+	function verify_unreplyed_actionlist_fails_test ()
+		local tmp = m.foo
+		mc:replay()
+		local ok, err = pcall( function() mc:verify() end )
+		assert_false( ok, "Verify succeeded" )
+		assert_match( "Wrong replay count 0 ", err )
+	end
+
+<<Class Controller method verify>>=
+	function Controller:verify ()
+		if self.is_recording then
+			error( "Verify called during record.", 2 )
+		end
+		for a in self:actions() do
+			a:assert_satisfied()
+		end
+	end
diff --git a/src/misc.nw b/src/misc.nw
new file mode 100644
index 0000000..6d95ac3
--- /dev/null
+++ b/src/misc.nw
@@ -0,0 +1,30 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+<<Lua file blurb>>=
+	------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------
+	-- Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+	-- See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+
+<<Simple Fake_action class>>=
+	Fake_action = class()
+	function Fake_action:new (x)
+		local a = object(Fake_action)
+		a.x = x
+		return a
+	end
+	function Fake_action:match (q)
+		return self.x < q.x
+	end
+	function Fake_action:is_expected ()
+		return true
+	end
+	function Fake_action:tostring ()
+		return '<faked action>'
+	end
+	function Fake_action:blocks ()
+		return function () end
+	end
+	Fake_action.depends = Fake_action.blocks
diff --git a/src/restrictions.nw b/src/restrictions.nw
new file mode 100644
index 0000000..7380089
--- /dev/null
+++ b/src/restrictions.nw
@@ -0,0 +1,632 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+Action Controll
+###############
+
+Times
+=====
+
+Some Actions might need to be replayed an arbitrary number of times,
+although they should be replayed at least once. Others might be optional
+and not need to be replayed at all.
+
+The [[min_replays]] and [[max_replays]] properties of the Action implements
+this kind of control. The Action is satisfied if it is replayed at least
+[[min_replay]] times, but it will still continue to match on lookups until
+it has been replayed [[max_replays]] times.
+
+Common values for min and max:
+
++--------+-------------------+
+| 1, 1   | exactly once      |
++--------+-------------------+
+| 1, inf | at least once     |
++--------+-------------------+
+| 0, 1   | no more than once |
++--------+-------------------+
+| 0, inf | any times         |
++--------+-------------------+
+
+It is no harm to change the times more than once; they will simply be
+overwritten. Suppressing multiple changes would require an extra control
+property.
+
+<<Unit test for module mock; times>>=
+	function times_test ()
+		local tmp = m.foo ;mc:returns( 2 ):times( 2, 3 )
+		mc:replay()
+		-- 1
+		local tmp = m.foo
+		local ok, err = pcall( function() mc:verify() end )
+		assert_false( ok, "verified unsatisfied action" )
+		assert_match( "Wrong replay count 1 ", err )
+		-- 2
+		local tmp = m.foo
+		mc:verify()
+		-- 3
+		local tmp = m.foo
+		mc:verify()
+		-- 4
+		local ok, err = pcall( function() local tmp = m.foo end )
+		assert_false( ok, "replaied finished action" )
+		assert_match( "Unexpected action index foo", err )
+	end
+	function times_called_twice_test ()
+		m.foo = 1 ;mc:times( 0, math.huge ):times( 1 )
+	end
+	function times_in_replay_mode_fails_test ()
+		mc:replay()
+		local ok, err = pcall( function() mc:times(1) end )
+		assert_false( ok, "changed times in replay mode" )
+		assert_match( "Can not set times in replay mode.", err )
+	end
+	function unrealistic_times_fails_with_message_test ()
+		m.a = 'a'
+		local ok, err = pcall( function() mc:times(0) end )
+		assert_false( ok, "accepted unrealistic time arguments" )
+		assert_match( "Unrealistic time arguments", err )
+	end
+
+<<Class Controller method times>>=
+	function Controller:times (min, max)
+		if not self.is_recording then
+			error( "Can not set times in replay mode.", 0 )
+		end
+		self:get_last_action():set_times( min, max )
+		return self -- for chaining
+	end
+	-- convenience functions
+	function Controller:anytimes()    return self:times( 0, math.huge ) end
+	function Controller:atleastonce() return self:times( 1, math.huge ) end
+@
+
+Action set_times
+----------------
+
+<<Unit test for class Action.generic method set_times>>=
+	function set_and_get_times_test ()
+	end
+	function unrealistic_times_fails_test ()
+		local ps = { {'foo'}, {8,'bar'}, {-1}, {3,2}, {1/0}, {0/0}, {0,0} }
+		for _, p in ipairs( ps ) do
+			local ok, err = pcall( function() a:set_times( unpack(p) ) end )
+			assert_false( ok, "unrealistic times "..table.concat(p,", ") )
+			assert_match( "Unrealistic time arguments ", err )
+		end
+	end
+
+<<Class Action.generic method set_times>>=
+	function Action.generic:set_times (a, b)
+		min = a or 1
+		max = b or min
+		min, max = tonumber(min), tonumber(max)
+		if (not min) or (not max) or (min >= math.huge)
+		             or (min ~= min) or (max ~= max) -- NaN
+		             or (min < 0) or (max <= 0) or (min > max) then
+			error( sfmt( "Unrealistic time arguments (%s, %s)"
+			           , qtostring( min )
+			           , qtostring( max )
+			           )
+			     , 0
+			     )
+		end
+		self.min_replays = min
+		self.max_replays = max
+	end
+@
+
+Label
+=====
+
+Labels help establishing relationships between Actions. The labels are
+actually implemented as tags, in a many-to-many relationship, so that one
+Action can have multiple labels, and the same label can be assigned to
+multiple Actions.
+
+<<Unit test for module mock; label>>=
+	function label_in_replay_mode_fails_test ()
+		mc:replay()
+		local ok, err = pcall( function() mc:label( 'foo' ) end )
+		assert_false( ok, "set label in replay mode" )
+		assert_match( "Can not add labels in replay mode", err )
+	end
+	function label_on_empty_actionlist_fails_test ()
+		local ok, err = pcall( function() mc:label( 'bar' ) end )
+		assert_false( ok, "set label with empty action list" )
+		assert_match( "No action is recorded yet", err )
+	end
+
+<<Unit test for class Controller method label>>=
+	function label_test ()
+		mc:add_action( A:new() )
+		mc:label( 'a', 'b' ):label( 'c', 'b' )
+		local a = mc:get_last_action()
+		local seen = {}
+		for l in a:blocks() do
+			seen[l] = true
+		end
+		assert_true( seen['a'] )
+		assert_true( seen['b'] )
+		assert_true( seen['c'] )
+		assert_nil(  seen['d'] )
+	end
+
+<<Class Controller method label>>=
+	function Controller:label (...)
+	if not self.is_recording then
+		error( "Can not add labels in replay mode.", 2 )
+	end
+	local action = self:get_last_action()
+	for _, label in ipairs{ ... } do
+		action:add_label( label )
+	end
+	return self -- for chaining
+	end
+@
+
+Action add_label, has_label, and blocks
+---------------------------------------
+
+There is no method for iterating through the labels, but there is a
+[[blocks]] method, that iterates through the labels if the Action is not
+satisfied. This method is used for updating the dependency information.
+
+<<Unit test for class Action.generic label methods>>=
+	function label_test ()
+		local ls = { 1/0, 0, false, {}, a, "foo", true }
+		for i = 1, #ls do
+			assert_false( a:has_label( ls[i] ))
+		end
+		for i = 1, #ls do
+			a:add_label( ls[i] )
+			for j = 1 , #ls do
+				if j <= i then
+					assert_true( a:has_label( ls[j] ))
+				else
+					assert_false( a:has_label( ls[j] ))
+				end
+			end
+		end
+	end
+	function add_label_twice_test ()
+		local l = 'foo'
+		a:add_label( l )
+		a:add_label( l )
+		local cnt = 0
+		for x in a:blocks() do
+			assert_equal( l, x )
+			cnt = cnt + 1
+		end
+		assert_equal( 1, cnt )
+	end
+
+<<Class Action.generic method add_label>>=
+	function Action.generic:add_label (label)
+		add_to_set( self, 'labellist', label )
+	end
+
+<<Class Action.generic method has_label>>=
+	function Action.generic:has_label (l)
+		for x in elements_of_set( self, 'labellist' ) do
+			if x == l then return true end
+		end
+		return false
+	end
+
+<<Class Action.generic method blocks>>=
+	function Action.generic:blocks ()
+		if self:is_satisfied() then
+			return function () end
+		end
+		return elements_of_set( self, 'labellist' )
+	end
+@
+
+Depend
+======
+
+A typical usage case is expected to have some tenths actions, so there is
+no need to optimize dependency calculations for speed. The dependencies are
+stored as lists of labels in the action objects. When an action changes
+states the Controller's [[update_dependency]] method examines the action
+list. If an action is not satisfied all its labels are collected in a
+blocking list, and finally all actions that depend on a label in the
+blocking list are blocked by setting the [[is_blocked]] property to true.
+
+<<Unit test for module mock; depend>>=
+	function depend_fulfilled_test ()
+		m.foo = 1 ;mc:label 'A'
+		m.bar = 2 ;mc:depend 'A'
+		mc:replay()
+		m.foo = 1
+		m.bar = 2
+		mc:verify()
+	end
+	function depend_unfulfilled_fails_test ()
+		m.foo = 1 ;mc:label 'A'
+		m.bar = 2 ;mc:depend 'A'
+		mc:replay()
+		local ok, err = pcall( function() m.bar = 2 end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action newindex", err )
+	end
+	function depend_fulfilled_any_order_test ()
+		local tmp
+		m.a = 1 ;mc:label 'A'
+		tmp = m.b ;mc:returns(2):depend 'A'
+		tmp = m.b ;mc:returns(3)
+		mc:replay()
+		assert_equal( 3, m.b, "replayed wrong b" )
+		m.a = 1
+		assert_equal( 2, m.b, "replayed wrong b" )
+		mc:verify()
+	end
+	function depend_serial_blocks_test ()
+		local tmp
+		tmp = m:a() ;mc:label 'a'
+		tmp = m:c() ;mc:label 'c' :depend 'b'
+		tmp = m:b() ;mc:label 'b' :depend 'a'
+		mc:replay()
+		local ok, err = pcall( function() tmp = m:b() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:a()
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:b()
+		m:c()
+		mc:verify()
+	end
+	function depend_on_many_labels_test ()
+		local tmp
+		tmp = m:b() ;mc:label 'b'
+		tmp = m:c() ;mc:label 'c' :depend( 'a', 'b' )
+		tmp = m:a() ;mc:label 'a'
+		mc:replay()
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:a()
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:b()
+		m:c()
+		mc:verify()
+	end
+	function depend_on_many_labels_test2_test ()
+		-- swap order, in case whole list is not checked
+		local tmp
+		tmp = m:b() ;mc:label 'b'
+		tmp = m:c() ;mc:label 'c' :depend( 'b', 'a' )
+		tmp = m:a() ;mc:label 'a'
+		mc:replay()
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:a()
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:b()
+		m:c()
+		mc:verify()
+	end
+	function depend_on_many_bloskers_with_same_label_test ()
+		tmp = m:c() ;mc:label 'c' :depend 'b'
+		tmp = m:a() ;mc:label 'b'
+		tmp = m:b() ;mc:label 'b'
+		mc:replay()
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:a()
+		local ok, err = pcall( function() tmp = m:c() end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "Unexpected action", err )
+		m:b()
+		m:c()
+		mc:verify()
+	end
+@
+The algorithm implies that "unknown" labels are ignored, i.e. unless a
+depended upon label is explicitly blocked by an unsatisfied action with
+that a label, the dependency is considered fulfilled.
+
+<<Unit test for module mock; depend>>=
+	function depend_ignors_unknown_label_test ()
+		m.foo = 1 ;mc:label 'A'
+		m.bar = 2 ;mc:depend 'B'
+		mc:replay()
+		m.foo = 1
+		m.bar = 2
+		mc:verify()
+	end
+@
+Cycles constitute a problem. A dependency cycle of actions will block
+itself out and can not be replayed. Although this does not necessarily mean
+replay will fail -- all the actions might for example have [[min_replays]]
+set to zero, in which case they are automatically satisfied -- it is most
+likely a user error to introduce a dependency cycle, and a helpful error
+message is in place.
+
+<<Unit test for module mock; depend>>=
+	function depend_detect_cycle_test ()
+		local ok, err = pcall( function()
+			m.foo = 1 ;mc:label 'A' :depend 'B'
+			m.bar = 2 ;mc:label 'B' :depend 'A'
+			mc:replay()
+			m.foo = 1
+		end )
+		assert_false( ok, "replayed cyclically blocked action" )
+		assert_match( "dependency cycle", err )
+	end
+
+<<Unit test for module mock; depend>>=
+	function depend_chaining_test ()
+		m.a = 1 ;mc:label 'A'
+		m.b = 1 ;mc:label 'B'
+		m.c = 1 ;mc:depend('A'):depend('B')
+	end
+	function depend_in_replay_mode_fails_test ()
+		mc:replay()
+		local ok, err = pcall( function() mc:depend( 'foo' ) end )
+		assert_false( ok, "set dependency in replay mode" )
+		assert_match( "Can not add dependency in replay mode", err )
+	end
+	function depend_on_empty_actionlist_fails_test ()
+		local ok, err = pcall( function() mc:depend( 'bar' ) end )
+		assert_false( ok, "set dependency with empty action list" )
+		assert_match( "No action is recorded yet", err )
+	end
+	function depend_reports_expected_actions_on_faliure_test ()
+		local tmp
+		tmp = m.foo ;mc:depend 'B'
+		tmp = m.bar ;mc:label 'B'
+		mc:replay()
+		local ok, err = pcall( function() tmp = m.foo end )
+		assert_false( ok, "replayed blocked action" )
+		assert_match( "expected:.*index bar", err )
+		assert_not_match( "expected:.*index foo", err )
+		tmp = m.bar
+		local ok, err = pcall( function() tmp = m.bar end )
+		assert_false( ok, "expected:.*replayed blocked action" )
+		assert_not_match( "expected:.*index bar", err )
+		assert_match( "index foo", err )
+	end
+@
+
+Addind dependencies
+-------------------
+
+<<Class Controller method depend>>=
+	function Controller:depend (...)
+		if not self.is_recording then
+			error( "Can not add dependency in replay mode.", 2 )
+		end
+		local action = self:get_last_action()
+		for _, dependency in ipairs{ ... } do
+			action:add_depend( dependency )
+		end
+		return self -- for chaining
+	end
+
+<<Unit test for Class Action.generic method add_depend and depends>>=
+	function add_depend_test ()
+		local ls = { 0, 'foo', 1/0, a, {} }
+		local seen = {}
+		for _, l in ipairs( ls ) do
+			seen[l] = 0
+			a:add_depend( l )
+		end
+		for l in a:depends() do
+			seen[l] = seen[l] + 1
+		end
+		for _, l in ipairs( ls ) do
+			assert_equal( 1, seen[l], "Mismatch for "..qtostring(l) )
+		end
+	end
+	function dependencies_dont_iterate_on_empty_list_test ()
+		for _ in a:depends() do
+			fail( "unexpected dependency" )
+		end
+	end
+
+<<Class Action.generic method add_depend>>=
+	function Action.generic:add_depend (d)
+		add_to_set( self, 'dependlist', d )
+	end
+
+<<Class Action.generic method depends>>=
+	function Action.generic:depends ()
+		return elements_of_set( self, 'dependlist' )
+	end
+@
+
+Updating dependencies and detecting cycles
+------------------------------------------
+
+<<Class Controller method update_dependencies>>=
+	function Controller:update_dependencies ()
+		local blocked = {}
+		for action in self:actions() do
+			for label in action:blocks() do
+				blocked[label] = true
+			end
+		end
+		local function is_blocked (action)
+			for label in action:depends() do
+				if blocked[label] then return true end
+			end
+			return false
+		end
+		for action in self:actions() do
+			action.is_blocked = is_blocked( action )
+		end
+	end
+@
+A cycle is detected by a complete depth-first search of the dependency
+tree, examining for each step if new labels are already present somewhere
+in the path to the new node. The design with multiple labels and multiple
+dependencies makes the algorithm a bit extra complicated, because each node
+in the tree is a set of labels.
+
+A *node* is represented as a table, where labels are stored as array
+elements, and the [[prev]] property references the previous node in the
+*path*.
+
+The use of temporary "linked lists" in this function generates a lot of
+garbage for the garbage collector, but it is only run once.
+
+<<Class Controller method assert_no_dependency_cycles>>=
+	function Controller:assert_no_dependency_cycles ()
+		local function is_in_path (label, path)
+			if not path then return false end -- is root
+			for _, l in ipairs( path ) do
+				if l == label then return true end
+			end
+			if path.prev then return is_in_path( label, path.prev ) end
+			return false
+		end
+		local function can_block (action, node)
+			for _, label in ipairs( node ) do
+				if action:has_label( label ) then return true end
+			end
+			return false
+		end
+		local function step (action, path)
+			local new_head
+			for label in action:depends() do
+				if is_in_path( label, path ) then
+					error( "Detected dependency cycle", 0 )
+				end
+				-- only create table if needed to reduce garbage
+				if not new_head then new_head = { prev=path } end
+				new_head[#new_head+1] = label
+			end
+			return new_head
+		end
+		local function search_depth_first (path)
+			for action in self:actions() do
+				if can_block( action, path ) then
+					local new_head = step( action, path )
+					if new_head then
+						search_depth_first( new_head )
+					end
+				end
+			end
+		end
+		for action in self:actions() do
+			local root = step( action, nil )
+			if root then search_depth_first( root ) end
+		end
+	end
+@
+
+Close
+=====
+
+<<Unit test for module mock; close>>=
+	function close_test ()
+		local t
+		t = m.foo ;mc:times(0,1/0):returns( 1 ) :label(1)
+		t = m.foo ;mc:times(0,1/0):returns( 2 ) :label(2)
+		t = m.foo ;mc:times(0,1/0):returns( 3 )
+		m.bar(1) ;mc:close(1)
+		m.bar(2) ;mc:close(2)
+		mc:replay()
+		m.bar(1)
+		assert_equal( 2, m.foo )
+		assert_equal( 2, m.foo )
+		assert_equal( 2, m.foo )
+		m.bar(2)
+		assert_equal( 3, m.foo )
+		mc:verify()
+	end
+	function close_unsatisfied_action_fails_test ()
+		m.a = 1 ;mc:label(1)
+		m.b = 2 ;mc:close(1)
+		mc:replay()
+		local ok, err = pcall( function() m.b = 2 end )
+		assert_false( ok, "Undetected close of unsatisfied action" )
+		assert_match( "Closes unsatisfied action", err )
+	end
+	function close_multiple_test ()
+		m.foo(1) ;mc:label(1) :times(0,1)
+		m.foo(1) ;mc:label(2) :times(0,1)
+		m.foo(1)
+		m.bar() ;mc:close(1,2)
+		mc:replay()
+		m.bar()
+		m.foo(1)
+		mc:verify()
+	end
+
+<<Unit test for module mock; close>>=
+	function close_chaining_test ()
+		m.a = 1 ;mc:label 'A'
+		m.b = 1 ;mc:label 'B'
+		m.c = 1 ;mc:close('A'):close('B')
+	end
+	function close_in_replay_mode_fails_test ()
+		mc:replay()
+		local ok, err = pcall( function() mc:close( 'foo' ) end )
+		assert_false( ok, "accepted close in replay mode" )
+		assert_match( "Can not insert close in replay mode", err )
+	end
+	function close_on_empty_actionlist_fails_test ()
+		local ok, err = pcall( function() mc:close( 'bar' ) end )
+		assert_false( ok, "accepted close with empty action list" )
+		assert_match( "No action is recorded yet", err )
+	end
+@
+
+Adding closes
+-------------
+
+<<Class Controller method close>>=
+	function Controller:close (...)
+		if not self.is_recording then
+			error( "Can not insert close in replay mode.", 2 )
+		end
+		local action = self:get_last_action()
+		for _, close in ipairs{ ... } do
+			action:add_close( close )
+		end
+		return self -- for chaining
+	end
+
+<<Class Action.generic method add_close>>=
+	function Action.generic:add_close (label)
+		add_to_set( self, 'closelist', label )
+	end
+@
+
+Perform closes
+--------------
+
+<<Class Controller method close_actions>>=
+	function Controller:close_actions( ... ) -- takes iterator
+		for label in ... do
+			for candidate in self:actions() do
+				if candidate:has_label( label ) then
+					if not candidate:is_satisfied() then
+						error( "Closes unsatisfied action: "..candidate:tostring(), 0 )
+					end
+					candidate.is_closed = true
+				end
+			end
+		end
+	end
+
+<<Class Action.generic method closes>>=
+	function Action.generic:closes ()
+		return elements_of_set( self, 'closelist' )
+	end
diff --git a/src/tostring.nw b/src/tostring.nw
new file mode 100644
index 0000000..8d9c1e6
--- /dev/null
+++ b/src/tostring.nw
@@ -0,0 +1,182 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+Convertng Objects to Strings
+############################
+
+When replay or verification fails there should be an explanation that shows
+what the problem is. One way is to list the expected actions. Therefore
+each Action type has a [[tostring]] method. The output tries to mimic what
+the missing expression might have looked like in the failing code.
+
+
+Helper functions qtostring and sfmt
+===================================
+
+[[sfmt]] is to make the code less verbose. [[qtostring]] is a wrapper for
+[[tostring]] which adds quoting of string values to make error messages
+easier to understand.
+
+<<Helper function qtostring and sfmt>>=
+	sfmt = string.format
+	function qtostring (v)
+		if type(v) == 'string' then
+			return sfmt( '%q', v )
+		else
+			return tostring( v )
+		end
+	end
+@
+
+Action Newindex
+================
+
+<<Unit test for class Action.newindex method tostring>>=
+	function newindex_tostring_test ()
+		local a = Action.newindex:new( {}, 'key', 7 )
+		assert_equal( 'newindex key = 7', a:tostring() )
+		a = Action.newindex:new( {}, true, '7' )
+		assert_equal( 'newindex true = "7"', a:tostring() )
+	end
+
+<<Class Action.newindex method tostring>>=
+	function Action.newindex:tostring ()
+		return sfmt( "newindex %s = %s"
+		             , tostring(self.key)
+		             , qtostring(self.val)
+		       )
+	end
+@
+
+Action Index
+============
+
+<<Unit test for class Action.index method tostring>>=
+	function index_tostring_test ()
+		local a = Action.index:new( {}, true )
+		assert_equal( 'index true', a:tostring() )
+		a:set_returnvalue('"false"')
+		assert_equal( 'index true => "\\"false\\""', a:tostring() )
+	end
+	function callable_index_tostring_test ()
+		local a = Action.index:new( {}, 'f' )
+		a.is_callable = true
+		assert_equal( 'index f()', a:tostring() )
+	end
+
+<<Class Action.index method tostring>>=
+	function Action.index:tostring ()
+		local key = 'index '..tostring( self.key )
+		if self.has_returnvalue then
+			return sfmt( "index %s => %s"
+			             , tostring( self.key )
+			             , qtostring( self.returnvalue )
+			       )
+		elseif self.is_callable then
+			return sfmt( "index %s()"
+			             , tostring( self.key )
+			       )
+		else
+			return sfmt( "index %s"
+			             , tostring( self.key )
+			       )
+		end
+	end
+@
+
+Action Call
+===========
+
+<<Unit test for class Action.call method tostring>>=
+	function call_tostring_test ()
+		local a = Action.call:new( {}, 'foo', 1, '"', 3 )
+		assert_equal( 'call foo(1,"\\"",3)', a:tostring() )
+		a:set_returnvalue( 'false', false )
+		assert_equal( 'call foo(1,"\\"",3) => "false",false', a:tostring() )
+	end
+
+<<Class Action.call method tostring>>=
+	function Action.call:tostring ()
+		if self.has_returnvalue then
+			return sfmt( "call %s(%s) => %s"
+			             , tostring(self.key)
+			             , self.argv:tostring()
+			             , self.returnvalue:tostring()
+			       )
+		else
+			return sfmt( "call %s(%s)"
+			             , tostring(self.key)
+			             , self.argv:tostring()
+			       )
+		end
+	end
+@
+
+Action Selfcall
+===============
+
+<<Unit test for class Action.selfcall method tostring>>=
+	function selfcall_tostring_test ()
+		local a = Action.selfcall:new( {}, 1, '"', nil )
+		assert_equal( 'selfcall (1,"\\"",nil)', a:tostring() )
+		a:set_returnvalue( 'false', false )
+		assert_equal( 'selfcall (1,"\\"",nil) => "false",false', a:tostring() )
+	end
+
+<<Class Action.selfcall method tostring>>=
+	function Action.selfcall:tostring ()
+		if self.has_returnvalue then
+			return sfmt( "selfcall (%s) => %s"
+			             , self.argv:tostring()
+			             , self.returnvalue:tostring()
+			       )
+		else
+			return sfmt( "selfcall (%s)"
+			             , self.argv:tostring()
+			       )
+		end
+	end
+@
+
+Class Argv
+==========
+
+Argument lists are converted without surrounding parentheses, because they
+can be used as multiple return values as well as call arguments. When they
+are used as call arguments, the invoker will have to add the parentheses.
+
+<<Unit test for class Argv method tostring>>=
+	function tostring_test ()
+		assert_equal( '',              Argv:new()              :tostring() )
+		assert_equal( '""',            Argv:new('')            :tostring() )
+		assert_equal( 'nil,nil',       Argv:new(nil,nil)       :tostring() )
+		assert_equal( '"false",false', Argv:new('false',false) :tostring() )
+		assert_equal( '1,2,3',         Argv:new(1,2,3)         :tostring() )
+		assert_equal( '1,ANYARG,3',    Argv:new(1,Argv.ANYARG,3):tostring() )
+		assert_equal( 'ANYARGS',       Argv:new(Argv.ANYARGS)  :tostring() )
+		assert_equal( '7,0,ANYARGS',   Argv:new(7,0,Argv.ANYARGS):tostring() )
+	end
+
+<<Class Argv method tostring>>=
+	function Argv:tostring ()
+		local res = {}
+		local function w (v)
+			res[#res+1] = qtostring( v )
+		end
+		local av, ac = self.v, self.len
+		for i = 1, ac do
+			if av[i] == Argv.ANYARG then
+				res[#res+1] = 'ANYARG'
+			elseif av[i] == Argv.ANYARGS then
+				res[#res+1] = 'ANYARGS'
+			else
+				w( av[i] )
+			end
+			if i < ac then
+				res[#res+1] = ',' -- can not use qtostring in w()
+			end
+		end
+		return table.concat( res )
+	end
diff --git a/src/unittestfiles.nw b/src/unittestfiles.nw
new file mode 100644
index 0000000..e986c9e
--- /dev/null
+++ b/src/unittestfiles.nw
@@ -0,0 +1,169 @@
+Lua Easy Mock -- LeMock
+Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
+See terms in file COPYRIGHT, or at http://lemock.luaforge.net
+@
+
+module
+------
+
+<<unit/module.lua>>=
+	<<Lua file blurb>>
+	
+	require 'lunit'
+	module( 'unit.module', lunit.testcase, package.seeall )
+	
+	require 'lemock'
+	
+	local mc, m
+	
+	function setup ()
+		mc = lemock.controller()
+		m  = mc:mock()
+	end
+
+	<<Unit test for module mock; close>>
+	<<Unit test for module mock; depend>>
+	<<Unit test for module mock; label>>
+	<<Unit test for module mock; make callable>>
+	<<Unit test for module mock; mock creation>>
+	<<Unit test for module mock; replay>>
+	<<Unit test for module mock; switching to replay mode>>
+	<<Unit test for module mock; times>>
+	<<Unit test for module mock; verify>>
+	
+	<<Unit test for module mock call>>
+	<<Unit test for module mock error>>
+	<<Unit test for module mock index>>
+	<<Unit test for module mock newindex>>
+	<<Unit test for module mock returnvalue>>
+	<<Unit test for module mock selfcall>>
+@
+
+controller
+----------
+
+<<unit/controller.lua>>=
+	<<Lua file blurb>>
+	
+	require 'lunit'
+	module( 'unit.controller', lunit.testcase, package.seeall )
+	
+	local class, object, qtostring, sfmt, add_to_set, elements_of_set
+	<<Helper function class and object>>
+	<<Helper function qtostring and sfmt>>
+	<<Helper function add_to_set and elements_of_set>>
+	
+	<<Module mock private data mock_controller_map>>
+	
+	local Controller, Action
+	<<Class Controller>>
+	<<Class Action>>
+	
+	local A = Action.generic
+	Action = nil -- only allow generic action
+	function A:tostring () return '<dummy>' end
+	
+	local mc
+	
+	function setup ()
+		mc = Controller:new()
+	end
+	
+	<<Unit test for class Controller method actions>>
+	<<Unit test for class Controller method add_action>>
+	<<Unit test for class Controller method get_last_action>>
+	<<Unit test for class Controller method label>>
+	<<Unit test for class Controller method lookup>>
+	<<Unit test for class Controller method replay>>
+	<<Unit test for class Controller method replay_action>>
+@
+
+argv
+----
+
+<<unit/argv.lua>>=
+	<<Lua file blurb>>
+	
+	require 'lunit'
+	module( 'unit.argv', lunit.testcase, package.seeall )
+	
+	local class, object, value_equal, sfmt, qtostring
+	<<Helper function class and object>>
+	<<Helper function value_equal>>
+	<<Helper function qtostring and sfmt>>
+	
+	local Argv
+	<<Class Argv>>
+	
+	<<Unit test for class Argv method equal>>
+	<<Unit test for class Argv method new>>
+	<<Unit test for class Argv method tostring>>
+	<<Unit test for class Argv method unpack>>
+@
+
+action_generic
+--------------
+
+<<unit/action_generic.lua>>=
+	<<Lua file blurb>>
+	
+	require 'lunit'
+	module( 'unit.action_generic', lunit.testcase, package.seeall )
+	
+	local class, object, qtostring, sfmt, add_to_set, elements_of_set
+	<<Helper function class and object>>
+	<<Helper function qtostring and sfmt>>
+	<<Helper function add_to_set and elements_of_set>>
+	
+	local Action, Argv
+	<<Class Action>>
+	<<Class Argv>>
+	
+	local A = Action.generic
+	Action = nil -- only allow generic action
+	function A:tostring () return "<generic action>" end
+	
+	local a
+	
+	function setup ()
+		a = A:new()
+	end
+	
+	<<Unit test for Class Action.generic method add_depend and depends>>
+	<<Unit test for class Action.generic label methods>>
+	<<Unit test for class Action.generic method is_expected>>
+	<<Unit test for class Action.generic method is_satisfied>>
+	<<Unit test for class Action.generic method match>>
+	<<Unit test for class Action.generic method new>>
+	<<Unit test for class Action.generic method set_times>>
+@
+
+action
+------
+
+<<unit/action.lua>>=
+	<<Lua file blurb>>
+	
+	require 'lunit'
+	module( 'unit.action', lunit.testcase, package.seeall )
+	
+	local class, object, qtostring, sfmt
+	<<Helper function class and object>>
+	<<Helper function value_equal>>
+	<<Helper function qtostring and sfmt>>
+	
+	local Action, Argv
+	<<Class Action>>
+	<<Class Argv>>
+	
+	<<Unit test for class Action.call method match>>
+	<<Unit test for class Action.call method tostring>>
+	<<Unit test for class Action.generic_call method get_returnvalue>>
+	<<Unit test for class Action.index method match>>
+	<<Unit test for class Action.index method new>>
+	<<Unit test for class Action.index method set_returnvalue>>
+	<<Unit test for class Action.index method tostring>>
+	<<Unit test for class Action.newindex method match>>
+	<<Unit test for class Action.newindex method tostring>>
+	<<Unit test for class Action.selfcall method match>>
+	<<Unit test for class Action.selfcall method tostring>>
diff --git a/tools/autotangle b/tools/autotangle
new file mode 100644
index 0000000..88e6a8d
--- /dev/null
+++ b/tools/autotangle
@@ -0,0 +1,28 @@
+#!/usr/bin/env rc
+
+nl='
+'
+tf=`tempfile
+
+for (f in ``($nl){noroots $* |sed 's/^<<\(.*\)>>$/\1/'}) {
+  if (~ $f *' '*) {
+    echo >[1=2] 'Skipping bad root <<'^$^f^'>>'
+  } else {
+    d=`{dirname $f} if (! test -d $d) mkdir -p $d
+    switch (`{basename $f}) {
+      case *.c *.h;   o=(-L'#line %L "%F"%N')
+      case *.lua;     o=(-L'-- %F:%L%N')
+      case *.sh;      o=(-L'# %F:%L%N')
+      case mkfile;    o=(-t8)
+      case *;         o=()
+    }
+    notangle $o -R$f $* >$tf
+    if (! cmp -s $tf $f) {
+      echo Updating $f
+      rm -f $f
+      cat $tf > $f
+      chmod a-w $f
+    }
+  }
+}
+rm $tf