return function()local f=require(script.Parent.validateMotor)local e=require(script.Parent.createSpy)local t=require(script.Parent.createSingleMotor)local I={step=function(f,e,t)return e end}local function S(f)local e={stepCount=0}e.step=function(t,I,S)e.stepCount=e.stepCount+1 if e.stepCount>=f then return{value=I.value,velocity=I.velocity,complete=true}end return I end setmetatable(e,{__index=function(f,e)error(("\037\113 \105\115 \110\111\116 \097 \118\097\108\105\100 \109\101\109\098\101\114 \111\102 \115\116\101\112\112\101\114"):format(e))end})return e end it("\115\104\111\117\108\100 \098\101 \097 \118\097\108\105\100 \109\111\116\111\114",function()local e=t(0)f(e)e:destroy()end)it("\115\104\111\117\108\100 \105\110\118\111\107\101 \115\117\098\115\099\114\105\098\101\114\115 \119\105\116\104 \110\101\119 \118\097\108\117\101\115",function()local f=t(8)f:setGoal(I)local S=e()local b=f:onStep(S.value);(expect(S.callCount)).to.equal(0)f:step(1);(expect(S.callCount)).to.equal(1)S:assertCalledWith(8)b()f:step(1);(expect(S.callCount)).to.equal(1)end)describe("\111\110\067\111\109\112\108\101\116\101 \115\104\111\117\108\100 \098\101 \099\097\108\108\101\100 \119\104\101\110",function()it("\104\097\115 \099\111\109\112\108\101\116\101\100 \105\116\115 \109\111\116\105\111\110",function()local f=t(0)f:setGoal(S(5))local I=e()f:onComplete(I.value)for e=1,5,1 do f:step(1)end;(expect(I.callCount)).to.equal(1)f:destroy()end)it("\104\097\115 \114\101\115\116\097\114\116\101\100 \105\116\115 \109\111\116\105\111\110",function()local f=t(0)f:setGoal(S(5))local I=e()f:onComplete(I.value);(expect(I.callCount)).to.equal(0)for e=1,5,1 do f:step(1)end;(expect(I.callCount)).to.equal(1)f:setGoal(S(5))for e=1,5,1 do f:step(1)end;(expect(I.callCount)).to.equal(2)f:destroy()end)end)describe("\111\110\067\111\109\112\108\101\116\101 \115\104\111\117\108\100 \110\111\116 \098\101 \099\097\108\108\101\100 \119\104\101\110",function()it("\104\097\115 \110\111\116 \099\111\109\112\108\101\116\101\100 \109\111\116\105\111\110",function()local f=t(0)f:setGoal(S(10))local I=e()f:onComplete(I.value)f:step(1);(expect(I.callCount)).to.equal(0)f:destroy()end)it("\100\111\101\115 \110\111\116 \099\097\108\108 \115\116\101\112",function()local f=t(0)f:setGoal(S(0))local I=e()f:onComplete(I.value);(expect(I.callCount)).to.equal(0)f:destroy()end)end)end
return function()
	local validateMotor = require(script.Parent.validateMotor)
	local createSpy = require(script.Parent.createSpy)

	local createSingleMotor = require(script.Parent.createSingleMotor)


	local identityGoal = {
		step = function(self, state, dt)
			return state
		end,
	}

	-- test motion object that completes after step has been called numSteps times
	local function createStepper(numSteps)
		local self = {
			stepCount = 0,
		}

		self.step = function(_, state, dt)
			self.stepCount = self.stepCount + 1

			if self.stepCount >= numSteps then
				return {
					value = state.value,
					velocity = state.velocity,
					complete = true,
				}
			end

			return state
		end

		setmetatable(self, {
			__index = function(_, key)
				error(("%q is not a valid member of stepper"):format(key))
			end,
		})

		return self
	end

	it("should be a valid motor", function()
		local motor = createSingleMotor(0)
		validateMotor(motor)
		motor:destroy()
	end)

	it("should invoke subscribers with new values", function()
		local motor = createSingleMotor(8)
		motor:setGoal(identityGoal)

		local spy = createSpy()

		local disconnect = motor:onStep(spy.value)

		expect(spy.callCount).to.equal(0)

		motor:step(1)

		expect(spy.callCount).to.equal(1)
		spy:assertCalledWith(8)

		disconnect()

		motor:step(1)

		expect(spy.callCount).to.equal(1)
	end)

	describe("onComplete should be called when", function()
		it("has completed its motion", function()
			local motor = createSingleMotor(0)
			motor:setGoal(createStepper(5))

			local spy = createSpy()

			motor:onComplete(spy.value)

			for _ = 1, 5 do
				motor:step(1)
			end

			expect(spy.callCount).to.equal(1)

			motor:destroy()
		end)

		it("has restarted its motion", function()
			local motor = createSingleMotor(0)
			motor:setGoal(createStepper(5))

			local spy = createSpy()

			motor:onComplete(spy.value)

			expect(spy.callCount).to.equal(0)

			for _ = 1, 5 do
				motor:step(1)
			end

			expect(spy.callCount).to.equal(1)

			motor:setGoal(createStepper(5))

			for _ = 1, 5 do
				motor:step(1)
			end

			expect(spy.callCount).to.equal(2)

			motor:destroy()
		end)
	end)

	describe("onComplete should not be called when", function()
		it("has not completed motion", function()
			local motor = createSingleMotor(0)
			motor:setGoal(createStepper(10))

			local spy = createSpy()

			motor:onComplete(spy.value)

			motor:step(1)

			expect(spy.callCount).to.equal(0)

			motor:destroy()
		end)

		it("does not call step", function()
			local motor = createSingleMotor(0)
			motor:setGoal(createStepper(0))

			local spy = createSpy()

			motor:onComplete(spy.value)

			expect(spy.callCount).to.equal(0)

			motor:destroy()
		end)
	end)
end