mirror of https://github.com/japl-lang/japl.git
More tests
This commit is contained in:
parent
b52585817f
commit
30fb134a74
|
@ -17,6 +17,7 @@ src/lexer
|
|||
src/vm
|
||||
tests/runtests
|
||||
testresults.txt
|
||||
testoutput.txt
|
||||
|
||||
# MacOS
|
||||
|
||||
|
@ -36,6 +37,3 @@ main
|
|||
|
||||
config.nim
|
||||
|
||||
# test results
|
||||
|
||||
testresults.txt
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
|
||||
var y = 0; //a global to keep track of state
|
||||
//does not need closures for this to work yet
|
||||
|
||||
fun next(x) {
|
||||
if (x == 10)
|
||||
{
|
||||
y = y + 1;
|
||||
x = 0;
|
||||
}
|
||||
if (y == 10)
|
||||
return -1;
|
||||
return x+y+1;
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
for (; i != -1; i = next(i))
|
||||
print(i);
|
||||
// before using next
|
||||
//output:0
|
||||
// y = 0
|
||||
//output:1
|
||||
//output:2
|
||||
//output:3
|
||||
//output:4
|
||||
//output:5
|
||||
//output:6
|
||||
//output:7
|
||||
//output:8
|
||||
//output:9
|
||||
//output:10
|
||||
// y = 1
|
||||
//output:2
|
||||
//output:3
|
||||
//output:4
|
||||
//output:5
|
||||
//output:6
|
||||
//output:7
|
||||
//output:8
|
||||
//output:9
|
||||
//output:10
|
||||
// y = 2
|
||||
//output:3
|
||||
//output:4
|
||||
//output:5
|
||||
//output:6
|
||||
//output:7
|
||||
//output:8
|
||||
//output:9
|
||||
//output:10
|
||||
// y = 3
|
||||
//output:4
|
||||
//output:5
|
||||
//output:6
|
||||
//output:7
|
||||
//output:8
|
||||
//output:9
|
||||
//output:10
|
||||
// y = 4
|
||||
//output:5
|
||||
//output:6
|
||||
//output:7
|
||||
//output:8
|
||||
//output:9
|
||||
//output:10
|
||||
// y = 5
|
||||
//output:6
|
||||
//output:7
|
||||
//output:8
|
||||
//output:9
|
||||
//output:10
|
||||
// y = 6
|
||||
//output:7
|
||||
//output:8
|
||||
//output:9
|
||||
//output:10
|
||||
// y = 7
|
||||
//output:8
|
||||
//output:9
|
||||
//output:10
|
||||
// y = 8
|
||||
//output:9
|
||||
//output:10
|
||||
// y = 9
|
||||
//output:10
|
||||
// y = 10
|
|
@ -0,0 +1,22 @@
|
|||
fun printInt(x) {
|
||||
if (x == 1)
|
||||
print("one");
|
||||
else if (x == 2)
|
||||
print("two");
|
||||
else if (x == 3)
|
||||
print("three");
|
||||
else if (x == 4)
|
||||
print("four");
|
||||
else if (x == 5)
|
||||
print("five");
|
||||
else if (x == 6)
|
||||
print("six");
|
||||
}
|
||||
var x = 3;
|
||||
printInt(x);//output:three
|
||||
x = 5;
|
||||
printInt(x);//output:five
|
||||
x = 7;
|
||||
printInt(x);
|
||||
x = 1;
|
||||
printInt(x);//output:one
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
var x = 5;
|
||||
var y = x;
|
||||
y = 6;
|
||||
print(x);//output:5
|
||||
}
|
||||
|
||||
var g = 7;
|
||||
var p = g;
|
||||
{
|
||||
var k = g;
|
||||
p = 3;
|
||||
k = 9;
|
||||
print(g);//output:7
|
||||
}
|
||||
print(g);//output:7
|
||||
|
||||
fun resetter(x) {
|
||||
x = 7;
|
||||
print(x);
|
||||
}
|
||||
|
||||
var q = 5;
|
||||
resetter(q);//output:7
|
||||
print(q);//output:5
|
|
@ -0,0 +1,76 @@
|
|||
//similar to vars.jpl, but more focused on shadowing
|
||||
|
||||
// simple shadowing
|
||||
var x = 4;
|
||||
{
|
||||
var x = 5;
|
||||
print(x);//output:5
|
||||
}
|
||||
print(x);//output:4
|
||||
|
||||
// type changing shadowing
|
||||
var y = true;
|
||||
{
|
||||
var y = 2;
|
||||
print(y);//output:2
|
||||
}
|
||||
print(y);//output:true
|
||||
|
||||
// no shadowing here
|
||||
var z = 3;
|
||||
{
|
||||
z = true;
|
||||
print(z);//output:true
|
||||
}
|
||||
print(z);//output:true
|
||||
|
||||
//in-function shadowing
|
||||
fun shadow(x) {
|
||||
//will be called once with the input 3
|
||||
print(x);//output:3
|
||||
{
|
||||
var x = 4;
|
||||
print(x);//output:4
|
||||
}
|
||||
print(x);//output:3
|
||||
x = nil;
|
||||
print(x);//output:nil
|
||||
return x;
|
||||
}
|
||||
|
||||
print(shadow(3));//output:nil
|
||||
|
||||
//shadowing functions
|
||||
fun hello() {
|
||||
print("hello");
|
||||
}
|
||||
hello();//output:hello
|
||||
{
|
||||
fun hello() {
|
||||
print("hello in");
|
||||
}
|
||||
hello();//output:hello in
|
||||
{
|
||||
fun hello() {
|
||||
print("hello inmost");
|
||||
}
|
||||
hello();//output:hello inmost
|
||||
}
|
||||
hello();//output:hello in
|
||||
}
|
||||
hello();//output:hello
|
||||
|
||||
//functions shadowing with type change
|
||||
fun eat() {
|
||||
print("nom nom nom");
|
||||
}
|
||||
eat();//output:nom nom nom
|
||||
{
|
||||
var eat = 4;
|
||||
print(eat);//output:4
|
||||
{{{{{
|
||||
eat = 5;
|
||||
}}}}} //multiple scopes haha
|
||||
print(eat);//output:5
|
||||
}
|
||||
eat();//output:nom nom nom
|
|
@ -22,12 +22,22 @@
|
|||
|
||||
|
||||
# Imports nim tests as well
|
||||
import multibyte, os, strformat, times, re
|
||||
import multibyte, os, strformat, times, re, terminal
|
||||
|
||||
|
||||
# Exceptions for tests that represent not-yet implemented behaviour
|
||||
const exceptions = ["all.jpl"]
|
||||
|
||||
type LogLevel {.pure.} = enum
|
||||
Debug, # always written to file only (large outputs, such as the entire output of the failing test or stacktrace)
|
||||
Info, # important information about the progress of the test suite
|
||||
Error, # failing tests (printed with red)
|
||||
Stdout, # always printed to stdout only (for cli experience)
|
||||
|
||||
|
||||
const echoedLogs = { LogLevel.Info, LogLevel.Error, LogLevel.Stdout }
|
||||
const savedLogs = { LogLevel.Debug, LogLevel.Info, LogLevel.Error }
|
||||
|
||||
|
||||
proc compileExpectedOutput(path: string): string =
|
||||
for line in path.lines():
|
||||
|
@ -50,22 +60,29 @@ proc deepComp(left, right: string): tuple[same: bool, place: int] =
|
|||
return
|
||||
|
||||
|
||||
# Quick logging levels using procs
|
||||
proc logWithLevel(level: LogLevel, file: File, msg: string) =
|
||||
let msg = &"[{$level} - {$getTime()}] {msg}"
|
||||
|
||||
proc log(file: File, msg: string, toFile: bool = true) =
|
||||
## Logs to stdout and to the log file unless
|
||||
## toFile == false
|
||||
if toFile:
|
||||
file.writeLine(&"[LOG - {$getTime()}] {msg}")
|
||||
echo &"[LOG - {$getTime()}] {msg}"
|
||||
if level in savedLogs:
|
||||
file.writeLine(msg)
|
||||
if level in echoedLogs:
|
||||
if level == LogLevel.Error:
|
||||
setForegroundColor(fgRed)
|
||||
echo msg
|
||||
if level == LogLevel.Error:
|
||||
setForegroundColor(fgDefault)
|
||||
|
||||
|
||||
proc detail(file: File, msg: string) =
|
||||
## Logs only to the log file
|
||||
file.writeLine(&"[DETAIL - {$getTime()}] {msg}")
|
||||
|
||||
|
||||
proc main(testsDir: string, japlExec: string, testResultsFile: File): tuple[numOfTests: int, successTests: int, failedTests: int, skippedTests: int] =
|
||||
template detail(msg: string) =
|
||||
logWithLevel(LogLevel.Debug, testResultsFile, msg)
|
||||
template log(msg: string) =
|
||||
logWithLevel(LogLevel.Info, testResultsFile, msg)
|
||||
template error(msg: string) =
|
||||
logWithLevel(LogLevel.Error, testResultsFile, msg)
|
||||
|
||||
var numOfTests = 0
|
||||
var successTests = 0
|
||||
var failedTests = 0
|
||||
|
@ -74,26 +91,26 @@ proc main(testsDir: string, japlExec: string, testResultsFile: File): tuple[numO
|
|||
for file in walkDir(testsDir):
|
||||
block singleTest:
|
||||
if file.path.extractFilename in exceptions:
|
||||
detail(testResultsFile, &"Skipping '{file.path}'")
|
||||
detail(&"Skipping '{file.path}'")
|
||||
numOfTests += 1
|
||||
skippedTests += 1
|
||||
break singleTest
|
||||
elif file.path.dirExists():
|
||||
detail(testResultsFile, "Descending into '" & file.path & "'")
|
||||
detail(&"Descending into '" & file.path & "'")
|
||||
var subTestResult = main(file.path, japlExec, testResultsFile)
|
||||
numOfTests += subTestResult.numOfTests
|
||||
successTests += subTestResult.successTests
|
||||
failedTests += subTestResult.failedTests
|
||||
skippedTests += subTestResult.skippedTests
|
||||
break singleTest
|
||||
detail(testResultsFile, &"Running test '{file.path}'")
|
||||
detail(&"Running test '{file.path}'")
|
||||
if fileExists("testoutput.txt"):
|
||||
removeFile("testoutput.txt") # in case this crashed
|
||||
let retCode = execShellCmd(&"{japlExec} {file.path} >> testoutput.txt")
|
||||
numOfTests += 1
|
||||
if retCode != 0:
|
||||
failedTests += 1
|
||||
log(testResultsFile, &"Test '{file.path}' has crashed!")
|
||||
error(&"Test '{file.path}' has crashed!")
|
||||
else:
|
||||
let expectedOutput = compileExpectedOutput(file.path).replace(re"(\n*)$", "")
|
||||
let realOutputFile = open("testoutput.txt", fmRead)
|
||||
|
@ -103,17 +120,17 @@ proc main(testsDir: string, japlExec: string, testResultsFile: File): tuple[numO
|
|||
let comparison = deepComp(expectedOutput, realOutput)
|
||||
if comparison.same:
|
||||
successTests += 1
|
||||
log(testResultsFile, &"Test '{file.path}' was successful")
|
||||
log(&"Test '{file.path}' was successful")
|
||||
else:
|
||||
failedTests += 1
|
||||
detail(testResultsFile, &"Expected output:\n{expectedOutput}\n")
|
||||
detail(testResultsFile, &"Received output:\n{realOutput}\n")
|
||||
detail(testResultsFile, &"Mismatch at pos {comparison.place}")
|
||||
detail(&"Expected output:\n{expectedOutput}\n")
|
||||
detail(&"Received output:\n{realOutput}\n")
|
||||
detail(&"Mismatch at pos {comparison.place}")
|
||||
if comparison.place > expectedOutput.high() or comparison.place > realOutput.high():
|
||||
detail(testResultsFile, &"Length mismatch")
|
||||
detail(&"Length mismatch")
|
||||
else:
|
||||
detail(testResultsFile, &"Expected is '{expectedOutput[comparison.place]}' while received '{realOutput[comparison.place]}'")
|
||||
log(testResultsFile, &"Test '{file.path}' failed")
|
||||
detail(&"Expected is '{expectedOutput[comparison.place]}' while received '{realOutput[comparison.place]}'")
|
||||
error(&"Test '{file.path}' failed")
|
||||
result = (numOfTests: numOfTests, successTests: successTests, failedTests: failedTests, skippedTests: skippedTests)
|
||||
except IOError:
|
||||
stderr.write(&"Fatal IO error encountered while running tests -> {getCurrentExceptionMsg()}")
|
||||
|
@ -121,12 +138,14 @@ proc main(testsDir: string, japlExec: string, testResultsFile: File): tuple[numO
|
|||
|
||||
when isMainModule:
|
||||
let testResultsFile = open("testresults.txt", fmWrite)
|
||||
log(testResultsFile, "Running Nim tests")
|
||||
template log (msg: string) =
|
||||
logWithLevel(LogLevel.Info, testResultsFile, msg)
|
||||
log("Running Nim tests")
|
||||
# Nim tests
|
||||
detail(testResultsFile, "Running testMultiByte")
|
||||
logWithLevel(LogLevel.Debug, testResultsFile, "Running testMultiByte")
|
||||
testMultiByte()
|
||||
# JAPL tests
|
||||
log(testResultsFile, "Running JAPL tests")
|
||||
log("Running JAPL tests")
|
||||
var testsDir = "tests" / "japl"
|
||||
var japlExec = "src" / "japl"
|
||||
var currentDir = getCurrentDir()
|
||||
|
@ -134,16 +153,16 @@ when isMainModule:
|
|||
if currentDir.lastPathPart() == "tests":
|
||||
testsDir = "japl"
|
||||
japlExec = ".." / japlExec
|
||||
log(testResultsFile, &"Looking for JAPL tests in {testsDir}")
|
||||
log(testResultsFile, &"Looking for JAPL executable at {japlExec}")
|
||||
log(&"Looking for JAPL tests in {testsDir}")
|
||||
log(&"Looking for JAPL executable at {japlExec}")
|
||||
if not fileExists(japlExec):
|
||||
log(testResultsFile, "JAPL executable not found")
|
||||
log("JAPL executable not found")
|
||||
quit(1)
|
||||
if not dirExists(testsDir):
|
||||
log(testResultsFile, "Tests dir not found")
|
||||
log("Tests dir not found")
|
||||
quit(1)
|
||||
let testResult = main(testsDir, japlExec, testResultsFile)
|
||||
log(testResultsFile, &"Found {testResult.numOfTests} tests: {testResult.successTests} were successful, {testResult.failedTests} failed and {testResult.skippedTests} were skipped.")
|
||||
log(testResultsFile, "Check 'testresults.txt' for details", toFile=false)
|
||||
log(&"Found {testResult.numOfTests} tests: {testResult.successTests} were successful, {testResult.failedTests} failed and {testResult.skippedTests} were skipped.")
|
||||
logWithLevel(LogLevel.Stdout, testResultsFile, "Check 'testresults.txt' for details")
|
||||
testResultsfile.close()
|
||||
|
||||
|
|
Loading…
Reference in New Issue