From 142d1bc7549f04c29d4ca78ee5f796562a533435 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Thu, 23 Aug 2012 22:02:42 +0100 Subject: TEST: Initial test suite, plus coverage code --- .gitignore | 2 + Makefile | 44 +++++++ extras/luacov/Makefile | 26 +++++ extras/luacov/README.md | 79 +++++++++++++ extras/luacov/doc/doc.css | 223 ++++++++++++++++++++++++++++++++++++ extras/luacov/doc/index.html | 200 ++++++++++++++++++++++++++++++++ extras/luacov/doc/license.html | 113 ++++++++++++++++++ extras/luacov/doc/luacov.png | Bin 0 -> 8420 bytes extras/luacov/luacov-0.2-1.rockspec | 28 +++++ extras/luacov/src/bin/luacov | 142 +++++++++++++++++++++++ extras/luacov/src/luacov.lua | 95 +++++++++++++++ extras/luacov/src/luacov/stats.lua | 73 ++++++++++++ extras/luacov/src/luacov/tick.lua | 7 ++ test/test-clod.lua | 51 +++++++++ 14 files changed, 1083 insertions(+) create mode 100644 Makefile create mode 100644 extras/luacov/Makefile create mode 100644 extras/luacov/README.md create mode 100644 extras/luacov/doc/doc.css create mode 100644 extras/luacov/doc/index.html create mode 100644 extras/luacov/doc/license.html create mode 100644 extras/luacov/doc/luacov.png create mode 100644 extras/luacov/luacov-0.2-1.rockspec create mode 100755 extras/luacov/src/bin/luacov create mode 100644 extras/luacov/src/luacov.lua create mode 100644 extras/luacov/src/luacov/stats.lua create mode 100644 extras/luacov/src/luacov/tick.lua create mode 100644 test/test-clod.lua diff --git a/.gitignore b/.gitignore index b25c15b..f1cc253 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ *~ +luacov.report.out +luacov.stats.out diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e5be3ad --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ +all: test + +MODULES := clod +LUA_VER := 5.1 + +INST_BASE := /usr/local +INST_ROOT := $(DESTDIR)$(INST_BASE)/share/lua/$(LUA_VER) + +MOD_FILES := $(patsubst %,%.lua,$(subst .,/,$(MODULES))) + +install: + for MOD in $(sort $(MOD_FILES)); do \ + cp lib/$${MOD} $(INST_ROOT)/$${MOD}; \ + done + +LUA := LUA_PATH="$(shell pwd)/lib/?.lua;$(shell pwd)/extras/luacov/src/?.lua;;" lua$(LUA_VER) + +clean: + $(RM) luacov.report.out luacov.stats.out + +distclean: clean + find . -name "*~" -delete + +.PHONY: example +example: + $(LUA) example/simple-config-reader.lua + $(LUA) example/change-setting.lua + $(LUA) example/config-passthru.lua + +.PHONY: test +test: + @$(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. $(MODULES); \ + exit $$ERR + +.PHONY: interactive +interactive: + $(LUA) -e'clod=require"clod"' -i 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 @@ + + + + LuaCov - Coverage analysis for Lua scripts + + + + + + + +
+ +
+ +
LuaCov
+
Coverage analysis for Lua scripts
+
+ +
+ + + +
+ +

Overview

+ +

+LuaCov is a simple coverage analyzer for Lua +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 uses the same license as Lua. +

+ +

Download

+ +

+LuaCov can be downloaded from its +LuaForge page. +

+ +

+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, +just modify the first line of xavante_start.lua so it reads: +

+ +
+#!/usr/bin/env lua -lluacov.tick +
+ +

History

+ +
+
0.1 [July 16, 2007]
+
+
    +
  • Initial release.
  • +
+
+
+ +

Credits

+ +

+LuaCov was designed and implemented by Hisham Muhammad as a tool for +testing LuaRocks. +

+ +

Contact

+ +

+For more information please +contact us. Comments are welcome! +

+ +
+ +
+ +
+

+ Valid XHTML 1.0!

+
+ +
+ + + 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 @@ + + + + LuaCov - Coverage analysis for Lua scripts + + + + + + +
+ +
+ +
LuaCov
+
Coverage analysis for Lua scripts
+
+ +
+ + + +
+ +

License

+ +

+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 Open Source software. +Its licenses are compatible with GPL. +LuaCov is not in the public domain. The legal details are below. +

+ +

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

+ +

+LuaCov is designed and implemented by Hisham Muhammad. +The implementation is not derived from licensed software. +

+ +
+ +

Copyright (c) 2007 Hisham Muhammad.

+ +

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

+ +
+ +
+ +
+

+ Valid XHTML 1.0!

+
+ +
+ + + diff --git a/extras/luacov/doc/luacov.png b/extras/luacov/doc/luacov.png new file mode 100644 index 0000000..1cf37b7 Binary files /dev/null and b/extras/luacov/doc/luacov.png 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/test/test-clod.lua b/test/test-clod.lua new file mode 100644 index 0000000..b453dba --- /dev/null +++ b/test/test-clod.lua @@ -0,0 +1,51 @@ +-- test/test-clod.lua +-- +-- Configuration languge organised (by) dots. +-- +-- Copyright 2012 Daniel Silverstone +-- +-- For Licence terms, see COPYING +-- + +-- Step one, start coverage + +local luacov = require 'luacov' + +local clod = require 'clod' + +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.test_parse_empty() + local conf = assert(clod.parse("")) +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) -- cgit v1.2.1