local C=require(script.Parent.TestEnum)local K={}K.__index=K function K.new()local C={children={}}setmetatable(C,K)return C end function K.visitAllNodes(y,C,K)K=K or y for K,E in ipairs(K.children)do C(E)y:visitAllNodes(C,E)end end local function y(C)if C.parent then local K=y(C.parent)if K then return K..(" "..C.phrase)end end return C.phrase end function K.createNode(K,E,t)t=t or C.NodeModifier.None local m={phrase=K;type=E,modifier=t,children={},callback=nil;getFullName=y}return m end function K.visualize(E,K,y)K=K or E y=y or 0 local t={}for K,m in ipairs(K.children)do if m.type==C.NodeType.It then table.insert(t,(" "):rep(3*y)..m.phrase)else table.insert(t,(" "):rep(3*y)..m.phrase)end if#m.children>0 then local C=E:visualize(m,y+1)table.insert(t,C)end end return table.concat(t,"\n")end function K.findNodes(E,C,K,y)y=y or E K=K or{}for y,t in ipairs(y.children)do if C(t)then table.insert(K,t)end E:findNodes(C,K,t)end return K end return K
--[[
	Represents a tree of tests that have been loaded but not necessarily
	executed yet.

	TestPlan objects are produced by TestPlanner and TestPlanBuilder.
]]

local TestEnum = require(script.Parent.TestEnum)

local TestPlan = {}

TestPlan.__index = TestPlan

--[[
	Create a new, empty TestPlan.
]]
function TestPlan.new()
	local self = {
		children = {}
	}

	setmetatable(self, TestPlan)

	return self
end

--[[
	Calls the given callback on all nodes in the tree, traversed depth-first.
]]
function TestPlan:visitAllNodes(callback, root)
	root = root or self

	for _, child in ipairs(root.children) do
		callback(child)

		self:visitAllNodes(callback, child)
	end
end

local function constructNodeFullName(node)
	if node.parent then
		local parentPhrase = constructNodeFullName(node.parent)
		if parentPhrase then
			return parentPhrase .. " " .. node.phrase
		end
	end
	return node.phrase
end

--[[
	Creates a new node that would be suitable to insert into the TestPlan.
]]
function TestPlan.createNode(phrase, nodeType, nodeModifier)
	nodeModifier = nodeModifier or TestEnum.NodeModifier.None

	local node = {
		phrase = phrase,
		type = nodeType,
		modifier = nodeModifier,
		children = {},
		callback = nil,
		getFullName = constructNodeFullName
	}

	return node
end

--[[
	Visualizes the test plan in a simple format, suitable for debugging the test
	plan's structure.
]]
function TestPlan:visualize(root, level)
	root = root or self
	level = level or 0

	local buffer = {}

	for _, child in ipairs(root.children) do
		if child.type == TestEnum.NodeType.It then
			table.insert(buffer, (" "):rep(3 * level) .. child.phrase)
		else
			table.insert(buffer, (" "):rep(3 * level) .. child.phrase)
		end

		if #child.children > 0 then
			local text = self:visualize(child, level + 1)
			table.insert(buffer, text)
		end
	end

	return table.concat(buffer, "\n")
end

--[[
	Gets a list of all nodes in the tree for which the given callback returns
	true.
]]
function TestPlan:findNodes(callback, results, node)
	node = node or self
	results = results or {}

	for _, childNode in ipairs(node.children) do
		if callback(childNode) then
			table.insert(results, childNode)
		end

		self:findNodes(callback, results, childNode)
	end

	return results
end

return TestPlan