tests-clean doc-clean bench-clean
doc: doc-html
lint:
- luacheck --codes .
+ luacheck --codes --formatter TAP .
+coverage: $(wildcard */*/luacov.stats.out)
+ @echo "# C coverage in gcov.c.info"
+ @lcov --no-external --capture --directory . --output-file gcov.c.info > /dev/null
+ @if [ ! -z "$^" ]; then \
+ echo "# Lua coverage in luacov.stats.out and gcov.lua.info"; \
+ cat $^ > luacov.stats.out; \
+ ./scripts/luacov_to_info.lua $^ > gcov.lua.info; \
+ lcov --add-tracefile gcov.c.info --add-tracefile gcov.lua.info --output-file gcov.total.info; \
+ else \
+ lcov --add-tracefile gcov.c.info --output-file gcov.total.info; \
+ fi
+
.PHONY: all install check clean doc info
# Options
"`libprotobuf-c`_ 1.0+", "``modules/dnstap``", "C bindings for Protobuf."
"libfstrm_ 0.2+", "``modules/dnstap``", "Frame Streams data transport protocol."
"luacheck_", "``lint``", "Syntax and static analysis checker for Lua."
+ "luacov_", "``check-config``", "Code coverage analysis for Lua modules."
.. [#] Requires C99, ``__attribute__((cleanup))`` and ``-MMD -MP`` for dependency file generation. GCC, Clang and ICC are supported.
.. [#] You can use variables ``<dependency>_CFLAGS`` and ``<dependency>_LIBS`` to configure dependencies manually (i.e. ``libknot_CFLAGS`` and ``libknot_LIBS``).
The project can be built with code coverage tracking using the ``COVERAGE=1`` variable.
+The `make coverage` target gathers both gcov code coverage for C files, and luacov_ code coverage for Lua files and merges it for analysis. It requires lcov_ to be installed.
+
+.. code-block:: bash
+
+ $ make coverage
+
Running unit and integration tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. _libprotobuf-c: https://github.com/protobuf-c/protobuf-c/wiki
.. _libfstrm: https://github.com/farsightsec/fstrm
.. _luacheck: http://luacheck.readthedocs.io
+.. _luacov: https://keplerproject.github.io/luacov/
+.. _lcov: http://ltp.sourceforge.net/coverage/lcov.php
.. _DESTDIR: https://www.gnu.org/prep/standards/html_node/DESTDIR.html
--- /dev/null
+#!/usr/bin/env luajit
+
+local luacov = require('luacov')
+local ReporterBase = require('luacov.reporter').ReporterBase
+local LcovReporter = setmetatable({}, ReporterBase)
+LcovReporter.__index = LcovReporter
+
+function LcovReporter:on_new_file(filename)
+ self.finfo = self.current_files[filename] or {name=filename, coverage={}}
+end
+
+function LcovReporter:on_mis_line(_, lineno, _)
+ self.finfo.coverage[lineno] = self.finfo.coverage[lineno] or 0
+end
+
+function LcovReporter:on_hit_line(_, lineno, _, hits)
+ self.finfo.coverage[lineno] = (self.finfo.coverage[lineno] or 0) + hits
+end
+
+function LcovReporter:on_end_file()
+ self.current_files[self.finfo.name] = self.finfo
+ self.finfo = nil
+end
+
+-- Write out results in lcov format
+local function write_lcov_info(files)
+ for fname, finfo in pairs(files) do
+ local instrumented, nonzero = 0, 0
+ print('TN:')
+ print(string.format('SF:%s', fname))
+ for i, hits in pairs(finfo.coverage) do
+ print(string.format('DA:%d,%d', i - 1, hits))
+ instrumented = instrumented + 1
+ if hits > 0 then
+ nonzero = nonzero + 1
+ end
+ end
+ print(string.format('LH:%d', nonzero))
+ print(string.format('LF:%d', instrumented))
+ print('end_of_record')
+ end
+end
+
+-- Accumulate total coverage
+local all_files = {}
+for _, fname in ipairs(arg) do
+ local conf = luacov.load_config()
+ conf.statsfile = fname
+ local reporter = assert(LcovReporter:new(conf))
+ reporter.current_files = all_files
+ reporter:run()
+ reporter:close()
+end
+
+-- Write results
+write_lcov_info(all_files)
\ No newline at end of file