aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/all.lua4
-rw-r--r--test/inet.lua118
-rw-r--r--test/inet_set.lua73
-rw-r--r--test/init.lua163
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