pax_global_header00006660000000000000000000000064121223421130014501gustar00rootroot0000000000000052 comment=2c9b8a671d2f3a95bdf13bb8894c88fc82bc703a lua-lemock-0.6/000077500000000000000000000000001212234211300133775ustar00rootroot00000000000000lua-lemock-0.6/.travis.yml000066400000000000000000000020771212234211300155160ustar00rootroot00000000000000# # 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: alwayslua-lemock-0.6/CMakeLists.txt000066400000000000000000000010061212234211300161340ustar00rootroot00000000000000# 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/ ) lua-lemock-0.6/COPYRIGHT000066400000000000000000000026411212234211300146750ustar00rootroot00000000000000LeMock 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 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. -------------------------------------------------------------------------- lua-lemock-0.6/DEVEL000066400000000000000000000047571212234211300141760ustar00rootroot00000000000000LeMock 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). : lua-lemock-0.6/HISTORY000066400000000000000000000011501212234211300144600ustar00rootroot00000000000000LeMock 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. lua-lemock-0.6/README000066400000000000000000000023451212234211300142630ustar00rootroot00000000000000LeMock 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. lua-lemock-0.6/build/000077500000000000000000000000001212234211300144765ustar00rootroot00000000000000lua-lemock-0.6/build/htdocs/000077500000000000000000000000001212234211300157625ustar00rootroot00000000000000lua-lemock-0.6/build/htdocs/COPYRIGHT.html000066400000000000000000000044031212234211300202210ustar00rootroot00000000000000 LeMock lua-lemock-0.6/build/htdocs/DEVEL.html000066400000000000000000000071021212234211300175070ustar00rootroot00000000000000 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 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 [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, 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, 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 with the command:

