Quantcast

Split out unit tests in OvaleTimeSpan into a separate file.

Johnny C. Lam [07-13-14 - 11:30]
Split out unit tests in OvaleTimeSpan into a separate file.

git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@1535 d5049fe3-3747-40f7-a4b5-f36d6801af5f
Filename
OvaleTimeSpan.lua
tests/timespan.t
diff --git a/OvaleTimeSpan.lua b/OvaleTimeSpan.lua
index b960f4d..196c9bd 100644
--- a/OvaleTimeSpan.lua
+++ b/OvaleTimeSpan.lua
@@ -459,335 +459,3 @@ function OvaleTimeSpan:Union(B, result)
 	return OvaleTimeSpan(result)
 end
 --</public-static-methods>
-
-do
-	local testFunction = {}
-
-	testFunction[#testFunction + 1] = function()
-		local A = OvaleTimeSpan(1, 2, 3, 4)
-		local atTime = 0
-		if A:HasTime(atTime) then
-			print(string.format("%s should not contain %s", tostring(A), tostring(atTime)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A = OvaleTimeSpan(1, 2, 3, 4)
-		local atTime = 1
-		if not A:HasTime(atTime) then
-			print(string.format("%s should contain %s", tostring(A), tostring(atTime)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(1, 2, 3, 4)
-		local expected = OvaleTimeSpan(0, 1, 2, 3, 4, math.huge)
-		local result = A:Complement()
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan()
-		local expected = OvaleTimeSpan(0, math.huge)
-		local result = A:Complement()
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(0, math.huge)
-		local expected = OvaleTimeSpan()
-		local result = A:Complement()
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(1, 2)
-		local B        = OvaleTimeSpan(3, 4)
-		local expected = OvaleTimeSpan(1, 2, 3, 4)
-
-		local result = A:Union(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(3, 4)
-		local B        = OvaleTimeSpan(1, 2)
-		local expected = OvaleTimeSpan(1, 2, 3, 4)
-
-		local result = A:Union(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(1, 2, 3, 4)
-		local B        = OvaleTimeSpan(2, 3, 4, 5)
-		local expected = OvaleTimeSpan(1, 5)
-
-		local result = A:Union(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(2, 3, 4, 5)
-		local B        = OvaleTimeSpan(1, 2, 3, 4)
-		local expected = OvaleTimeSpan(1, 5)
-
-		local result = A:Union(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(1, 2)
-		local B        = OvaleTimeSpan(2, 3, 4, 5)
-		local expected = OvaleTimeSpan(1, 3, 4, 5)
-
-		local result = A:Union(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(2, 3, 4, 5)
-		local B        = OvaleTimeSpan(1, 2)
-		local expected = OvaleTimeSpan(1, 3, 4, 5)
-
-		local result = A:Union(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(2, 3, 4, 5)
-		local B        = OvaleTimeSpan(1, 4)
-		local expected = OvaleTimeSpan(1, 5)
-
-		local result = A:Union(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(1, 5, 6, 10, 15, 17, 20, 30, 99, 101)
-		local B        = OvaleTimeSpan(2, 3, 7, 11, 14, 18, 21, 29, 42, 47, 99, 101)
-		local expected = OvaleTimeSpan(1, 5, 6, 11, 14, 18, 20, 30, 42, 47, 99, 101)
-
-		local result = A:Union(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(1, 5, 6, 10, 15, 17, 20, 30, 99, 101)
-		local B        = OvaleTimeSpan(2, 3, 7, 11, 14, 18, 21, 29, 42, 47, 101, 105)
-		local expected = OvaleTimeSpan(1, 5, 6, 11, 14, 18, 20, 30, 42, 47, 99, 105)
-
-		local result = A:Union(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A = OvaleTimeSpan()
-		local B = OvaleTimeSpan()
-
-		local a = math.floor(math.random(1, 10))
-		local b = math.floor(math.random(1, 10))
-
-		for i = 1, 20 do
-			local da = math.floor(math.random(1, 10))
-			local db = math.floor(math.random(1, 10))
-			A[i], B[i] = a, b
-			a, b = a + da, b + db
-		end
-
-		--print(string.format("        A: %s", tostring(A)))
-		--print(string.format("        B: %s", tostring(B)))
-
-		local result = A:Union(B)
-		--print(string.format("A union B: %s", tostring(result)))
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan()
-		local B        = OvaleTimeSpan()
-		local expected = OvaleTimeSpan()
-
-		local result = A:Intersect(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(1, 3)
-		local B        = OvaleTimeSpan(2, 4)
-		local expected = OvaleTimeSpan(2, 3)
-
-		local result = A:Intersect(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(1, 3, 4, 6)
-		local B        = OvaleTimeSpan(2, 5)
-		local expected = OvaleTimeSpan(2, 3, 4, 5)
-
-		local result = A:Intersect(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(1, 5, 6, 10, 15, 17, 20, 30, 99, 101)
-		local B        = OvaleTimeSpan(2, 3, 7, 11, 14, 18, 21, 29, 42, 47, 99, 101)
-		local expected = OvaleTimeSpan(2, 3, 7, 10, 15, 17, 21, 29, 99, 101)
-
-		local result = A:Intersect(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(2, math.huge)
-		local B        = OvaleTimeSpan(3, math.huge)
-		local expected = OvaleTimeSpan(3, math.huge)
-
-		local result = A:Intersect(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A            = OvaleTimeSpan(1, 3, 4, 6)
-		local startB, endB = 2, 5
-		local expected     = OvaleTimeSpan(2, 3, 4, 5)
-
-		local result = A:IntersectInterval(startB, endB)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A        = OvaleTimeSpan(1, 3, 4, 6)
-		local B        = OvaleTimeSpan(3, math.huge)
-		local expected = OvaleTimeSpan(4, 6)
-
-		local result = A:Intersect(B)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	testFunction[#testFunction + 1] = function()
-		local A            = OvaleTimeSpan(1, 3, 4, 6)
-		local startB, endB = 3, math.huge
-		local expected     = OvaleTimeSpan(4, 6)
-
-		local result = A:IntersectInterval(startB, endB)
-		if not result:Equals(expected) then
-			print(string.format("  result: %s", tostring(result)))
-			print(string.format("expected: %s", tostring(expected)))
-			return false
-		end
-		return true
-	end
-
-	local function TestDriver()
-		for i, func in ipairs(testFunction) do
-			local result = func()
-			local resultString = result and "true" or "FAILED!"
-			print(string.format("Test %d: %s", i, resultString))
-			if not result then
-				break
-			end
-		end
-	end
-	--TestDriver()
-end
diff --git a/tests/timespan.t b/tests/timespan.t
new file mode 100644
index 0000000..89c2a66
--- /dev/null
+++ b/tests/timespan.t
@@ -0,0 +1,362 @@
+--[[------------------------------
+	Load fake WoW environment.
+--]]------------------------------
+local root = "../"
+do
+	dofile(root .. "WoWAPI.lua")
+	WoWAPI:Initialize("Ovale")
+	WoWAPI:ExportSymbols()
+end
+
+--[[-----------------------------------------------
+	Fake loading via file order from Ovale.toc.
+--]]-----------------------------------------------
+do
+	local addonFiles = {
+		"Ovale.lua",
+		"OvaleTimeSpan.lua",
+	}
+	for _, file in ipairs(addonFiles) do
+		WoWAPI:LoadAddonFile(file, root)
+	end
+end
+
+local OvaleTimeSpan = Ovale.OvaleTimeSpan
+local format = string.format
+local tconcat = table.concat
+local tinsert = table.insert
+
+local tests = {}
+
+tests[#tests + 1] = function()
+	local A = OvaleTimeSpan(1, 2, 3, 4)
+	local atTime = 0
+
+	local msg = format("%s should not contain %s", tostring(A), tostring(atTime))
+	if A:HasTime(atTime) then
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A = OvaleTimeSpan(1, 2, 3, 4)
+	local atTime = 1
+
+	local msg = format("%s should contain %s", tostring(A), tostring(atTime))
+	if not A:HasTime(atTime) then
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(1, 2, 3, 4)
+	local expected = OvaleTimeSpan(0, 1, 2, 3, 4, math.huge)
+
+	local msg = { format("complement of %s", tostring(A)) }
+	local result = A:Complement()
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan()
+	local expected = OvaleTimeSpan(0, math.huge)
+
+	local msg = { "complement of empty set should be the universe" }
+	local result = A:Complement()
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(0, math.huge)
+	local expected = OvaleTimeSpan()
+
+	local msg = { "complement of the universe should be the empty set" }
+	local result = A:Complement()
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(1, 2)
+	local B        = OvaleTimeSpan(3, 4)
+	local expected = OvaleTimeSpan(1, 2, 3, 4)
+
+	local msg = { format("union of disjoint A%s and B%s, A before B", tostring(A), tostring(B)) }
+	local result = A:Union(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(3, 4)
+	local B        = OvaleTimeSpan(1, 2)
+	local expected = OvaleTimeSpan(1, 2, 3, 4)
+
+	local msg = { format("union of disjoint A%s and B%s, A after B", tostring(A), tostring(B)) }
+	local result = A:Union(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(1, 2, 3, 4)
+	local B        = OvaleTimeSpan(2, 3, 4, 5)
+	local expected = OvaleTimeSpan(1, 5)
+
+	local msg = { format("union of %s and %s", tostring(A), tostring(B)) }
+	local result = A:Union(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(2, 3, 4, 5)
+	local B        = OvaleTimeSpan(1, 2, 3, 4)
+	local expected = OvaleTimeSpan(1, 5)
+
+	local msg = { format("union of %s and %s", tostring(A), tostring(B)) }
+	local result = A:Union(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(1, 2)
+	local B        = OvaleTimeSpan(2, 3, 4, 5)
+	local expected = OvaleTimeSpan(1, 3, 4, 5)
+
+	local msg = { format("union of %s and %s", tostring(A), tostring(B)) }
+	local result = A:Union(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(2, 3, 4, 5)
+	local B        = OvaleTimeSpan(1, 2)
+	local expected = OvaleTimeSpan(1, 3, 4, 5)
+
+	local msg = { format("union of %s and %s", tostring(A), tostring(B)) }
+	local result = A:Union(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(2, 3, 4, 5)
+	local B        = OvaleTimeSpan(1, 4)
+	local expected = OvaleTimeSpan(1, 5)
+
+	local msg = { format("union of %s and %s", tostring(A), tostring(B)) }
+	local result = A:Union(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(1, 5, 6, 10, 15, 17, 20, 30, 99, 101)
+	local B        = OvaleTimeSpan(2, 3, 7, 11, 14, 18, 21, 29, 42, 47, 99, 101)
+	local expected = OvaleTimeSpan(1, 5, 6, 11, 14, 18, 20, 30, 42, 47, 99, 101)
+
+	local msg = { format("union of %s and %s", tostring(A), tostring(B)) }
+	local result = A:Union(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(1, 5, 6, 10, 15, 17, 20, 30, 99, 101)
+	local B        = OvaleTimeSpan(2, 3, 7, 11, 14, 18, 21, 29, 42, 47, 101, 105)
+	local expected = OvaleTimeSpan(1, 5, 6, 11, 14, 18, 20, 30, 42, 47, 99, 105)
+
+	local msg = { format("union of %s and %s", tostring(A), tostring(B)) }
+	local result = A:Union(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan()
+	local B        = OvaleTimeSpan()
+	local expected = OvaleTimeSpan()
+
+	local msg = { "union of empty sets should be empty" }
+	local result = A:Intersect(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(1, 3)
+	local B        = OvaleTimeSpan(2, 4)
+	local expected = OvaleTimeSpan(2, 3)
+
+	local msg = { format("intersection of %s and %s", tostring(A), tostring(B)) }
+	local result = A:Intersect(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(1, 3, 4, 6)
+	local B        = OvaleTimeSpan(2, 5)
+	local expected = OvaleTimeSpan(2, 3, 4, 5)
+
+	local msg = { format("intersection of %s and %s", tostring(A), tostring(B)) }
+	local result = A:Intersect(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(1, 5, 6, 10, 15, 17, 20, 30, 99, 101)
+	local B        = OvaleTimeSpan(2, 3, 7, 11, 14, 18, 21, 29, 42, 47, 99, 101)
+	local expected = OvaleTimeSpan(2, 3, 7, 10, 15, 17, 21, 29, 99, 101)
+
+	local msg = { format("intersection of %s and %s", tostring(A), tostring(B)) }
+	local result = A:Intersect(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(2, math.huge)
+	local B        = OvaleTimeSpan(3, math.huge)
+	local expected = OvaleTimeSpan(3, math.huge)
+
+	local msg = { format("intersection of %s and %s", tostring(A), tostring(B)) }
+	local result = A:Intersect(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A            = OvaleTimeSpan(1, 3, 4, 6)
+	local startB, endB = 2, 5
+	local expected     = OvaleTimeSpan(2, 3, 4, 5)
+
+	local msg = { format("intersect %s with interval (%s, %s)", tostring(A), tostring(startB), tostring(endB)) }
+	local result = A:IntersectInterval(startB, endB)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A        = OvaleTimeSpan(1, 3, 4, 6)
+	local B        = OvaleTimeSpan(3, math.huge)
+	local expected = OvaleTimeSpan(4, 6)
+
+	local msg = { format("intersection of %s and %s", tostring(A), tostring(B)) }
+	local result = A:Intersect(B)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+tests[#tests + 1] = function()
+	local A            = OvaleTimeSpan(1, 3, 4, 6)
+	local startB, endB = 3, math.huge
+	local expected     = OvaleTimeSpan(4, 6)
+
+	local msg = { format("intersect %s with interval (%s, %s)", tostring(A), tostring(startB), tostring(endB)) }
+	local result = A:IntersectInterval(startB, endB)
+	if not result:Equals(expected) then
+		tinsert(msg, format("#   result: %s", tostring(result)))
+		tinsert(msg, format("# expected: %s", tostring(expected)))
+		return false, msg
+	end
+	return true, msg
+end
+
+-- Produce TAP output for unit tests.
+do
+	print(format("1..%d", #tests))
+	for i, func in ipairs(tests) do
+		local result, msg = func()
+		local msgString = msg
+		if type(msg) == "table" then
+			msgString = tconcat(msg, "\n")
+		end
+		local resultString = result and "ok" or "not ok"
+		print(format("%s %d - %s", resultString, i, msgString))
+	end
+end