diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/all.lua | 4 | ||||
-rw-r--r-- | test/inet.lua | 118 | ||||
-rw-r--r-- | test/inet_set.lua | 73 | ||||
-rw-r--r-- | test/init.lua | 163 |
4 files changed, 358 insertions, 0 deletions
diff --git a/test/all.lua b/test/all.lua new file mode 100644 index 0000000..4ee056a --- /dev/null +++ b/test/all.lua @@ -0,0 +1,4 @@ +local all = require('test').new() +all:depend('inet') +all:depend('inet_set') +return all diff --git a/test/inet.lua b/test/inet.lua new file mode 100644 index 0000000..43432cc --- /dev/null +++ b/test/inet.lua @@ -0,0 +1,118 @@ +local inet = require 'inet' +local test = require 'test' + +local function parse(addr) + local ret, err = inet(addr) + assert(ret, (err or '')..' '..addr) + return ret, err +end + +local function dontparse(...) + test.fail(parse, ...) +end + +return test.new(function() + -- parsing + parse('1:2:3:4:5:6:7:8') + parse('::1/33') + parse('1::/33') + parse('1:2:3:4:5:6:7::/33') + parse('::2:3:4:5:6:7:8/33') + parse('2a03:5440:1010::80/64') + dontparse('::1::/33') + dontparse('::1/33a') + dontparse('::1/150') + dontparse('1:2:3:4::2:3:4:5:6:7:8/33') + assert(tostring(parse('1:0:0:1::/64') * 1) == '1:0:0:2::/64') + assert(tostring(parse('1::/64') * 5 / 32 * 3) == '1:3:0:5::/32') + assert(tostring(parse('5::64') / 32 * -3) == '4:fffd::64/32') + assert(tostring(parse('2::/32') ^ 1) == '2::/33') + assert(tostring(parse('2::/32') ^ -1) == '2::/31') + assert(tostring(parse('2::/128') * 5) == '2::5') + assert(tostring(parse('2::/49') - 1) + == '1:ffff:ffff:ffff:ffff:ffff:ffff:ffff/49') + assert(tostring(parse('2::/49') - 1 + 2) == '2::1/49') + assert(tostring(parse('1:ffff:ffff:fe00::/56') * 2) == '2::/56') + assert(tostring(parse('1:ffff:ffff:fe00::/56') * 2 * -2) + == '1:ffff:ffff:fe00::/56') + local ip = inet('10.0.0.0/33') + assert(ip == nil) + + local ip = inet('10.0.0.0/24') + assert(type(ip) == 'table') + assert(#ip == 24, 'incorrect netmask') + assert(tostring(ip) == '10.0.0.0/24', 'not human readable') + + assert(inet('10.0.0.0/32') == inet('10.0.0.0')) + assert(inet('10.0.0.0/31') ~= inet('10.0.0.0')) + + assert(tostring(ip+1) == '10.0.0.1/24', 'ip adding is broken') + assert(tostring(ip+9-1) == '10.0.0.8/24', 'ip subtract is broken') + assert(tostring(ip*1) == '10.0.1.0/24', 'ip multiplification is broken') + assert(tostring(ip/8) == '10.0.0.0/8', 'ip division is broken') + assert(tostring(ip^1) == '10.0.0.0/25', 'ip power is broken') + + -- test inet4.__lt + assert(inet('10.0.0.0/24') > inet('10.0.0.0/30'), 'inet less than is broken') + assert(not (inet('10.0.0.0/30') > inet('10.0.0.0/30')), 'inet less than is broken') + assert(inet('10.0.0.0/30') >= inet('10.0.0.0/30'), 'inet less than is broken') + assert(inet('10.0.0.0/30') <= inet('10.0.0.0/30'), 'inet less than is broken') + assert(inet('10.0.0.0/30') < inet('10.0.0.0/24'), 'inet less than is broken') + assert(not (inet('10.0.0.0/24') < inet('10.0.0.0/30')), 'inet less than is broken') + assert(not (inet('10.0.0.0/30') < inet('10.0.0.0/30')), 'inet less than is broken') + assert(not (inet('20.0.0.0/30') < inet('10.0.0.0/24')), 'inet less than is broken') + + -- test inet4.__le + assert(inet('10.0.1.2/24') <= inet('10.0.0.0/16')) + assert(not (inet('10.0.1.0/24') <= inet('10.0.0.0/24'))) + + assert(inet('127.0.0.1/8'):netmask() == inet('255.0.0.0')) + + + -- test inet*.__eq + assert(inet('10.0.0.0/30') == inet('10.0.0.0/30'), 'inet4 eq is broken') + assert(inet('10.0.1.0/30') ~= inet('10.0.0.0/30'), 'inet4 eq is broken') + assert(inet('10.0.0.0/31') ~= inet('10.0.0.0/30'), 'inet4 eq is broken') + assert(inet('::1') == inet('::1'), 'inet6 eq is broken') + assert(inet('::1') ~= inet('::2'), 'inet6 eq is broken') + assert(inet('::1/64') ~= inet('::1/56'), 'inet6 eq is broken') + + -- test inet*.ipstring + assert((ip+1):ipstring() == '10.0.0.1', 'ip4 string is broken') + assert(inet('::1/64'):ipstring() == '::1', 'ip6 string is broken') + + -- test inet*.network + assert(inet('10.0.0.1/30'):network() == inet('10.0.0.0/30'), 'inet4.network() is broken') + assert(inet('1::2/64'):network() == inet('1::/64'), 'inet6.network() is broken') + local ip = inet('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/62') + assert((ip/22):network() == inet('ffff:fc00::/22'), 'inet6.network() is broken') + assert((ip/27):network() == inet('ffff:ffe0::/27'), 'inet6.network() is broken') + + --- test inet4:flip + assert(inet('10.0.0.1/24'):flip() == inet('10.0.1.1/24'), 'inet.flip() is broken') + assert(inet('10.0.0.0/24'):flip() == inet('10.0.1.0/24'), 'inet.flip() is broken') + assert(inet('10.0.0.0/24'):flip():flip() == inet('10.0.0.0/24'), 'inet.flip() is broken') + assert(inet('10.20.30.0/24'):flip() == inet('10.20.31.0/24')) + assert(inet('10.20.30.5/24'):flip() == inet('10.20.31.5/24')) + assert(inet('10.20.30.5/32'):flip() == inet('10.20.30.4/32')) + assert(inet('0.0.0.0/0'):flip() == nil) + local ips = { + inet('::'), + inet('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'), + } + assert(inet('::/0'):flip() == nil) + assert(inet('::1/32'):flip() == inet('0:1::1/32')) + assert(inet('::1/48'):flip() == inet('0:0:1::1/48')) + for i=1,#ips do + local ip = ips[i] + for j=1,128 do + local foo = ip / j + local bar = foo:flip() + assert(foo ~= bar) + assert(foo == bar:flip()) + end + end + + -- TODO inet6.__le + -- TODO inet6.__eq +end) diff --git a/test/inet_set.lua b/test/inet_set.lua new file mode 100644 index 0000000..044de09 --- /dev/null +++ b/test/inet_set.lua @@ -0,0 +1,73 @@ +local inet = require 'inet' +local inet_set = require 'inet.set' +local test = require 'test' +local inspect = require 'inspect' + +function agg_set(a, b) + inet_set.aggregate(a) + assert(#a == #b, 'wrong set size') + for i=1,#a do + --print(a[i], b[i]) + assert(a[i] == b[i], 'unexpected network') + end +end + + +return test.new(function() + local ip = inet('10.0.0.0/24') + + agg_set({ + inet('10.0.0.0/24'), + inet('10.0.1.0/24'), + }, { + inet('10.0.0.0/23'), + }) + + agg_set({ + inet('10.0.1.0/24'), + inet('10.0.2.0/24'), + }, { + inet('10.0.1.0/24'), + inet('10.0.2.0/24'), + }) + + agg_set({ + inet('10.0.1.0/24'), + inet('10.0.2.0/24'), + inet('10.0.3.0/24'), + inet('10.0.4.0/24'), + }, { + inet('10.0.1.0/24'), + inet('10.0.2.0/23'), + inet('10.0.4.0/24'), + }) + + agg_set({ + inet('10.0.2.1/24'), + inet('10.0.4.0/24'), + inet('10.0.1.0/24'), + inet('10.0.3.0/24'), + }, { + inet('10.0.2.0/23'), + inet('10.0.4.0/24'), + inet('10.0.1.0/24'), + }) + + agg_set({ + inet('10.0.1.1/24'), + inet('10.0.3.2/24'), + inet('10.0.2.3/24'), + inet('10.0.4.4/24'), + }, { + inet('10.0.1.0/24'), + inet('10.0.2.0/23'), + inet('10.0.4.0/24'), + }) + + agg_set({ + inet('::/32'), + inet('0:1::/32'), + }, { + inet('::/31'), + }) +end) diff --git a/test/init.lua b/test/init.lua new file mode 100644 index 0000000..0a4e05b --- /dev/null +++ b/test/init.lua @@ -0,0 +1,163 @@ +local utils = require 'lem.utils' + +local updatenow = utils.updatenow +local pack = table.pack +local unpack = table.unpack +local format = string.format + +local master + +local function test_assert(v, msg, ...) + if not v then + error(msg or 'assertion failed!', 2) + end + master.assert_cnt = master.assert_cnt + 1 + return v, msg, ... +end + +local function msg_handler(msg) + local trace = debug.traceback(msg, 4) + return trace + --return string.match(trace, '^(.-)\n[^\n]-tester_cut_traceback_here') +end + +local test = {} +test.__index = test + +function test:enter() + self.prev_test = master.activetest + master.activetest = self + self.real_assert = assert + _ENV.assert = test_assert +end + +function test:leave() + master.activetest = self.prev_test + self.prev_test = nil + _ENV.assert = self.real_assert + self.real_assert = nil +end + +function test:depend(t) + if type(t) == 'string' then + t = require('test.'..t) + end + table.insert(self.dependencies, t) +end + +local function tester_cut_traceback_here(self) + local deps = self.dependencies + for i=1,#deps do + local dep = deps[i] + dep:run() + end + if self.test then + self:test() + end +end + +local function tester(...) + -- hack due to the first function called by xpcall + -- not being refered to by name in tracebacks + local ret, msg = tester_cut_traceback_here(...) + return ret, msg +end + +function test:run() + if master == nil then + self:setmaster() + end + if master.have_run[self] then + return self.passed -- TODO return previous result + end + self:enter() + local t1, t2 + t1 = updatenow() + local ret, msg = xpcall(tester, msg_handler, self) + t2 = updatenow() + self.runtime = t2 - t1 + self:leave() + if not ret then + self.error_msg = msg + end + master.have_run[self] = true + self.passed = ret + master.run = master.run + 1 + if ret then + master.passed = master.passed + 1 + else + table.insert(master.failed, self) + end + return ret +end + +function test:setmaster() + assert(master == nil, 'master already set') + master = { + test = self, + assert_cnt = 0, + have_run = {}, + passed = 0, + run = 0, + failed = {}, + } +end + +function test:reset() + if self ~= master.test then + error('you can only run reset on current master task') + end + master = nil +end + +local function new_test(func) + local src = debug.getinfo(func or 2, 'S').short_src + return setmetatable({ + test = func, + dependencies = {}, + source = src, + }, test) +end + +function test:stats() + if self ~= master.test then + error('you can only run stats on current master task') + end + local run, passed, asserts = master.run, master.passed, master.assert_cnt + if run == passed then + print(format('%d/%d All tests passed, %d assertions in %.3fs', + run, passed, asserts, master.test.runtime)) + else + print(format('%d/%d %d failed', run, passed, run-passed)) + end +end + +function test:failed() + if self ~= master.test then + error('you can only run stats on current master task') + end + for i=1,#master.failed do + local t = master.failed[i] + print(t.error_msg) + end +end + +local function assert_fail(cb, ...) + local ret = pack(pcall(cb, ...)) + if ret[1] then assert(false, 'doomed function succeeded') end + return unpack(ret) +end + +local M = {} + +function M.test() + local index = require 'test.all' + index:run() + index:stats() + index:failed() +end + +M.new = new_test +M.fail = assert_fail + +return M |