Skip to content
This repository has been archived by the owner on Sep 14, 2024. It is now read-only.

Split createEnvironment out into a separate class #86

Merged
merged 1 commit into from
Apr 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions src/TestEnvironment.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
--[[
Create a new environment with functions for defining the test plan structure
using the given TestPlanBuilder.

These functions illustrate the advantage of the stack-style tree navigation
as state doesn't need to be passed around between functions or explicitly
global.
]]
local TestEnum = require(script.Parent.TestEnum)

local TestEnvironment = {}

function TestEnvironment.new(builder, extraEnvironment)
local env = {}

if extraEnvironment then
if type(extraEnvironment) ~= "table" then
error(("Bad argument #2 to TestEnvironment.new. Expected table, got %s"):format(
typeof(extraEnvironment)), 2)
end

for key, value in pairs(extraEnvironment) do
env[key] = value
end
end

function env.describeFOCUS(phrase, callback)
return env.describe(phrase, callback, TestEnum.NodeModifier.Focus)
end

function env.describeSKIP(phrase, callback)
return env.describe(phrase, callback, TestEnum.NodeModifier.Skip)
end

function env.describe(phrase, callback, nodeModifier)
local node = builder:pushNode(phrase, TestEnum.NodeType.Describe, nodeModifier)

local ok, err = pcall(callback)

-- loadError on a TestPlan node is an automatic failure
if not ok then
node.loadError = err
end

builder:popNode()
end

function env.it(phrase, callback)
local node = builder:pushNode(phrase, TestEnum.NodeType.It)

node.callback = callback

builder:popNode()
end

-- Incrementing counter used to ensure that beforeAll, afterAll, beforeEach, afterEach have unique phrases
local lifecyclePhaseId = 0

local lifecycleHooks = {
[TestEnum.NodeType.BeforeAll] = "beforeAll",
[TestEnum.NodeType.AfterAll] = "afterAll",
[TestEnum.NodeType.BeforeEach] = "beforeEach",
[TestEnum.NodeType.AfterEach] = "afterEach"
}

for nodeType, name in pairs(lifecycleHooks) do
env[name] = function(callback)
local node = builder:pushNode(name .. "_" .. tostring(lifecyclePhaseId), nodeType)
lifecyclePhaseId = lifecyclePhaseId + 1

node.callback = callback

builder:popNode()
end
end

function env.itFOCUS(phrase, callback)
local node = builder:pushNode(phrase, TestEnum.NodeType.It, TestEnum.NodeModifier.Focus)

node.callback = callback

builder:popNode()
end

function env.itSKIP(phrase, callback)
local node = builder:pushNode(phrase, TestEnum.NodeType.It, TestEnum.NodeModifier.Skip)

node.callback = callback

builder:popNode()
end

function env.itFIXME(phrase, callback)
local node = builder:pushNode(phrase, TestEnum.NodeType.It, TestEnum.NodeModifier.Skip)

warn("FIXME: broken test", node:getFullName())
node.callback = callback

builder:popNode()
end

function env.FIXME(optionalMessage)
local currentNode = builder:getCurrentNode()
warn("FIXME: broken test", currentNode:getFullName(), optionalMessage or "")

currentNode.modifier = TestEnum.NodeModifier.Skip
end

function env.FOCUS()
local currentNode = builder:getCurrentNode()

currentNode.modifier = TestEnum.NodeModifier.Focus
end

function env.SKIP()
local currentNode = builder:getCurrentNode()

currentNode.modifier = TestEnum.NodeModifier.Skip
end

--[[
These method is intended to disable the use of xpcall when running
nodes contained in the same node that this function is called in.
This is because xpcall breaks badly if the method passed yields.

This function is intended to be hideous and seldom called.

Once xpcall is able to yield, this function is obsolete.
]]
function env.HACK_NO_XPCALL()
local currentNode = builder:getCurrentNode()

currentNode.HACK_NO_XPCALL = true
end

env.step = env.it

env.fit = env.itFOCUS
env.xit = env.itSKIP
env.fdescribe = env.describeFOCUS
env.xdescribe = env.describeSKIP

setmetatable(env, TestEnvironment)
return env
end

return TestEnvironment
144 changes: 2 additions & 142 deletions src/TestPlanner.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

local TestEnum = require(script.Parent.TestEnum)
local TestPlanBuilder = require(script.Parent.TestPlanBuilder)
local TestEnvironment = require(script.Parent.TestEnvironment)

local TestPlanner = {}

