local istream = require("InputStream") local ds = require("DataStructures") local Stack, Dictionary, WordInfo, Environment = ds.Stack, ds.Dictionary, ds.WordInfo, ds.Environment local CoreHelpers = require("CoreHelpers") local CoreWords = require("CoreWords") local interpreters = require("Interpreters") function pushThree(s) s:push(1) s:push(2) s:push(3) end describe("Stack Tests", function() local stack = Stack:new() it("fails on stack underflow", function() stack = Stack:new() assert.has.errors(function() stack:pop() end) end) it("pushes three items properly", function() stack = Stack:new() pushThree(stack) assert.are.same(stack.contents, {1,2,3}) end) it("pops three items properly", function() stack = Stack:new() pushThree(stack) assert.are.same(stack.contents, {1,2,3}) assert(3 == stack:pop()) assert.are.same(stack.contents, {1,2}) assert(2 == stack:pop()) assert.are.same(stack.contents, {1}) assert(1 == stack:pop()) assert.are.same(stack.contents, {}) assert.has.errors(function() stack:pop() end) end) it("PUSH 1, 2, 3, POP = 3, PUSH 4 = {1,2,4}", function() stack = Stack:new() pushThree(stack) assert(3 == stack:pop()) assert.are.same(stack.contents, {1, 2}) stack:push(4) assert.are.same(stack.contents, {1, 2, 4}) end) end) local function dummyInput() return "1234567890" end describe("InputStream tests", function() local input = istream:new(dummyInput) it("gets a new refill accurately", function() input = istream:new(dummyInput) assert.are.equal(input.refill, dummyInput) end) it("reads text properly", function() input = istream:new(dummyInput) local inputString = dummyInput() for i = 0, 100 do local j = i % #inputString + 1 assert.are.same(inputString:sub(j, j), input:next()) end end) describe("Tests with ends of input", function() it("handles a single line", function() local inputstr = "TEST TEST TEST" input = CoreHelpers.oneReadInputStream(inputstr) for i = 1, #inputstr do assert.are.same(inputstr:sub(i, i), input:next()) end for i = 1, 1000 do assert.are.same(nil, input:next()) end end) it("handles multiple lines", function() local inputstr = "TEST\nTEST\nTEST\nTEST\nTEST\nTEST51515151" input = CoreHelpers.oneReadInputStream(inputstr) input:curr() for i = 1, #inputstr do assert.are.same(inputstr:sub(i, i), input:next()) end for i = 1, 1000 do assert.are.same(nil, input:next()) end end) it("can do files", function() local fname = "./filetest.txt" input = CoreHelpers.fileStream(fname) local expected_output = io.open(fname, "r"):read("*all") for i = 1, #expected_output do assert.are.same(expected_output:sub(i,i), input:next()) end for i = 1, 1000 do assert.are.same(nil, input:next()) end end) end) end) describe("WordInfo tests", function() local Environment = ds.Environment local WordInfo = ds.WordInfo it("creates and doesn't crash", function() local env = Environment:new() wi = WordInfo:new(function(env) end, false) end) end) describe("Dictionary tests", function() local Dictionary = ds.Dictionary local WordInfo = ds.WordInfo local Environment = ds.Environment it("defines without breaking",function() local env = Environment:new() local dict = Dictionary:new() local wi = WordInfo:new(function(env) end, false) dict:define("TEST",wi) end) it("can get WordInfo back after it being defined", function() local env = Environment:new() local dict = Dictionary:new() local wi = WordInfo:new(function(env) end, false) dict:define("TEST",wi) assert.are.same(dict:lookup("TEST"),wi) end) end) function buildEnvironment(testString) local testEnv = Environment:new(CoreHelpers.oneReadInputStream(testString), {CoreWords}) return testEnv end local twoRandom = function() return math.random(100000), math.random(100000) end describe("Interpreter tests", function() describe("Arithmetic tests", function() it("can add two numbers, and leave the sum on the stack", function() for i=1, 1000 do local a, b = twoRandom() local expected_sum = a + b local testString = a.." "..b.." +" local testEnv = buildEnvironment(testString) interpreters.start(testEnv) assert.are.same(testEnv.activeDataStack.contents[1], expected_sum) end end) it("can subtract two numbers, and leave the difference on the stack", function() for i=1, 1000 do local a, b = twoRandom() local expected_diff = a -b local testString = a.." "..b.." -" local testEnv = buildEnvironment(testString) interpreters.start(testEnv) assert.are.same(testEnv.activeDataStack.contents[1], expected_diff) end end) it("can multiply two numbers, leaving product on the stack", function() for i = 1, 1000 do local a, b = twoRandom() local expected_prod = a*b local testString = a.." "..b.." *" local testEnv = buildEnvironment(testString) interpreters.start(testEnv) assert.are.same(testEnv.activeDataStack.contents[1], expected_prod) end end) it("can divide two numbers, leaving the quotient on the stack", function() for i = 1, 1000 do local a, b = twoRandom() local expected_quo = a/b local testString = a.." "..b.." /" local testEnv = buildEnvironment(testString) interpreters.start(testEnv) assert.are.same(testEnv.activeDataStack.contents[1], expected_quo) end end) it("can evaluate a arithmetic expression with multiple operations", function() for i = 1, 1000 do operands = {math.random(100000), math.random(100000), math.random(100000), math.random(100000)} local operations = {math.random(4), math.random(4), math.random(4)} local testString = ""..operands[1] local expectedResult = operands[1] for j, op in ipairs(operations) do if j == 1 then testString = testString.." "..operands[j + 1].." +" expectedResult = expectedResult + operands[j+1] elseif j == 2 then testString = testString.." "..operands[j + 1].." -" expectedResult = expectedResult - operands[j+1] elseif j == 3 then testString = testString.." "..operands[j + 1].." *" expectedResult = expectedResult * operands[j+1] else testString = testString.." "..operands[j + 1].." /" expectedResult = expectedResult / operands[j+1] end end local testEnv = buildEnvironment(testString) interpreters.start(testEnv) assert.are.same(expectedResult,testEnv.activeDataStack.contents[1]) end end) end) end)