return function()local x=game:GetService("\067\111\110\116\101\120\116\065\099\116\105\111\110\083\101\114\118\105\099\101")local M=require(script.Parent.MockContextActionService)local P=require(script.Parent.Action)local w=Enum.ContextActionPriority.Default.Value local C=function()return true end local k={Enum.KeyCode.E;Enum.KeyCode.ButtonB}local function Q(x)return next(x)==nil end describe("\110\101\119",function()it("\115\104\111\117\108\100 \099\114\101\097\116\101 \097 \110\101\119 \065\099\116\105\111\110",function()local x=P.new("\102\111\111");(expect(x.name)).to.equal("\102\111\111");(expect(x)).to.never.equal(P)end)end)describe("\102\114\111\109\079\098\106\101\099\116",function()it("\115\104\111\117\108\100 \099\114\101\097\116\101 \097 \110\101\119 \065\099\116\105\111\110 \102\114\111\109 \097\110 \111\098\106\101\099\116",function()local x=P.fromObject({name="\102\111\111";callback=C,inputTypes=k});(expect(x.name)).to.equal("\102\111\111");(expect(x.callback)).to.equal(C);(expect(x.inputTypes)).equal(k)end)end)describe("\115\101\116\067\097\108\108\098\097\099\107",function()it("\115\104\111\117\108\100 \115\101\116 \096\099\097\108\108\098\097\099\107\096 \116\111 \116\104\101 \103\105\118\101\110 \102\117\110\099\116\105\111\110",function()local x=P.new("\102\111\111")x:setCallback(C);(expect(x.callback)).to.equal(C)end)end)describe("\115\101\116\073\110\112\117\116\084\121\112\101\115",function()it("\115\104\111\117\108\100 \115\101\116 \096\105\110\112\117\116\084\121\112\101\115\096 \116\111 \116\104\101 \103\105\118\101\110 \097\114\114\097\121",function()local x=P.new("\102\111\111")x:setInputTypes(k);(expect(x.inputTypes)).to.equal(k)end)end)describe("\098\105\110\100\065\116\080\114\105\111\114\105\116\121",function()it("\115\104\111\117\108\100 \114\101\103\105\115\116\101\114 \116\104\101 \097\099\116\105\111\110 \119\105\116\104 \067\111\110\116\101\120\116\065\099\116\105\111\110\083\101\114\118\105\099\101",function()local M=P.new("\102\111\111")M:setCallback(C)M:setInputTypes(k)M:bindAtPriority(w)local t=x:GetBoundActionInfo(M.name);(expect(not Q(t))).to.equal(true)end)it("\115\104\111\117\108\100 \099\104\097\110\103\101 \096\105\115\066\111\117\110\100\096 \116\111 \116\114\117\101",function()local x=P.new("\102\111\111")x:setCallback(C)x:setInputTypes(k);(expect(x.isBound)).to.equal(false)x:bindAtPriority(w);(expect(x.isBound)).to.equal(true)end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \098\101 \098\111\117\110\100 \116\111 \085\115\101\114\073\110\112\117\116\083\116\097\116\101\046\066\101\103\105\110",function()local x=false local C=P.fromObject({name="\102\111\111";inputState=Enum.UserInputState.Begin,inputTypes=k;callback=function(M)expect(M.UserInputState==Enum.UserInputState.Begin)x=true end})C.contextActionServiceImpl=M C:bindAtPriority(w)M:SimulateInputBegin(Enum.KeyCode.E);(expect(x)).to.equal(true)end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \098\101 \098\111\117\110\100 \116\111 \085\115\101\114\073\110\112\117\116\083\116\097\116\101\046\069\110\100",function()local x=false local C=P.fromObject({name="\102\111\111",inputState=Enum.UserInputState.Begin;inputTypes=k;callback=function(M)expect(M.UserInputState==Enum.UserInputState.End)x=true end})C.contextActionServiceImpl=M C:bindAtPriority(w)M:SimulateInputBegin(Enum.KeyCode.E);(expect(x)).to.equal(true)end)it("\115\104\111\117\108\100 \101\114\114\111\114 \105\102 \116\104\101 \097\099\116\105\111\110 \105\115 \097\108\114\101\097\100\121 \098\111\117\110\100",function()local x=P.new("\102\111\111")x:setCallback(C)x:setInputTypes(k);(expect(x.isBound)).to.equal(false)x:bindAtPriority(w);(expect(x.isBound)).to.equal(true);(expect(function()x:bind()end)).to.throw()end)it("\115\104\111\117\108\100 \101\114\114\111\114 \105\102 \096\105\110\112\117\116\084\121\112\101\115\096 \105\115\110\'\116 \115\101\116",function()local x=P.new("\102\111\111")x:setCallback(C);(expect(x.inputTypes)).to.never.be.ok();(expect(function()x:bindAtPriority(w)end)).to.throw()end)it("\115\104\111\117\108\100 \101\114\114\111\114 \105\102 \096\099\097\108\108\098\097\099\107\096 \105\115\110\'\116 \115\101\116",function()local x=P.new("\102\111\111")x:setInputTypes(k);(expect(x.callback)).to.never.be.ok();(expect(function()x:bindAtPriority(w)end)).to.throw()end)end)describe("\098\105\110\100",function() end)describe("\117\110\098\105\110\100\040\041",function()it("\115\104\111\117\108\100 \099\104\097\110\103\101 \116\104\101 \105\115\066\111\117\110\100 \112\114\111\112\101\114\116\121 \116\111 \102\097\108\115\101",function()local x=P.new("\102\111\111")x:setCallback(C)x:setInputTypes(k)x:bind();(expect(x.isBound)).to.equal(true)x:unbind();(expect(x.isBound)).to.equal(false)end)it("\115\104\111\117\108\100 \117\110\098\105\110\100 \116\104\101 \097\099\116\105\111\110 \102\114\111\109 \067\111\110\116\101\120\116\065\099\116\105\111\110\083\101\114\118\105\099\101",function() end)it("\115\104\111\117\108\100 \101\114\114\111\114 \105\102 \116\104\101 \097\099\116\105\111\110 \105\115 \110\111\116 \098\111\117\110\100",function()local x=P.new("\102\111\111");(expect(function()x:unbind()end)).to.throw()end)end)end
return function()
	local ContextActionService = game:GetService("ContextActionService")

	local MockContextActionService = require(script.Parent.MockContextActionService)
	local Action = require(script.Parent.Action)

	local MOCK_PRIORITY = Enum.ContextActionPriority.Default.Value

	local MOCK_CALLBACK = function()
		return true
	end
	local MOCK_INPUT_TYPES = {
		Enum.KeyCode.E,
		Enum.KeyCode.ButtonB,
	}

	-- This is for use with GetBoundActionInfo. Apparently an empty table is
	-- returned even if the action has never been bound! cool!
	local function isEmpty(t)
		return next(t) == nil
	end

	describe("new", function()
		it("should create a new Action", function()
			local action = Action.new("foo")

			expect(action.name).to.equal("foo")
			expect(action).to.never.equal(Action)
		end)
	end)

	describe("fromObject", function()
		it("should create a new Action from an object", function()
			local action = Action.fromObject({
				name = "foo",
				callback = MOCK_CALLBACK,
				inputTypes = MOCK_INPUT_TYPES,
			})

			expect(action.name).to.equal("foo")
			expect(action.callback).to.equal(MOCK_CALLBACK)
			expect(action.inputTypes).equal(MOCK_INPUT_TYPES)
		end)
	end)

	describe("setCallback", function()
		it("should set `callback` to the given function", function()
			local action = Action.new("foo")

			action:setCallback(MOCK_CALLBACK)

			expect(action.callback).to.equal(MOCK_CALLBACK)
		end)
	end)

	describe("setInputTypes", function()
		it("should set `inputTypes` to the given array", function()
			local action = Action.new("foo")

			action:setInputTypes(MOCK_INPUT_TYPES)

			expect(action.inputTypes).to.equal(MOCK_INPUT_TYPES)
		end)
	end)

	describe("bindAtPriority", function()
		it("should register the action with ContextActionService", function()
			local action = Action.new("foo")
			action:setCallback(MOCK_CALLBACK)
			action:setInputTypes(MOCK_INPUT_TYPES)

			action:bindAtPriority(MOCK_PRIORITY)

			local info = ContextActionService:GetBoundActionInfo(action.name)

			expect(not isEmpty(info)).to.equal(true)
		end)

		it("should change `isBound` to true", function()
			local action = Action.new("foo")
			action:setCallback(MOCK_CALLBACK)
			action:setInputTypes(MOCK_INPUT_TYPES)

			expect(action.isBound).to.equal(false)

			action:bindAtPriority(MOCK_PRIORITY)

			expect(action.isBound).to.equal(true)
		end)

		-- Need to mock ContextActionService to test this
		it("should be able to be bound to UserInputState.Begin", function()
			local wasCalled = false

			local action = Action.fromObject({
				name = "foo",
				inputState = Enum.UserInputState.Begin,
				inputTypes = MOCK_INPUT_TYPES,
				callback = function(input)
					expect(input.UserInputState == Enum.UserInputState.Begin)
					wasCalled = true
				end,
			})

			action.contextActionServiceImpl = MockContextActionService
			action:bindAtPriority(MOCK_PRIORITY)

			MockContextActionService:SimulateInputBegin(Enum.KeyCode.E)

			expect(wasCalled).to.equal(true)
		end)

		it("should be able to be bound to UserInputState.End", function()
			local wasCalled = false

			local action = Action.fromObject({
				name = "foo",
				inputState = Enum.UserInputState.Begin,
				inputTypes = MOCK_INPUT_TYPES,
				callback = function(input)
					expect(input.UserInputState == Enum.UserInputState.End)
					wasCalled = true
				end,
			})

			action.contextActionServiceImpl = MockContextActionService
			action:bindAtPriority(MOCK_PRIORITY)

			MockContextActionService:SimulateInputBegin(Enum.KeyCode.E)

			expect(wasCalled).to.equal(true)
		end)

		it("should error if the action is already bound", function()
			local action = Action.new("foo")
			action:setCallback(MOCK_CALLBACK)
			action:setInputTypes(MOCK_INPUT_TYPES)

			expect(action.isBound).to.equal(false)

			action:bindAtPriority(MOCK_PRIORITY)

			expect(action.isBound).to.equal(true)

			expect(function()
				action:bind()
			end).to.throw()
		end)

		it("should error if `inputTypes` isn't set", function()
			local action = Action.new("foo")
			action:setCallback(MOCK_CALLBACK)

			expect(action.inputTypes).to.never.be.ok()

			expect(function()
				action:bindAtPriority(MOCK_PRIORITY)
			end).to.throw()
		end)

		it("should error if `callback` isn't set", function()
			local action = Action.new("foo")
			action:setInputTypes(MOCK_INPUT_TYPES)

			expect(action.callback).to.never.be.ok()

			expect(function()
				action:bindAtPriority(MOCK_PRIORITY)
			end).to.throw()
		end)
	end)

	describe("bind", function()
		-- This does the same thing as bindAtPriority but with implicit
		-- priority. Unsure how to test that
	end)

	describe("unbind()", function()
		it("should change the isBound property to false", function()
			local action = Action.new("foo")
			action:setCallback(MOCK_CALLBACK)
			action:setInputTypes(MOCK_INPUT_TYPES)

			action:bind()

			expect(action.isBound).to.equal(true)

			action:unbind()

			expect(action.isBound).to.equal(false)
		end)

		it("should unbind the action from ContextActionService", function() end)

		it("should error if the action is not bound", function()
			local action = Action.new("foo")

			expect(function()
				action:unbind()
			end).to.throw()
		end)
	end)

	-- describe("getInfo()", function()
	-- 	it("should return info from ContextActionService about the bound action", function()

	-- 	end)

	-- 	it("should return nil when the action isn't bound", function()
	-- 		local action = Action.new("foo")

	-- 		expect(action:getInfo()).to.equal(nil)
	-- 	end)
	-- end)
end
