Module:Format ISBN/data/testcases

-- Unit tests for Module:Format ISBN/data. Click talk page to run tests. -- Example usage: --  -- Console example: --  mw.log(p.run_tests(mw.getCurrentFrame))

require('Module:No globals')

local p = require('Module:UnitTests')

local _data = nil

local function _table_length(table_) local count = 0 for _ in ipairs(table_) do		count = count + 1 end return count end

local _test_cases, _test_case_failures = 0, 0

function p:_assert_equals(name, actual, expected) _test_cases = _test_cases + 1 if actual ~= expected then self:equals(name, actual, expected) _test_case_failures = _test_case_failures + 1 end end

function p:_assert_true(name, actual) self:_assert_equals(name, actual, true) end

local _exec_depth = 0

function p:_exec(function_) if _exec_depth == 0 then _test_cases, _test_case_failures = 0, 0 end local cases, failures = _test_cases, _test_case_failures _exec_depth = _exec_depth + 1 local status, error_ = pcall(function_) _exec_depth = _exec_depth - 1 return status, error_, _test_cases - cases, _test_case_failures - failures end

function p:_catch(name, function_, threshold) threshold = threshold or 0 local status, error_, cases, failures = self:_exec(function_) local summary = name .. ", "				.. cases .. " test cases, " .. failures .. " failed" if status then local result = failures == 0 and "pass" or "fail" if result == "fail" or (_exec_depth <= threshold and cases > 0) then self:equals(summary, result, "pass") end else self:equals(summary, "fail (aborted)", "pass") self:equals(name .. ": aborted", error_, "(no error)") end end

function p:_inner_catch(name, function_) self:_catch(name, function_, _exec_depth) end

function p:test___framework_functions self:_catch("test___framework_functions", function		self:_assert_equals("_exec_depth == 1", _exec_depth, 1)		self:_assert_equals("_test_cases == 1", _test_cases, 1)		self:_assert_equals("_test_case_failures == 0", _test_case_failures, 0)

self:_assert_equals("_test_cases == 3", _test_cases, 3) self:_catch("framework_recursion_test", function			self:_assert_equals("_exec_depth == 2", _exec_depth, 2)			self:_assert_equals("_test_cases == 5", _test_cases, 5)		end) self:_inner_catch("framework_inner_test", function			self:_assert_equals("_exec_depth == 2", _exec_depth, 2)			self:_assert_equals("_test_cases == 7", _test_cases, 7)		end) self:_assert_equals("_test_cases == 8", _test_cases, 8) self:_assert_equals("_test_cases == 9", _test_cases, 9) self:_assert_equals("_test_case_failures == 0", _test_case_failures, 0)

self:_assert_true("_table_length({}) == 0", _table_length({}) == 0) self:_assert_equals("_table_length({1}) == 1", _table_length({1}), 1) self:_assert_equals("_table_length({1, 2}) == 2", _table_length({1, 2}), 2) self:_assert_equals("_table_length({1, 2, 3}) == 3", _table_length({1, 2, 3}), 3) end) end

function p:test__initial_data_load self:_catch("test__initial_data_load", function		_data = mw.loadData('Module:Format ISBN/data')		self:_assert_true("_data ~= nil", _data ~= nil)		self:_assert_equals("type(_data)", type(_data), "table")	end) end

function p:test_main_registration_groups_exist self:_catch("test_main_registration_groups_exist", function		self:_assert_equals("type(_data[\"978-0\"])", type(_data["978-0"]), "table")		self:_assert_equals("type(_data[\"978-1\"])", type(_data["978-1"]), "table")		self:_assert_equals("type(_data[\"979-8\"])", type(_data["979-8"]), "table")	end) end

function p:_test_range_shape(locus, digits, range) self:_catch("_test_range_shape", function		self:_assert_equals(locus .. ": type(range)", type(range), "table")		self:_assert_equals(locus .. ": #range == 2", _table_length(range), 2)

self:_assert_equals(locus .. ": type(range[1])", type(range[1]), "number") self:_assert_equals(locus .. ": type(range[2])", type(range[2]), "number")

local max_ = tonumber(string.rep("9", 8 - digits)) self:_assert_true(locus .. ": range[1] <= " .. max_, range[1] <= max_) self:_assert_true(locus .. ": range[2] <= " .. max_, range[2] <= max_) self:_assert_true(locus .. ": range[2] >= range[1]", range[2] >= range[1]) end) end

function p:_test_entry_shape(locus, entry) self:_catch("_test_entry_shape", function		self:_assert_equals(locus .. ": type(entry)", type(entry), "table")		self:_assert_true(locus .. ": #entry > 1", _table_length(entry) > 1)

self:_assert_equals(locus .. ": type(entry[1])", type(entry[1]), "number") self:_assert_true(locus .. ": entry[1] >= 1", entry[1] >= 1) self:_assert_true(locus .. ": entry[1] <= 7", entry[1] <= 7)

for j, range in ipairs(entry) do			if j > 1 then self:_test_range_shape(locus .. "[" .. j .. "]", entry[1], range) end end end) end

function p:_test_table_shape(prefix) self:_inner_catch("_data[\"" .. tostring(prefix) .. "\"]", function		local locus = "_data[\"" .. prefix .. "\"]"		local pattern = "^97[89][-]%d+$"		self:_assert_equals(locus .. ": type(prefix)", type(prefix), "string")		self:_assert_equals(locus .. ": pattern(prefix)", prefix:match(pattern), prefix)		self:_assert_equals(locus .. ": type(_data[prefix])", type(_data[prefix]), "table")

for i, entry in ipairs(_data[prefix]) do self:_test_entry_shape(locus .. "[" .. i .. "]", entry) end end) end

function p:test_all_tables_for_shape_validity self:_catch("test_all_tables_for_shape_validity", function		for prefix in pairs(_data) do			self:_assert_true("prefix ~= nil", prefix ~= nil)			self:_test_table_shape(prefix)		end	end) end

function p:_test_build_allocations_table local allocations = {} self:_catch("_test_build_allocations_table", function		for prefix, ranges in pairs(_data) do			local prefix_ = prefix:gsub("[-]", "")			local exponent = 12 - prefix_:len			local basis = tonumber(prefix_) * 10 ^ exponent

for i, entry in ipairs(ranges) do				local digits = entry[1] local power = 10 ^ (exponent - (8 - digits)) for j, range in ipairs(entry) do					if j > 1 then local start = basis + range[1] * power local finish = basis + range[2] * power + power - 1 local locus = "_data[\"" .. prefix .. "\"][" .. i .. "][" .. j .. "]"						table.insert(allocations, {start, finish, locus}) end end end end table.sort(allocations, function(a, b) return a[1] < b[1] end) end)	return allocations end

function p:test_for_range_overlaps self:_catch("test_for_range_overlaps", function		local allocations = self:_test_build_allocations_table(_data)		for i, range in ipairs(allocations) do			if i > 1 then				local start, locus = range[1], range[3]				local preceding = allocations[i - 1]				local preceding_end, preceding_locus = preceding[2], preceding[3]				local is_disjoint = preceding_end < start				local name = preceding_locus .. " < " .. locus							.. " (" .. preceding_end .. " < " .. start .. ")"				self:_assert_true(name, is_disjoint)			end		end	end) end

return p