Expand Down Expand Up @@ -41,147 +42,6 @@ local function buildPlan(builder, module, env)
end
end

--[[
Create a new environment with functions for defining the test plan structure
using the given TestPlanBuilder.

These functions illustrate the advantage of the stack-style tree navigation
as state doesn't need to be passed around between functions or explicitly
global.
]]
function TestPlanner.createEnvironment(builder, extraEnvironment)
local env = {}

if extraEnvironment then
if type(extraEnvironment) ~= "table" then
error(("Bad argument #2 to TestPlanner.createEnvironment. Expected table, got %s"):format(
typeof(extraEnvironment)), 2)
end

for key, value in pairs(extraEnvironment) do
env[key] = value
end
end

function env.describeFOCUS(phrase, callback)
return env.describe(phrase, callback, TestEnum.NodeModifier.Focus)
end

function env.describeSKIP(phrase, callback)
return env.describe(phrase, callback, TestEnum.NodeModifier.Skip)
end

function env.describe(phrase, callback, nodeModifier)
local node = builder:pushNode(phrase, TestEnum.NodeType.Describe, nodeModifier)

local ok, err = pcall(callback)

-- loadError on a TestPlan node is an automatic failure
if not ok then
node.loadError = err
end

builder:popNode()
end

function env.it(phrase, callback)
local node = builder:pushNode(phrase, TestEnum.NodeType.It)

node.callback = callback

builder:popNode()
end

-- Incrementing counter used to ensure that beforeAll, afterAll, beforeEach, afterEach have unique phrases
local lifecyclePhaseId = 0

local lifecycleHooks = {
[TestEnum.NodeType.BeforeAll] = "beforeAll",
[TestEnum.NodeType.AfterAll] = "afterAll",
[TestEnum.NodeType.BeforeEach] = "beforeEach",
[TestEnum.NodeType.AfterEach] = "afterEach"
}

for nodeType, name in pairs(lifecycleHooks) do
env[name] = function(callback)
local node = builder:pushNode(name .. "_" .. tostring(lifecyclePhaseId), nodeType)
lifecyclePhaseId = lifecyclePhaseId + 1

node.callback = callback

builder:popNode()
end
end

function env.itFOCUS(phrase, callback)
local node = builder:pushNode(phrase, TestEnum.NodeType.It, TestEnum.NodeModifier.Focus)

node.callback = callback

builder:popNode()
end

function env.itSKIP(phrase, callback)
local node = builder:pushNode(phrase, TestEnum.NodeType.It, TestEnum.NodeModifier.Skip)

node.callback = callback

builder:popNode()
end

function env.itFIXME(phrase, callback)
local node = builder:pushNode(phrase, TestEnum.NodeType.It, TestEnum.NodeModifier.Skip)

warn("FIXME: broken test", node:getFullName())
node.callback = callback

builder:popNode()
end

function env.FIXME(optionalMessage)
local currentNode = builder:getCurrentNode()
warn("FIXME: broken test", currentNode:getFullName(), optionalMessage or "")

currentNode.modifier = TestEnum.NodeModifier.Skip
end

function env.FOCUS()
local currentNode = builder:getCurrentNode()

currentNode.modifier = TestEnum.NodeModifier.Focus
end

function env.SKIP()
local currentNode = builder:getCurrentNode()

currentNode.modifier = TestEnum.NodeModifier.Skip
end

--[[
These method is intended to disable the use of xpcall when running
nodes contained in the same node that this function is called in.
This is because xpcall breaks badly if the method passed yields.

This function is intended to be hideous and seldom called.

Once xpcall is able to yield, this function is obsolete.
]]
function env.HACK_NO_XPCALL()
local currentNode = builder:getCurrentNode()

currentNode.HACK_NO_XPCALL = true
end

env.step = env.it

env.fit = env.itFOCUS
env.xit = env.itSKIP
env.fdescribe = env.describeFOCUS
env.xdescribe = env.describeSKIP

return env
end

--[[
Create a new TestPlan from a list of specification functions.

Expand All @@ -192,7 +52,7 @@ function TestPlanner.createPlan(specFunctions, noXpcallByDefault, testNamePatter
local builder = TestPlanBuilder.new()
builder.noXpcallByDefault = noXpcallByDefault
builder.testNamePattern = testNamePattern
local env = TestPlanner.createEnvironment(builder, extraEnvironment)
local env = TestEnvironment.new(builder, extraEnvironment)

for _, module in ipairs(specFunctions) do
buildPlan(builder, module, env)
Expand Down