2021-05-19 05:41:01 +00:00
|
|
|
local istream = require("InputStream")
|
|
|
|
local ds = require("DataStructures")
|
|
|
|
local Stack, Dictionary, WordInfo, Environment = ds.Stack, ds.Dictionary, ds.WordInfo, ds.Environment
|
2021-05-20 01:21:17 +00:00
|
|
|
local CoreHelpers = require("CoreHelpers")
|
2021-05-23 11:59:36 +00:00
|
|
|
local CoreWords = require("CoreWords")
|
|
|
|
local interpreters = require("Interpreters")
|
2021-05-19 05:41:01 +00:00
|
|
|
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()
|
2021-05-19 06:26:57 +00:00
|
|
|
input = istream:new(dummyInput)
|
2021-05-19 05:41:01 +00:00
|
|
|
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
|
2021-05-20 01:21:17 +00:00
|
|
|
assert.are.same(inputString:sub(j, j), input:next())
|
2021-05-19 05:41:01 +00:00
|
|
|
end
|
|
|
|
end)
|
2021-05-20 01:21:17 +00:00
|
|
|
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)
|
2021-05-20 07:00:48 +00:00
|
|
|
input:curr()
|
2021-05-20 01:21:17 +00:00
|
|
|
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)
|
2021-05-19 05:41:01 +00:00
|
|
|
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)
|
2021-05-19 06:26:57 +00:00
|
|
|
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)
|
2021-05-19 05:41:01 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
|
2021-05-23 11:59:36 +00:00
|
|
|
function buildEnvironment(testString)
|
|
|
|
local testEnv = Environment:new(CoreHelpers.oneReadInputStream(testString), {CoreWords})
|
|
|
|
return testEnv
|
|
|
|
end
|
|
|
|
|
2021-05-23 12:12:10 +00:00
|
|
|
local twoRandom = function() return math.random(-100000, 100000), math.random(-100000, 100000) end
|
2021-05-23 11:59:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
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
|
2021-05-23 12:12:10 +00:00
|
|
|
operands = {math.random(-100000,100000), math.random(-100000,100000), math.random(-100000,100000), math.random(-100000,100000)}
|
2021-05-23 11:59:36 +00:00
|
|
|
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)
|
2021-05-23 12:12:10 +00:00
|
|
|
describe("Core word tests", function()
|
|
|
|
describe("DUP tests", function()
|
|
|
|
it("DUPs the top item of a stack with one item on it.", function()
|
|
|
|
local testEnv = buildEnvironment("1 DUP")
|
|
|
|
interpreters.start(testEnv)
|
|
|
|
assert.are.same(1, testEnv.activeDataStack.contents[2])
|
|
|
|
end)
|
|
|
|
it("DUPs the top item of a stack with random quantities of random numbers on it.", function()
|
|
|
|
for i = 1, 1000 do
|
|
|
|
local stack_depth = math.random(100)
|
|
|
|
local stack_top = 0
|
|
|
|
for j = 1, stack_depth do
|
|
|
|
stack_top = math.random(-100000,100000)
|
|
|
|
testEnv.activeDataStack:push(stack_top)
|
|
|
|
end
|
|
|
|
local testEnv = buildEnvironment(stack_top.." DUP")
|
|
|
|
assert.are.same(stack_top, testEnv.activeDataStack.contents[j+1])
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
end)
|
2021-05-23 11:59:36 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-05-19 05:41:01 +00:00
|
|
|
|