lunit unit/*.lua

A program like luacov 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).

2009-05-31

lua-lemock-0.6/build/htdocs/HISTORY.html000066400000000000000000000032211212234211300200070ustar00rootroot00000000000000 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.

2009-05-31

lua-lemock-0.6/build/htdocs/README.html000066400000000000000000000045171212234211300176140ustar00rootroot00000000000000 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 the user guide.

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.


2009-05-31

lua-lemock-0.6/build/htdocs/index.html000066400000000000000000000015551212234211300177650ustar00rootroot00000000000000 LeMock
lua-lemock-0.6/build/htdocs/style.css000066400000000000000000000077651212234211300176530ustar00rootroot00000000000000 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; } lua-lemock-0.6/build/htdocs/userguide.html000066400000000000000000000327561212234211300206610ustar00rootroot00000000000000 LeMock

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 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

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()

2009-05-31

lua-lemock-0.6/build/lemock.lua000066400000000000000000000423441212234211300164620ustar00rootroot00000000000000------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------ -- Copyright (C) 2009 Tommy Pettersson -- 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 " 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 lua-lemock-0.6/build/mkfile000066400000000000000000000007501212234211300156720ustar00rootroot00000000000000MKSHELL = 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 lua-lemock-0.6/build/unit/000077500000000000000000000000001212234211300154555ustar00rootroot00000000000000lua-lemock-0.6/build/unit/action.lua000066400000000000000000000354021212234211300174410ustar00rootroot00000000000000-- ../src/unittestfiles.nw:145 -- ../src/misc.nw:7 ------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------ -- Copyright (C) 2009 Tommy Pettersson -- 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 lua-lemock-0.6/build/unit/action_generic.lua000066400000000000000000000327651212234211300211460ustar00rootroot00000000000000-- ../src/unittestfiles.nw:108 -- ../src/misc.nw:7 ------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------ -- Copyright (C) 2009 Tommy Pettersson -- 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 "" 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 lua-lemock-0.6/build/unit/argv.lua000066400000000000000000000127151212234211300171250ustar00rootroot00000000000000-- ../src/unittestfiles.nw:85 -- ../src/misc.nw:7 ------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------ -- Copyright (C) 2009 Tommy Pettersson -- 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 lua-lemock-0.6/build/unit/controller.lua000066400000000000000000000506041212234211300203500ustar00rootroot00000000000000-- ../src/unittestfiles.nw:46 -- ../src/misc.nw:7 ------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------ -- Copyright (C) 2009 Tommy Pettersson -- 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 '' 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 '' 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 ", 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 ", 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 lua-lemock-0.6/build/unit/module.lua000066400000000000000000000415401212234211300174510ustar00rootroot00000000000000-- ../src/unittestfiles.nw:10 -- ../src/misc.nw:7 ------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------ -- Copyright (C) 2009 Tommy Pettersson -- 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 lua-lemock-0.6/build/unit/userguide.lua000066400000000000000000000142711212234211300201610ustar00rootroot00000000000000-- ../src/doc/userguide/unittests.nw:7 -- ../src/misc.nw:7 ------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------ -- Copyright (C) 2009 Tommy Pettersson -- 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 lua-lemock-0.6/build/userguide.t2t000066400000000000000000000266721212234211300171420ustar00rootroot00000000000000LeMock User Guide v 0.6 2009-05-30 %!postproc(html): – – %!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() ``` lua-lemock-0.6/build/www/000077500000000000000000000000001212234211300153225ustar00rootroot00000000000000lua-lemock-0.6/build/www/COPYRIGHT.t2t000066400000000000000000000005101212234211300173210ustar00rootroot00000000000000LeMock %!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 lua-lemock-0.6/build/www/DEVEL.t2t000066400000000000000000000005561212234211300166220ustar00rootroot00000000000000LeMock %!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) lua-lemock-0.6/build/www/HISTORY.t2t000066400000000000000000000005521212234211300171200ustar00rootroot00000000000000LeMock %!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) lua-lemock-0.6/build/www/README.t2t000066400000000000000000000005471212234211300167200ustar00rootroot00000000000000LeMock %!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) lua-lemock-0.6/build/www/config.rc000066400000000000000000000001121212234211300171070ustar00rootroot00000000000000%!options: --no-rc %!style(html): style.css %!options(html): --css-sugar lua-lemock-0.6/build/www/index.t2t000066400000000000000000000004351212234211300170660ustar00rootroot00000000000000LeMock %!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'' lua-lemock-0.6/build/www/menubar.html000066400000000000000000000006061212234211300176430ustar00rootroot00000000000000 lua-lemock-0.6/build/www/userguide.t2t000066400000000000000000000005511212234211300177520ustar00rootroot00000000000000LeMock %!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) lua-lemock-0.6/cmake/000077500000000000000000000000001212234211300144575ustar00rootroot00000000000000lua-lemock-0.6/cmake/FindLua.cmake000066400000000000000000000076561212234211300170210ustar00rootroot00000000000000# 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 # 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) lua-lemock-0.6/cmake/dist.cmake000066400000000000000000000320741212234211300164320ustar00rootroot00000000000000# 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 ) lua-lemock-0.6/cmake/lua.cmake000066400000000000000000000266271212234211300162570ustar00rootroot00000000000000# 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() lua-lemock-0.6/dist.info000066400000000000000000000005121212234211300152150ustar00rootroot00000000000000--- 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" }lua-lemock-0.6/src/000077500000000000000000000000001212234211300141665ustar00rootroot00000000000000lua-lemock-0.6/src/action/000077500000000000000000000000001212234211300154435ustar00rootroot00000000000000lua-lemock-0.6/src/action/call.nw000066400000000000000000000067371212234211300167410ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson @ 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. <>= 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 ============ <>= 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 Action.call:new (m, key, ...) local a = Action.generic_call.new( self, m, ... ) a.key = key return a end @ Replay Phase ============ <>= 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 <>= 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 <>= 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 lua-lemock-0.6/src/action/generic_call.nw000066400000000000000000000044511212234211300204240ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson @ 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. <>= 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. <>= 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 --------------- <>= function Action.generic_call:set_returnvalue (...) self.returnvalue = Argv:new(...) self.has_returnvalue = true end @ 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 <>= function Action.generic_call:get_returnvalue () if self.has_returnvalue then return self.returnvalue:unpack() end end lua-lemock-0.6/src/action/index.nw000066400000000000000000000063351212234211300171270ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson @ 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. <>= 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 ============ <>= 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 ---------- <>= 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 <>= function Action.index:new (m, key) local a = Action.generic.new( self, m ) a.key = key return a end @ Action set_returnvalue ---------------------- <>= function index_returnvalue_test () local a = Action.index:new( {}, -3 ) a:set_returnvalue( 'foo' ) assert_equal( 'foo', a:get_returnvalue() ) end <>= function Action.index:set_returnvalue (v) self.returnvalue = v self.has_returnvalue = true end @ Replay Phase ============ <>= 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 ------------ <>= 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 <>= 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 ---------------------- <>= function Action.index:get_returnvalue () return self.returnvalue end lua-lemock-0.6/src/action/newindex.nw000066400000000000000000000057341212234211300176430ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson @ The Newindex Action ################### <>= 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 ============ <>= function Mock.record:__newindex (key, val) local mc = mock_controller_map[self] mc:add_action( Action.newindex:new( self, key, val )) end <>= 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 ============ <>= 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 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 <>= 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 lua-lemock-0.6/src/action/selfcall.nw000066400000000000000000000051041212234211300175760ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson @ The Call Action ############### The selfcall action is made to the Mock object itself, so no Callable or index action is needed. <>= 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 ============ <>= function Mock.record:__call (...) local mc = mock_controller_map[self] mc:add_action( Action.selfcall:new( self, ... )) end <>= function Action.selfcall:new (m, ...) local a = Action.generic_call.new( self, m, ... ) return a end @ Replay Phase ============ <>= 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 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 <>= function Action.selfcall:match (q) return Action.generic_call.match( self, q ) end lua-lemock-0.6/src/argv.nw000066400000000000000000000104121212234211300154710ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson 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. <>= 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 --- <>= 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 <>= 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 ----- <>= 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. <>= 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 ------ <>= 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 <>= function Argv:unpack () return unpack( self.v, 1, self.len ) end lua-lemock-0.6/src/class/000077500000000000000000000000001212234211300152735ustar00rootroot00000000000000lua-lemock-0.6/src/class/action.nw000066400000000000000000000046441212234211300171260ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson @ Class Inheritance ================= ABSTRACT CONCRETE generic | `------------------ newindex | `------------------ index | `-- generic_call | `------------ call | `------------ selfcall <>= Action = {} -- abstract <> <> -- concrete <> <> <> <> @ Abstract Action Classes ======================= <>= Action.generic = class() <> <> <> <> <> <> <> <> <> <> <> <> <> <>= Action.generic_call = class( Action.generic ) Action.generic_call.can_return = true <> <> <> <> @ Concrete Action Classes ======================= <>= Action.newindex = class( Action.generic ) <> <> <> <>= Action.index = class( Action.generic ) Action.index.can_return = true <> <> <> <> <> <>= Action.call = class( Action.generic_call ) <> <> <> <>= Action.selfcall = class( Action.generic_call ) <> <> <> lua-lemock-0.6/src/class/argv.nw000066400000000000000000000003541212234211300166020ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson @ <>= Argv = class() <> <> <> <> lua-lemock-0.6/src/class/callable.nw000066400000000000000000000005301212234211300173760ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson @ <>= Callable = {} Callable.generic = class() Callable.record = class( Callable.generic ) Callable.replay = class( Callable.generic ) <> <> <> lua-lemock-0.6/src/class/controller.nw000066400000000000000000000016711212234211300200310ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson @ <>= Controller = class() -- Exported methods <> <> <> <> <> <> <> <> <> <> -- Protected methods <> <> <> <> <> <> <> <> <> <> lua-lemock-0.6/src/class/mock.nw000066400000000000000000000005301212234211300165700ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson @ <>= <> <> <> <> <> <> <> lua-lemock-0.6/src/doc/000077500000000000000000000000001212234211300147335ustar00rootroot00000000000000lua-lemock-0.6/src/doc/userguide/000077500000000000000000000000001212234211300167275ustar00rootroot00000000000000lua-lemock-0.6/src/doc/userguide/chapter_controller.nw000066400000000000000000000014431212234211300231700ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ <>= = 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. <> <> <> <> @ lua-lemock-0.6/src/doc/userguide/chapter_introduction.nw000066400000000000000000000044021212234211300235240ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ <>= = Introduction = <> === Example === This example tests that the insert_data function of the foo module handles a missing data base table gracefully. ``` <> ``` 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. @ <>= -- 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() @ <>= 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 <> end lua-lemock-0.6/src/doc/userguide/chapter_mock.nw000066400000000000000000000015651212234211300217430ustar00rootroot00000000000000Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ <>= = 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. <> <> @ lua-lemock-0.6/src/doc/userguide/chapter_tricks.nw000066400000000000000000000034711212234211300223070ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ <>= = 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() @ <>= function overloading_test () <> end lua-lemock-0.6/src/doc/userguide/main.nw000066400000000000000000000007501212234211300202230ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ <>= LeMock User Guide v 0.6 2009-05-30 %!postproc(html): – – %!postproc(tex): – -- <> <> <> <> @ TODO method reference with syntax errors and their messages limitations & future work lua-lemock-0.6/src/doc/userguide/section_actions.nw000066400000000000000000000015741212234211300224700ustar00rootroot00000000000000Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ <>= == 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 @ <>= function actions_test () <> end lua-lemock-0.6/src/doc/userguide/section_anyargs.nw000066400000000000000000000023231212234211300224650ustar00rootroot00000000000000Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ <>= == Anyargs ==[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. ``` <> ``` @ <>= 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() @ <>= 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 <> end lua-lemock-0.6/src/doc/userguide/section_close.nw000066400000000000000000000032561212234211300221340ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ <>= == 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() @ <>= 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 <> end lua-lemock-0.6/src/doc/userguide/section_label_depend.nw000066400000000000000000000041421212234211300234200ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ <>= == 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. ``` <> ``` 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. @ <>= 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() @ <>= 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 <> end lua-lemock-0.6/src/doc/userguide/section_returns_error.nw000066400000000000000000000022241212234211300237340ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ <>= == 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") @ <>= function returns_error_test () <> end lua-lemock-0.6/src/doc/userguide/section_times.nw000066400000000000000000000034111212234211300221410ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ <>= == 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() @ <>= 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 <> end lua-lemock-0.6/src/doc/userguide/unittests.nw000066400000000000000000000011751212234211300213430ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ <>= <> require 'lunit' module( 'unit.userguide', lunit.testcase, package.seeall ) <> <> <> <> <> <> <> <> lua-lemock-0.6/src/doc/webpages.nw000066400000000000000000000146521212234211300171060ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson 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. <>= 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. <>= <> %!postproc(html): 'ID="body"' 'ID="page-README"' <> = Readme = %!include: ../../README <> @ (No footer on copyright page!) <>= <> %!postproc(html): 'ID="body"' 'ID="page-COPYRIGHT"' <> = License = %!include: ../../COPYRIGHT @ <>= <> %!postproc(html): 'ID="body"' 'ID="page-HISTORY"' <> = History = %!include: ../../HISTORY <> @ <>= <> %!postproc(html): 'ID="body"' 'ID="page-DEVEL"' <> = Developer Notes = %!include: ../../DEVEL <> @ (The user guide is tangled into the build directory.) <>= <> %!postproc(html): 'ID="body"' 'ID="page-userguide"' <> %%toc %!include: ../userguide.t2t <> @ The index file is just an empty file with the navigation menu. This is stupid. FIXME! <>= <> %!postproc(html): 'ID="body"' 'ID="page-index"' <> @ == 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. <>= LeMock %!includeconf: config.rc <> @ <>= -------------------- %%Date(%Y-%m-%d) @ Use css for layout and navigation menu. <>= %!options: --no-rc %!style(html): style.css %!options(html): --css-sugar @ <>= <> <> @ 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. <>= %!preproc: COPYRIGHT_ "[COPYRIGHT COPYRIGHT.html]" %!preproc: DEVEL_ "[DEVEL DEVEL.html]" %!preproc: "build/htdocs/userguide.html" "[the user guide userguide.html]" @ == Style Sheet === <>= <> <> <> <> <> <>= 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; } @ == Navigation Menu Bar == The navigation menu bar is implemented with css. <>= %!include(html): ''menubar.html'' @ <>= @ <>= #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; } lua-lemock-0.6/src/files.nw000066400000000000000000000015211212234211300156350ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson 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 " local class, object, qtostring, sfmt, add_to_set local elements_of_set, value_equal <> <> <> <> <> -- All the classes are private local Action, Argv, Callable, Controller, Mock <> <> <> <> <> <> return _M lua-lemock-0.6/src/helperfunctions.nw000066400000000000000000000026441212234211300177520ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson 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. <>= 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. <>= 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. <>= 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 lua-lemock-0.6/src/main.nw000066400000000000000000000575331212234211300154750ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ 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 ---------- <>= 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 <>= 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. <>= function lookup_returns_first_matching_action_test () local Fake_action <> 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 ", 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 ", err ) assert_equal( a1, mc:lookup( a2 ), "did not find first match" ) end <>= function Controller:lookup (actual) for action in self:actions() do if action:match( actual ) then return action end end <> 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. <>= 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. <>= 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 <>= 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 ---- <>= 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 <>= 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. <>= 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 <>= 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. <>= function expect_unreplayed_action_test () assert_true( a:is_expected() ) 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 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 <>= 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. <>= 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 <>= 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. <>= 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 <>= self.min_replays <= self.replay_count <>= function Action.generic:is_satisfied () return <> end <>= function Action.generic:assert_satisfied () assert( self.replay_count <= self.max_replays, "lemock internal error" ) if not (<>) 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. <>= 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. <>= 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 <>= 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. <>= 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. <>= 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 <>= 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. <>= 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. <>= 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 <>= 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. <>= 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 <>= 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. <>= 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 <>= 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. <>= 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 <>= function replay_test () assert_true( mc.is_recording ) mc:replay() assert_false( mc.is_recording ) 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 @ Replay Phase ============ The key point with the replay phase is that unexpected actions should fail. <>= 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. <>= 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. <>= 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 <>= 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 lua-lemock-0.6/src/misc.nw000066400000000000000000000014161212234211300154710ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ <>= ------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------ -- Copyright (C) 2009 Tommy Pettersson -- See terms in file COPYRIGHT, or at http://lemock.luaforge.net <>= 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 '' end function Fake_action:blocks () return function () end end Fake_action.depends = Fake_action.blocks lua-lemock-0.6/src/restrictions.nw000066400000000000000000000437161212234211300172770ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson 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. <>= 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 <>= 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 ---------------- <>= 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 <>= 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. <>= 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 <>= 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 <>= 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. <>= 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 <>= function Action.generic:add_label (label) add_to_set( self, 'labellist', label ) 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: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. <>= 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. <>= 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. <>= 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 <>= 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 ------------------- <>= 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 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 <>= function Action.generic:add_depend (d) add_to_set( self, 'dependlist', d ) end <>= function Action.generic:depends () return elements_of_set( self, 'dependlist' ) end @ Updating dependencies and detecting cycles ------------------------------------------ <>= 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. <>= 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 ===== <>= 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 <>= 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 ------------- <>= 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 Action.generic:add_close (label) add_to_set( self, 'closelist', label ) end @ Perform closes -------------- <>= 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 Action.generic:closes () return elements_of_set( self, 'closelist' ) end lua-lemock-0.6/src/tostring.nw000066400000000000000000000121401212234211300164030ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson 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. <>= sfmt = string.format function qtostring (v) if type(v) == 'string' then return sfmt( '%q', v ) else return tostring( v ) end end @ Action Newindex ================ <>= 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 <>= function Action.newindex:tostring () return sfmt( "newindex %s = %s" , tostring(self.key) , qtostring(self.val) ) end @ Action Index ============ <>= 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 <>= 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 =========== <>= 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 <>= 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 =============== <>= 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 <>= 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. <>= 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 <>= 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 lua-lemock-0.6/src/unittestfiles.nw000066400000000000000000000105701212234211300174410ustar00rootroot00000000000000Lua Easy Mock -- LeMock Copyright (C) 2009 Tommy Pettersson See terms in file COPYRIGHT, or at http://lemock.luaforge.net @ module ------ <>= <> require 'lunit' module( 'unit.module', lunit.testcase, package.seeall ) require 'lemock' local mc, m function setup () mc = lemock.controller() m = mc:mock() end <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> @ controller ---------- <>= <> require 'lunit' module( 'unit.controller', lunit.testcase, package.seeall ) local class, object, qtostring, sfmt, add_to_set, elements_of_set <> <> <> <> local Controller, Action <> <> local A = Action.generic Action = nil -- only allow generic action function A:tostring () return '' end local mc function setup () mc = Controller:new() end <> <> <> <> <> <> <> @ argv ---- <>= <> require 'lunit' module( 'unit.argv', lunit.testcase, package.seeall ) local class, object, value_equal, sfmt, qtostring <> <> <> local Argv <> <> <> <> <> @ action_generic -------------- <>= <> require 'lunit' module( 'unit.action_generic', lunit.testcase, package.seeall ) local class, object, qtostring, sfmt, add_to_set, elements_of_set <> <> <> local Action, Argv <> <> local A = Action.generic Action = nil -- only allow generic action function A:tostring () return "" end local a function setup () a = A:new() end <> <> <> <> <> <> <> @ action ------ <>= <> require 'lunit' module( 'unit.action', lunit.testcase, package.seeall ) local class, object, qtostring, sfmt <> <> <> local Action, Argv <> <> <> <> <> <> <> <> <> <> <> <> <> lua-lemock-0.6/tools/000077500000000000000000000000001212234211300145375ustar00rootroot00000000000000lua-lemock-0.6/tools/autotangle000066400000000000000000000011271212234211300166260ustar00rootroot00000000000000#!/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