summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2012-07-21 11:26:54 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2012-07-21 11:26:54 +0100
commitb4d2d633cd88308487aa6e2b689a4328ce6023c1 (patch)
tree7d20facb39d11255c43271251ee6d278028a09d9
downloadsupple-b4d2d633cd88308487aa6e2b689a4328ce6023c1.tar.gz
Initial framework for Supple
-rw-r--r--.gitignore6
-rw-r--r--COPYING26
-rw-r--r--Makefile70
-rw-r--r--README19
-rw-r--r--extras/luacov/Makefile26
-rw-r--r--extras/luacov/README.md79
-rw-r--r--extras/luacov/doc/doc.css223
-rw-r--r--extras/luacov/doc/index.html200
-rw-r--r--extras/luacov/doc/license.html113
-rw-r--r--extras/luacov/doc/luacov.pngbin0 -> 8420 bytes
-rw-r--r--extras/luacov/luacov-0.2-1.rockspec28
-rwxr-xr-xextras/luacov/src/bin/luacov142
-rw-r--r--extras/luacov/src/luacov.lua95
-rw-r--r--extras/luacov/src/luacov/stats.lua73
-rw-r--r--extras/luacov/src/luacov/tick.lua7
-rw-r--r--lib/supple.lua23
-rw-r--r--lib/supple/capi.c35
-rw-r--r--test/test-supple.capi.lua55
-rw-r--r--test/test-supple.lua52
19 files changed, 1272 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3057691
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+*~
+*.o
+*.so
+luacov.stats.out
+luacov.report.out
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..a4ddae0
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,26 @@
+Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. Neither the name of the author nor the names of their contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a54466a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,70 @@
+all: test
+
+LMODULES := supple
+CMODULES := supple.capi
+MODULES := $(LMODULES) $(CMODULES)
+LUA_VER := 5.1
+
+INST_BASE := /usr/local
+LINST_ROOT := $(DESTDIR)$(INST_BASE)/share/lua/$(LUA_VER)
+CINST_ROOT := $(DESTDIR)$(INST_BASE)/lib/lua/$(LUA_VER)
+
+LMOD_FILES := $(patsubst %,%.lua,$(subst .,/,$(LMODULES)))
+CMOD_FILES := $(patsubst %,%.so,$(subst .,/,$(CMODULES)))
+
+CMOD_TARGETS := $(patsubst %,lib/%.so,$(subst .,/,$(CMODULES)))
+CMOD_OBJECTS := $(patsubst %,lib/%.o,$(subst .,/,$(CMODULES)))
+
+.PRECIOUS: $(CMOD_OBJECTS)
+
+INCS := -I/usr/include/lua$(LUA_VER)
+OPT := -O0 -g
+CFLAGS := $(INCS) $(OPT) $(CFLAGS)
+LFLAGS := -O1 -g -shared $(LFLAGS)
+
+%.so: %.o
+ $(CC) $(LFLAGS) -shared -o $@ $^ -llua$(LUA_VER)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -fPIC -o $@ -c $<
+
+build: $(CMOD_TARGETS)
+
+install: build
+ mkdir -p $(LINST_ROOT)/supple
+ mkdir -p $(CINST_ROOT)/supple
+ for MOD in $(sort $(LMOD_FILES)); do \
+ cp lib/$${MOD} $(LINST_ROOT)/$${MOD}; \
+ done
+ for MOD in $(sort $(CMOD_FILES)); do \
+ cp lib/$${MOD} $(CINST_ROOT)/$${MOD}; \
+ done
+
+LUA := LUA_PATH="$(shell pwd)/lib/?.lua;$(shell pwd)/extras/luacov/src/?.lua;;" LUA_CPATH="$(shell pwd)/lib/?.so;;" lua$(LUA_VER)
+
+clean:
+ $(RM) luacov.report.out luacov.stats.out
+ $(RM) $(CMOD_TARGETS) $(CMOD_OBJECTS)
+
+distclean: clean
+ find . -name "*~" -delete
+
+.PHONY: example
+example:
+ $(LUA) example/supple-example.lua
+
+.PHONY: test
+test: build
+ @$(RM) luacov.stats.out
+ @ERR=0; \
+ for MOD in $(sort $(MODULES)); do \
+ echo -n "$${MOD}: "; \
+ $(LUA) test/test-$${MOD}.lua; \
+ test "x$$?" = "x0" || ERR=1; \
+ done; \
+ $(LUA) extras/luacov/src/bin/luacov -X luacov. -X test. $(LMODULES); \
+ exit $$ERR
+
+.PHONY: interactive
+interactive: build
+ $(LUA) -e'lace=require"supple"' -i
diff --git a/README b/README
new file mode 100644
index 0000000..9e1e51b
--- /dev/null
+++ b/README
@@ -0,0 +1,19 @@
+Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine - Supple
+=======================================================================
+
+Supple is a tool for sandboxing untrusted code and providing security
+partitioning. It deliberately operates by first forking a subprocess which is
+strictly limited in what it can do. For example, only whitelisted Lua modules
+may be loaded, and they are all loaded *before* any untrusted code is run. The
+developer implementing Supple in their project is responsible for ensuring that
+any modules loaded into the subprocess cannot break the sandbox.
+
+In order to reduce the chance of anything breaking the sandbox, Supple always
+presents remote objects as userdata and forces the use of coroutines in order
+to allow calls back and forth between the two ends of the sandbox connection.
+
+This means that, for example, methods can be called and passed callback
+functions which can thread back and forth unrestricted.
+
+For examples of using Supple, please see the examples/ directory.
+
diff --git a/extras/luacov/Makefile b/extras/luacov/Makefile
new file mode 100644
index 0000000..1518bbf
--- /dev/null
+++ b/extras/luacov/Makefile
@@ -0,0 +1,26 @@
+
+PACKAGE=luacov
+VERSION=0.3
+PREFIX=/usr/local
+BINDIR=$(PREFIX)/bin
+LUADIR=$(PREFIX)/share/lua/5.1/
+
+install:
+ mkdir -p $(BINDIR)
+ cp src/bin/luacov $(BINDIR)
+ mkdir -p $(LUADIR)
+ cp src/luacov.lua $(LUADIR)
+ mkdir -p $(LUADIR)/luacov
+ cp src/luacov/stats.lua $(LUADIR)/luacov
+ cp src/luacov/tick.lua $(LUADIR)/luacov
+
+dist:
+ rm -f dist.files
+ rm -rf $(PACKAGE)-$(VERSION)
+ rm -f $(PACKAGE)-$(VERSION).tar.gz
+ find * | grep -v CVS > dist.files
+ mkdir -p $(PACKAGE)-$(VERSION)
+ cpio -p $(PACKAGE)-$(VERSION) < dist.files
+ tar czvf $(PACKAGE)-$(VERSION).tar.gz $(PACKAGE)-$(VERSION)
+ rm -f dist.files
+ rm -rf $(PACKAGE)-$(VERSION)
diff --git a/extras/luacov/README.md b/extras/luacov/README.md
new file mode 100644
index 0000000..efc31c5
--- /dev/null
+++ b/extras/luacov/README.md
@@ -0,0 +1,79 @@
+## Overview
+
+LuaCov is a simple coverage analyzer for [Lua](http://www.lua.org)
+scripts. When a Lua script is run with the `luacov` module loaded, it
+generates a stats file with the number of executions of each line of the
+script and its loaded modules. The `luacov` command-line script then
+processes this file generating a report file which allows one to visualize
+which code paths were not traversed, which is useful for verifying the
+effectiveness of a test suite.
+
+LuaCov is free software and, like Lua, is released under the
+[MIT License](http://www.lua.org/license.html).
+
+## Download and Installation
+
+LuaCov can be downloaded from its
+[LuaForge page](http://luaforge.net/projects/luacov/files).
+
+It can also be installed using Luarocks:
+
+ luarocks install luacov
+
+LuaCov is written in pure Lua and has no external dependencies.
+
+## Instructions
+
+Using LuaCov consists of two steps: running your script to collect
+coverage data, and then running `luacov` on the collected data to
+generate a report.
+
+To collect coverage data, your script needs to load the `luacov`
+Lua module. This can be done from the command-line, without modifying
+your script, like this:
+
+ lua -lluacov test.lua
+
+Alternatively, you can add `require("luacov")` to the first line
+of your script.
+
+Once the script is run, a file called `lcov.stats.out` is generated.
+If the file already exists, statistics are _added_ to it. This is useful,
+for example, for making a series of runs with different input parameters in
+a test suite. To start the accounting from scratch, just delete the stats file.
+
+To generate a report, just run the `luacov` command-line script.
+It expects to find a file named `lcov.stats.out` in the current
+directory, and outputs a file named `lcov.report.out`.
+
+This is an example output of the report file:
+
+ ============================================================
+ ../test.lua
+ ============================================================
+
+ -- Which branch will run?
+ 1 if 10 > 100 then
+ 0 print("I don't think this line will execute.")
+ 0 else
+ 1 print("Hello, LuaCov!")
+ 1 end
+
+Note that to generate this report, `luacov` reads the source files.
+Therefore, it expects to find them in the same location they were when
+the `luacov` module ran (the stats file stores the filenames, but
+not the sources themselves).
+
+LuaCov saves its stats upon normal program termination. If your program
+is a daemon -- in other words, if it does not terminate normally -- you
+can use the `luacov.tick` module, which periodically saves the
+stats file. For example, to run (on Unix systems) LuaCov on
+[Xavante](http://www.keplerproject.org/xavante),
+just modify the first line of `xavante_start.lua` so it reads:
+
+ #!/usr/bin/env lua -lluacov.tick
+
+## Credits
+
+LuaCov was designed and implemented by Hisham Muhammad as a tool for
+testing [Luarocks](http://luarocks.luaforge.net).
diff --git a/extras/luacov/doc/doc.css b/extras/luacov/doc/doc.css
new file mode 100644
index 0000000..3770e4e
--- /dev/null
+++ b/extras/luacov/doc/doc.css
@@ -0,0 +1,223 @@
+body {
+ margin-left: 1em;
+ margin-right: 1em;
+ font-family: arial, helvetica, geneva, sans-serif;
+ background-color:#ffffff; margin:0px;
+}
+
+code {
+ font-family: "Andale Mono", monospace;
+}
+
+tt {
+ font-family: "Andale Mono", monospace;
+}
+
+body, td, th { font-size: 11pt; }
+
+h1, h2, h3, h4 { margin-left: 0em; }
+
+textarea, pre, tt { font-size:10pt; }
+body, td, th { color:#000000; }
+small { font-size:0.85em; }
+h1 { font-size:1.5em; }
+h2 { font-size:1.25em; }
+h3 { font-size:1.15em; }
+h4 { font-size:1.06em; }
+
+a:link { font-weight:bold; color: #004080; text-decoration: none; }
+a:visited { font-weight:bold; color: #006699; text-decoration: none; }
+a:link:hover { text-decoration:underline; }
+hr { color:#cccccc }
+img { border-width: 0px; }
+
+
+h3 { padding-top: 1em; }
+
+p { margin-left: 1em; }
+
+p.name {
+ font-family: "Andale Mono", monospace;
+ padding-top: 1em;
+ margin-left: 0em;
+}
+
+blockquote { margin-left: 3em; }
+
+.example {
+ background-color: rgb(245, 245, 245);
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-style: solid;
+ border-right-style: solid;
+ border-bottom-style: solid;
+ border-left-style: solid;
+ border-top-color: silver;
+ border-right-color: silver;
+ border-bottom-color: silver;
+ border-left-color: silver;
+ padding: 1em;
+ margin-left: 1em;
+ margin-right: 1em;
+ font-family: "Andale Mono", monospace;
+ font-size: smaller;
+}
+
+
+hr {
+ margin-left: 0em;
+ background: #00007f;
+ border: 0px;
+ height: 1px;
+}
+
+ul { list-style-type: disc; }
+
+table.index { border: 1px #00007f; }
+table.index td { text-align: left; vertical-align: top; }
+table.index ul { padding-top: 0em; margin-top: 0em; }
+
+table {
+ border: 1px solid black;
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+}
+th {
+ border: 1px solid black;
+ padding: 0.5em;
+}
+td {
+ border: 1px solid black;
+ padding: 0.5em;
+}
+div.header, div.footer { margin-left: 0em; }
+
+#container
+{
+ margin-left: 1em;
+ margin-right: 1em;
+ background-color: #f0f0f0;
+}
+
+#product
+{
+ text-align: center;
+ border-bottom: 1px solid #cccccc;
+ background-color: #ffffff;
+}
+
+#product big {
+ font-size: 2em;
+}
+
+#product_logo
+{
+}
+
+#product_name
+{
+}
+
+#product_description
+{
+}
+
+#main
+{
+ background-color: #f0f0f0;
+ border-left: 2px solid #cccccc;
+}
+
+#navigation
+{
+ float: left;
+ width: 12em;
+ margin: 0;
+ vertical-align: top;
+ background-color: #f0f0f0;
+ overflow:visible;
+}
+
+#navigation h1 {
+ background-color:#e7e7e7;
+ font-size:1.1em;
+ color:#000000;
+ text-align:left;
+ margin:0px;
+ padding:0.2em;
+ border-top:1px solid #dddddd;
+ border-bottom:1px solid #dddddd;
+}
+
+#navigation ul
+{
+ font-size:1em;
+ list-style-type: none;
+ padding: 0;
+ margin: 1px;
+}
+
+#navigation li
+{
+ text-indent: -1em;
+ margin: 0em 0em 0em 0.5em;
+ display: block;
+ padding: 3px 0px 0px 12px;
+}
+
+#navigation li li a
+{
+ padding: 0px 3px 0px -1em;
+}
+
+#content
+{
+ margin-left: 12em;
+ padding: 1em;
+ border-left: 2px solid #cccccc;
+ border-right: 2px solid #cccccc;
+ background-color: #ffffff;
+}
+
+#about
+{
+ clear: both;
+ margin: 0;
+ padding: 5px;
+ border-top: 2px solid #cccccc;
+ background-color: #ffffff;
+}
+
+@media print {
+ body {
+ font: 10pt "Times New Roman", "TimeNR", Times, serif;
+ }
+ a { font-weight:bold; color: #004080; text-decoration: underline; }
+
+ #main { background-color: #ffffff; border-left: 0px; }
+ #container { margin-left: 2%; margin-right: 2%; background-color: #ffffff; }
+
+ #content { margin-left: 0px; padding: 1em; border-left: 0px; border-right: 0px; background-color: #ffffff; }
+
+ #navigation { display: none;
+ }
+
+ #product_logo
+ {
+ display: none;
+ }
+
+ #about img
+ {
+ display: none;
+ }
+
+ .example {
+ font-family: "Andale Mono", monospace;
+ font-size: 8pt;
+ page-break-inside: avoid;
+ }
+}
diff --git a/extras/luacov/doc/index.html b/extras/luacov/doc/index.html
new file mode 100644
index 0000000..ed451a2
--- /dev/null
+++ b/extras/luacov/doc/index.html
@@ -0,0 +1,200 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+ <title>LuaCov - Coverage analysis for Lua scripts</title>
+ <link rel="stylesheet" href="doc.css" type="text/css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<style type="text/css">
+pre {
+ font-family: "Andale Mono", monospace;
+}
+div.Example {
+ font-family: "Andale Mono", monospace;
+ background-color: #f0f0f0;
+ margin-left: 1em;
+ margin-right: 1em;
+ margin-top: 0.5em;
+ margin-bottom 0.5em;
+ padding: 0.5em;
+}
+</style>
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"><a href="http://luacov.luaforge.net">
+ <img alt="LuaCov logo" src="luacov.png" />
+ </a></div>
+ <div id="product_name"><big><strong>LuaCov</strong></big></div>
+ <div id="product_description">Coverage analysis for Lua scripts</div>
+</div> <!-- id="product" -->
+
+<div id="main">
+
+<div id="navigation">
+
+<h1>LuaCov</h1>
+
+<ul>
+ <li><strong>Home</strong>
+ <ul>
+ <li> <a href="index.html#over">Overview</a></li>
+ <li> <a href="index.html#download">Download</a></li>
+ <li> <a href="index.html#instructions">Instructions</a></li>
+ <li> <a href="index.html#history">History</a></li>
+ <li> <a href="index.html#credits">Credits</a></li>
+ <li> <a href="index.html#contact">Contact</a></li>
+ </ul>
+ </li>
+ <li><a href="http://luaforge.net/projects/luacov/">Project</a>
+ <ul>
+ <li><a href="http://luaforge.net/scm/?group_id=290">CVS</a></li>
+ </ul>
+ </li>
+ <li><a href="license.html">License</a></li>
+</ul>
+
+</div> <!-- id="navigation" -->
+
+<div id="content">
+
+<h2><a name="over"></a>Overview</h2>
+
+<p>
+LuaCov is a simple coverage analyzer for <a href="http://www.lua.org">Lua</a>
+scripts. When a Lua script is run with the <tt>luacov</tt> module loaded, it
+generates a stats file with the number of executions of each line of the
+script and its loaded modules. The <tt>luacov</tt> command-line script then
+processes this file generating a report file which allows one to visualize
+which code paths were not traversed, which is useful for verifying the
+effectiveness of a test suite.
+</p>
+
+<p>
+LuaCov is free software and uses the same <a href="license.html">license</a> as Lua.
+</p>
+
+<h2><a name="download"></a>Download</h2>
+
+<p>
+LuaCov can be downloaded from its
+<a href="http://luaforge.net/projects/luacov/files/">LuaForge page</a>.
+</p>
+
+<p>
+LuaCov is written in pure Lua and has no external dependencies.
+</p>
+
+<h2><a name="instructions"></a>Instructions</h2>
+
+<p>
+Using LuaCov consists of two steps: running your script to collect
+coverage data, and then running <tt>luacov</tt> on the collected data to
+generate a report.
+</p>
+
+<p>
+To collect coverage data, your script needs to load the <tt>luacov</tt>
+Lua module. This can be done from the command-line, without modifying
+your script, like this:
+</p>
+
+<div class="Example">
+lua -lluacov test.lua
+</div>
+
+<p>
+(Alternatively, you can add <tt>require("luacov")</tt> to the first line
+of your script.)
+</p>
+
+<p>
+Once the script is run, a file called <tt>lcov.stats.out</tt> is generated.
+If the file already exists, statistics are <i>added</i> to it. This is useful,
+for example, for making a series of runs with different input parameters in
+a test suite. To start the accounting from scratch, just delete the stats file.
+</p>
+
+<p>
+To generate a report, just run the <tt>luacov</tt> command-line script.
+It expects to find a file named <tt>lcov.stats.out</tt> in the current
+directory, and outputs a file named <tt>lcov.report.out</tt>.
+</p>
+
+<p>This is an example output of the report file:</p>
+
+<div class="Example"><pre>
+============================================================
+../test.lua
+============================================================
+
+ -- Which branch will run?
+1 if 10 > 100 then
+0 print("I don't think this line will execute.")
+0 else
+1 print("Hello, LuaCov!")
+1 end
+</pre></div>
+
+<p>
+Note that to generate this report, <tt>luacov</tt> reads the source files.
+Therefore, it expects to find them in the same location they were when
+the <tt>luacov</tt> module ran (the stats file stores the filenames, but
+not the sources themselves).
+</p>
+
+<p>
+LuaCov saves its stats upon normal program termination. If your program
+is a daemon -- in other words, if it does not terminate normally -- you
+can use the <tt>luacov.tick</tt> module, which periodically saves the
+stats file. For example, to run (on Unix systems) LuaCov on
+<a href="http://www.keplerproject.org/xavante">Xavante</a>,
+just modify the first line of <tt>xavante_start.lua</tt> so it reads:
+</p>
+
+<div class="Example">
+#!/usr/bin/env lua -lluacov.tick
+</div>
+
+<h2><a name="history"></a>History</h2>
+
+<dl>
+ <dt><strong>0.1</strong> [July 16, 2007]</dt>
+ <dd>
+ <ul>
+ <li>Initial release.</li>
+ </ul>
+ </dd>
+</dl>
+
+<h2><a name="credits"></a>Credits</h2>
+
+<p>
+LuaCov was designed and implemented by Hisham Muhammad as a tool for
+testing <a href="http://luarocks.luaforge.net">LuaRocks</a>.
+</p>
+
+<h2><a name="contact"></a>Contact</h2>
+
+<p>
+For more information please
+<a href="mailto:hisham-NO-SPAM-THANKS@gobolinux.org">contact</a> us. Comments are welcome!
+</p>
+
+</div> <!-- id="content" -->
+
+</div> <!-- id="main" -->
+
+<div id="about">
+ <p><a href="http://validator.w3.org/check?uri=referer">
+ <img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
+</div> <!-- id="about" -->
+
+</div> <!-- id="container" -->
+
+</body>
+</html>
diff --git a/extras/luacov/doc/license.html b/extras/luacov/doc/license.html
new file mode 100644
index 0000000..afbb9f6
--- /dev/null
+++ b/extras/luacov/doc/license.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+ <title>LuaCov - Coverage analysis for Lua scripts</title>
+ <link rel="stylesheet" href="doc.css" type="text/css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"><a href="http://luacov.luaforge.net">
+ <img alt="LuaCov logo" src="luacov.png" />
+ </a></div>
+ <div id="product_name"><big><b>LuaCov</b></big></div>
+ <div id="product_description">Coverage analysis for Lua scripts</div>
+</div> <!-- id="product" -->
+
+<div id="main">
+
+<div id="navigation">
+
+<h1>LuaCov</h1>
+
+<ul>
+ <li><a href="index.html">Home</a>
+ <ul>
+ <li> <a href="index.html#over">Overview</a></li>
+ <li> <a href="index.html#download">Download</a></li>
+ <li> <a href="index.html#dependencies">Instructions</a></li>
+ <li> <a href="index.html#history">History</a></li>
+ <li> <a href="index.html#credits">Credits</a></li>
+ <li> <a href="index.html#contact">Contact</a></li>
+ </ul>
+ </li>
+ <li><a href="http://luaforge.net/projects/luacov/">Project</a>
+ <ul>
+ <li><a href="http://luaforge.net/scm/?group_id=290">CVS</a></li>
+ </ul>
+ </li>
+ <li><strong>License</strong></li>
+</ul>
+
+</div> <!-- id="navigation" -->
+
+<div id="content">
+
+<h2>License</h2>
+
+<p>
+LuaCov is free software: it can be used for both academic and commercial purposes
+at absolutely no cost. There are no royalties or GNU-like "copyleft" restrictions.
+LuaCov qualifies as <a href="http://www.opensource.org/docs/definition.html">Open Source</a> software.
+Its licenses are compatible with <a href="http://www.gnu.org/licenses/gpl.html">GPL</a>.
+LuaCov is not in the public domain. The legal details are below.
+</p>
+
+<p>
+The spirit of the license is that you are free to use LuaCov for any purpose
+at no cost without having to ask us. The only requirement is that if you do use
+LuaCov, then you should give us credit by including the appropriate copyright notice
+somewhere in your product or its documentation.
+</p>
+
+<p>
+LuaCov is designed and implemented by Hisham Muhammad.
+The implementation is not derived from licensed software.
+</p>
+
+<hr/>
+
+<p>Copyright (c) 2007 Hisham Muhammad.</p>
+
+<p>
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+</p>
+
+<p>
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+</p>
+
+<p>
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+</p>
+
+</div> <!-- id="content" -->
+
+</div> <!-- id="main" -->
+
+<div id="about">
+ <p><a href="http://validator.w3.org/check?uri=referer">
+ <img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
+</div> <!-- id="about" -->
+
+</div> <!-- id="container" -->
+
+</body>
+</html>
diff --git a/extras/luacov/doc/luacov.png b/extras/luacov/doc/luacov.png
new file mode 100644
index 0000000..1cf37b7
--- /dev/null
+++ b/extras/luacov/doc/luacov.png
Binary files differ
diff --git a/extras/luacov/luacov-0.2-1.rockspec b/extras/luacov/luacov-0.2-1.rockspec
new file mode 100644
index 0000000..37eff94
--- /dev/null
+++ b/extras/luacov/luacov-0.2-1.rockspec
@@ -0,0 +1,28 @@
+package = "LuaCov"
+version = "0.2-1"
+source = {
+ url = "http://luaforge.net/frs/download.php/4053/luacov-0.2.tar.gz"
+}
+description = {
+ summary = "Coverage analysis tool for Lua scripts",
+ detailed = [[
+ LuaCov is a simple coverage analysis tool for Lua scripts.
+ When a Lua script is run with the luacov module, it
+ generates a stats file. The luacov command-line script then
+ processes this file generating a report indicating which code
+ paths were not traversed, which is useful for verifying the
+ effectiveness of a test suite.
+ ]],
+ license = "MIT/X11",
+ homepage = "http://luacov.luaforge.net/"
+}
+dependencies = {
+ "lua >= 5.0",
+}
+build = {
+ type = "make",
+ variables = {
+ LUADIR = "$(LUADIR)",
+ BINDIR = "$(BINDIR)"
+ }
+}
diff --git a/extras/luacov/src/bin/luacov b/extras/luacov/src/bin/luacov
new file mode 100755
index 0000000..6a24bc6
--- /dev/null
+++ b/extras/luacov/src/bin/luacov
@@ -0,0 +1,142 @@
+#!/usr/bin/env lua
+
+local luacov = require("luacov.stats")
+
+local data, most_hits = luacov.load()
+
+if not data then
+ print("Could not load stats file "..luacov.statsfile..".")
+ print("Run your Lua program with -lluacov and then rerun luacov.")
+ os.exit(1)
+end
+
+local report = io.open("luacov.report.out", "w")
+
+-- only report on files specified on the command line
+local patterns = {}
+local exclude_patterns = {}
+local exclude_next = false
+for i = 1, #arg do
+ if arg[i] == "-X" then
+ exclude_next = true
+ else
+ if exclude_next then
+ exclude_patterns[#exclude_patterns+1] = arg[i]
+ exclude_next = false
+ else
+ patterns[#patterns+1] = arg[i]
+ end
+ end
+end
+
+local names = {}
+for filename, _ in pairs(data) do
+ if not patterns[1] then
+ table.insert(names, filename)
+ else
+ local path = filename:gsub("/", "."):gsub("%.lua$", "")
+ local include = false
+ for _, p in ipairs(patterns) do
+ if path:match(p) then
+ include = true
+ break
+ end
+ end
+ if include then
+ for _, p in ipairs(exclude_patterns) do
+ if path:match(p) then
+ include = false
+ break
+ end
+ end
+ end
+ if include then
+ table.insert(names, filename)
+ end
+ end
+end
+
+table.sort(names)
+
+local most_hits_length = ("%d"):format(most_hits):len()
+local empty_format = (" "):rep(most_hits_length+1)
+local false_negative_format = ("!%% %dd"):format(most_hits_length)
+local zero_format = ("*"):rep(most_hits_length).."0"
+local count_format = ("%% %dd"):format(most_hits_length+1)
+
+local exclusions =
+{
+ { false, "^#!" }, -- Unix hash-bang magic line
+ { true, "" }, -- Empty line
+ { true, "}" }, -- Just a close-brace
+ { true, "end,?" }, -- Single "end"
+ { true, "else" }, -- Single "else"
+ { true, "repeat" }, -- Single "repeat"
+ { true, "do" }, -- Single "do"
+ { true, "local%s+[%w_,%s]+" }, -- "local var1, ..., varN"
+ { true, "local%s+[%w_,%s]+%s*=" }, -- "local var1, ..., varN ="
+ { true, "local%s+function%s*%([%w_,%.%s]*%)" }, -- "local function(arg1, ..., argN)"
+ { true, "local%s+function%s+[%w_]*%s*%([%w_,%.%s]*%)" }, -- "local function f (arg1, ..., argN)"
+}
+
+local function excluded(line)
+ for _, e in ipairs(exclusions) do
+ if e[1] then
+ if line:match("^%s*"..e[2].."%s*$") or line:match("^%s*"..e[2].."%s*%-%-") then return true end
+ else
+ if line:match(e[2]) then return true end
+ end
+ end
+ return false
+end
+
+for _, filename in ipairs(names) do
+ local filedata = data[filename]
+ local file = io.open(filename, "r")
+ if file then
+ report:write("\n")
+ report:write("==============================================================================\n")
+ report:write(filename, "\n")
+ report:write("==============================================================================\n")
+ local line_nr = 1
+ block_comment, equals = false, ""
+ while true do
+ local line = file:read("*l")
+ if not line then break end
+ local true_line = line
+
+ local new_block_comment = false
+ if not block_comment then
+ local l, equals = line:match("^(.*)%-%-%[(=*)%[")
+ if l then
+ line = l
+ new_block_comment = true
+ end
+ else
+ local l = line:match("%]"..equals.."%](.*)$")
+ if l then
+ line = l
+ block_comment = false
+ end
+ end
+
+ local hits = filedata[line_nr] or 0
+ if block_comment or excluded(line) then
+ if hits > 0 then
+ report:write(false_negative_format:format(hits))
+ else
+ report:write(empty_format)
+ end
+ else
+ if hits == 0 then
+ report:write(zero_format)
+ else
+ report:write(count_format:format(hits))
+ end
+ end
+ report:write("\t", true_line, "\n")
+ if new_block_comment then block_comment = true end
+ line_nr = line_nr + 1
+ end
+ end
+end
diff --git a/extras/luacov/src/luacov.lua b/extras/luacov/src/luacov.lua
new file mode 100644
index 0000000..a44333a
--- /dev/null
+++ b/extras/luacov/src/luacov.lua
@@ -0,0 +1,95 @@
+
+local M = {}
+
+local stats = require("luacov.stats")
+local data = stats.load()
+local statsfile = stats.start()
+M.statsfile = statsfile
+
+local tick = package.loaded["luacov.tick"]
+local ctr = 0
+local luacovlock = os.tmpname()
+
+local booting = true
+local skip = {}
+M.skip = skip
+
+local function on_line(_, line_nr)
+ if tick then
+ ctr = ctr + 1
+ if ctr == 100 then
+ ctr = 0
+ stats.save(data, statsfile)
+ end
+ end
+
+ -- get name of processed file; ignore Lua code loaded from raw strings
+ local name = debug.getinfo(2, "S").source
+ if not name:match("^@") then
+ return
+ end
+ name = name:sub(2)
+
+ -- skip 'luacov.lua' in coverage report
+ if booting then
+ skip[name] = true
+ booting = false
+ end
+
+ if skip[name] then
+ return
+ end
+
+ local file = data[name]
+ if not file then
+ file = {max=0}
+ data[name] = file
+ end
+ if line_nr > file.max then
+ file.max = line_nr
+ end
+ file[line_nr] = (file[line_nr] or 0) + 1
+end
+
+local function on_exit()
+ os.remove(luacovlock)
+ stats.save(data, statsfile)
+ stats.stop(statsfile)
+end
+
+local function init()
+ if not tick then
+ M.on_exit_trick = io.open(luacovlock, "w")
+ debug.setmetatable(M.on_exit_trick, { __gc = on_exit } )
+ end
+
+ debug.sethook(on_line, "l")
+
+ local rawcoroutinecreate = coroutine.create
+ coroutine.create = function(...)
+ local co = rawcoroutinecreate(...)
+ debug.sethook(co, on_line, "l")
+ return co
+ end
+ coroutine.wrap = function(...)
+ local co = rawcoroutinecreate(...)
+ debug.sethook(co, on_line, "l")
+ return function()
+ local r = { coroutine.resume(co) }
+ if not r[1] then
+ error(r[2])
+ end
+ return unpack(r, 2)
+ end
+ end
+
+ local rawexit = os.exit
+ os.exit = function(...)
+ on_exit()
+ rawexit(...)
+ end
+end
+
+init()
+
+return M
diff --git a/extras/luacov/src/luacov/stats.lua b/extras/luacov/src/luacov/stats.lua
new file mode 100644
index 0000000..5390c75
--- /dev/null
+++ b/extras/luacov/src/luacov/stats.lua
@@ -0,0 +1,73 @@
+
+local M = {}
+
+local statsfile = "luacov.stats.out"
+local stats
+
+function M.load()
+ local data, most_hits = {}, 0
+ stats = io.open(statsfile, "r")
+ if not stats then
+ return data
+ end
+ while true do
+ local nlines = stats:read("*n")
+ if not nlines then
+ break
+ end
+ local skip = stats:read(1)
+ if skip ~= ":" then
+ break
+ end
+ local filename = stats:read("*l")
+ if not filename then
+ break
+ end
+ data[filename] = {
+ max=nlines
+ }
+ for i = 1, nlines do
+ local hits = stats:read("*n")
+ if not hits then
+ break
+ end
+ local skip = stats:read(1)
+ if skip ~= " " then
+ break
+ end
+ if hits > 0 then
+ data[filename][i] = hits
+ most_hits = math.max(most_hits, hits)
+ end
+ end
+ end
+ stats:close()
+ return data, most_hits
+end
+
+function M.start()
+ return io.open(statsfile, "w")
+end
+
+function M.stop(stats)
+ stats:close()
+end
+
+function M.save(data, stats)
+ stats:seek("set")
+ for filename, filedata in pairs(data) do
+ local max = filedata.max
+ stats:write(max, ":", filename, "\n")
+ for i = 1, max do
+ local hits = filedata[i]
+ if not hits then
+ hits = 0
+ end
+ stats:write(hits, " ")
+ end
+ stats:write("\n")
+ end
+ stats:flush()
+end
+
+return M
diff --git a/extras/luacov/src/luacov/tick.lua b/extras/luacov/src/luacov/tick.lua
new file mode 100644
index 0000000..624cae3
--- /dev/null
+++ b/extras/luacov/src/luacov/tick.lua
@@ -0,0 +1,7 @@
+
+--- Load luacov using this if you want it to periodically
+-- save the stats file. This is useful if your script is
+-- a daemon (ie, does not properly terminate.)
+module("luacov.tick", package.seeall)
+
+require("luacov")
diff --git a/lib/supple.lua b/lib/supple.lua
new file mode 100644
index 0000000..5fc405b
--- /dev/null
+++ b/lib/supple.lua
@@ -0,0 +1,23 @@
+-- lib/supple.lua
+--
+-- Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine
+--
+-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
+--
+-- For licence terms, see COPYING
+--
+
+local capi = require 'supple.capi'
+
+local _VERSION = 1
+local _ABI = 1
+
+local VERSION = "Supple Version " .. tostring(_VERSION)
+
+return {
+ capi = capi,
+ _VERSION = _VERSION,
+ VERSION = VERSION,
+ _ABI = _ABI,
+ ABI = ABI,
+}
diff --git a/lib/supple/capi.c b/lib/supple/capi.c
new file mode 100644
index 0000000..139cfe6
--- /dev/null
+++ b/lib/supple/capi.c
@@ -0,0 +1,35 @@
+/* supple/lib/supple/capi.c
+ *
+ * Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine - Supple
+ *
+ * Useful C methods for Supple including the userdata partitioning.
+ *
+ * Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
+ *
+ * For licence terms, see COPYING
+ *
+ */
+
+#include <lua.h>
+#include <lauxlib.h>
+
+/* The API exposed, increment on backward-compatible changes */
+#define CAPI_API 1
+/* The ABI exposed, increment on backward-incompatible changes */
+#define CAPI_ABI 1
+
+static const struct luaL_Reg
+supple_capi_functions[] = {
+ { NULL, NULL }
+};
+
+int
+luaopen_supple_capi(lua_State *L)
+{
+ luaL_register(L, "supple.capi", supple_capi_functions);
+ lua_pushnumber(L, CAPI_API);
+ lua_setfield(L, -2, "_API");
+ lua_pushnumber(L, CAPI_ABI);
+ lua_setfield(L, -2, "_ABI");
+ return 1;
+}
diff --git a/test/test-supple.capi.lua b/test/test-supple.capi.lua
new file mode 100644
index 0000000..30dbf81
--- /dev/null
+++ b/test/test-supple.capi.lua
@@ -0,0 +1,55 @@
+-- test/test-supple.lua
+--
+-- Supple - Tests for the capi module
+--
+-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
+--
+-- For Licence terms, see COPYING
+--
+
+-- Step one, start coverage
+
+local luacov = require 'luacov'
+
+local capi = require 'supple.capi'
+
+local testnames = {}
+
+local real_assert = assert
+local total_asserts = 0
+local function assert(...)
+ local retval = real_assert(...)
+ total_asserts = total_asserts + 1
+ return retval
+end
+
+local function add_test(suite, name, value)
+ rawset(suite, name, value)
+ testnames[#testnames+1] = name
+end
+
+local suite = setmetatable({}, {__newindex = add_test})
+
+function suite.capi_has_api()
+ assert(capi._API, "No _API found in the CAPI")
+end
+
+function suite.capi_has_abi()
+ assert(capi._ABI, "No _ABI found in the CAPI")
+end
+
+local count_ok = 0
+for _, testname in ipairs(testnames) do
+-- print("Run: " .. testname)
+ local ok, err = xpcall(suite[testname], debug.traceback)
+ if not ok then
+ print(err)
+ print()
+ else
+ count_ok = count_ok + 1
+ end
+end
+
+print(tostring(count_ok) .. "/" .. tostring(#testnames) .. " [" .. tostring(total_asserts) .. "] OK")
+
+os.exit(count_ok == #testnames and 0 or 1)
diff --git a/test/test-supple.lua b/test/test-supple.lua
new file mode 100644
index 0000000..1053b87
--- /dev/null
+++ b/test/test-supple.lua
@@ -0,0 +1,52 @@
+-- test/test-supple.lua
+--
+-- Supple - Tests for the core module
+--
+-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
+--
+-- For Licence terms, see COPYING
+--
+
+-- Step one, start coverage
+
+local luacov = require 'luacov'
+
+local supple = require 'supple'
+local capi = require 'supple.capi'
+
+local testnames = {}
+
+local real_assert = assert
+local total_asserts = 0
+local function assert(...)
+ local retval = real_assert(...)
+ total_asserts = total_asserts + 1
+ return retval
+end
+
+local function add_test(suite, name, value)
+ rawset(suite, name, value)
+ testnames[#testnames+1] = name
+end
+
+local suite = setmetatable({}, {__newindex = add_test})
+
+function suite.capi_passed()
+ assert(supple.capi == capi, "Supple's capi entry is not supple.capi")
+end
+
+local count_ok = 0
+for _, testname in ipairs(testnames) do
+-- print("Run: " .. testname)
+ local ok, err = xpcall(suite[testname], debug.traceback)
+ if not ok then
+ print(err)
+ print()
+ else
+ count_ok = count_ok + 1
+ end
+end
+
+print(tostring(count_ok) .. "/" .. tostring(#testnames) .. " [" .. tostring(total_asserts) .. "] OK")
+
+os.exit(count_ok == #testnames and 0 or 1)