Add initial unit testing logic (#708)
Adds initial logic to allow for some form of basic unit testing.
This commit is contained in:
parent
11787b3896
commit
f427583ec4
|
@ -440,6 +440,19 @@
|
|||
"Path": "sh_northstar_safe_io.gnut",
|
||||
"RunOn": "CLIENT || SERVER || UI"
|
||||
},
|
||||
{
|
||||
"Path": "_testing.nut",
|
||||
"RunOn": "CLIENT || SERVER || UI",
|
||||
"ClientCallback": {
|
||||
"Before": "Testing_Init"
|
||||
},
|
||||
"ServerCallback": {
|
||||
"Before": "Testing_Init"
|
||||
},
|
||||
"UICallback": {
|
||||
"Before": "Testing_Init"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Path": "_event_models.gnut",
|
||||
"RunOn": "SERVER && LOBBY",
|
||||
|
|
|
@ -0,0 +1,302 @@
|
|||
global function Testing_Init
|
||||
global function RunAllTests
|
||||
global function RunAllTests_SaveToFile
|
||||
global function RunTestsByCategory
|
||||
global function RunTestByCategoryAndName
|
||||
|
||||
global function AddTest
|
||||
|
||||
struct TestInfo
|
||||
{
|
||||
string testName
|
||||
var functionref() callback
|
||||
// whether the test completed successfully
|
||||
// if this is true, actualResult is valid
|
||||
bool completed
|
||||
// var not string because then i can just set it to an exception
|
||||
// which print can then handle
|
||||
var error
|
||||
// whether the test is considered successful
|
||||
var expectedResult
|
||||
var actualResult
|
||||
bool passed
|
||||
}
|
||||
|
||||
struct {
|
||||
table< string, array< TestInfo > > tests = {}
|
||||
} file
|
||||
|
||||
void function Testing_Init()
|
||||
{
|
||||
// tests for the testing functions :)
|
||||
//AddTest( "Example Tests", "example succeeding test", ExampleTest_ReturnsTrue, true )
|
||||
//AddTest( "Example Tests", "example failing test", ExampleTest_ReturnsFalse, true )
|
||||
//AddTest( "Example Tests", "example erroring test", ExampleTest_ThrowsError, true )
|
||||
//AddTest( "Example Tests", "example test with args", var function() {
|
||||
// return ExampleTest_HasArgs_ReturnsNonVar( 2, 3 )
|
||||
//}, 6 )
|
||||
}
|
||||
|
||||
int function ExampleTest_HasArgs_ReturnsNonVar( int first, int second )
|
||||
{
|
||||
return first * second
|
||||
}
|
||||
|
||||
var function ExampleTest_ReturnsFalse()
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
var function ExampleTest_ReturnsTrue()
|
||||
{
|
||||
return true
|
||||
}
|
||||
|
||||
var function ExampleTest_ThrowsError()
|
||||
{
|
||||
throw "Example exception"
|
||||
return null
|
||||
}
|
||||
|
||||
void function RunAllTests_SaveToFile()
|
||||
{
|
||||
RunAllTests()
|
||||
|
||||
#if UI
|
||||
string fileName = "ns-unit-tests-UI.json"
|
||||
#elseif CLIENT
|
||||
string fileName = "ns-unit-tests-CLIENT.json"
|
||||
#elseif SERVER
|
||||
string fileName = "ns-unit-tests-SERVER.json"
|
||||
#endif
|
||||
|
||||
// cant encode structs so have to reconstruct a table manually from the structs
|
||||
table out = {}
|
||||
foreach ( category, tests in file.tests )
|
||||
{
|
||||
array categoryResults = []
|
||||
foreach ( test in tests )
|
||||
{
|
||||
table testTable = {}
|
||||
testTable[ "name" ] <- test.testName
|
||||
testTable[ "completed" ] <- test.completed
|
||||
testTable[ "passed" ] <- test.passed
|
||||
if ( !test.completed )
|
||||
testTable[ "error" ] <- test.error
|
||||
else if ( !test.passed )
|
||||
{
|
||||
testTable[ "expectedResult" ] <- test.expectedResult
|
||||
testTable[ "actualResult" ] <- test.actualResult
|
||||
}
|
||||
|
||||
categoryResults.append( testTable )
|
||||
}
|
||||
out[ category ] <- categoryResults
|
||||
}
|
||||
|
||||
NSSaveJSONFile( fileName, out )
|
||||
}
|
||||
|
||||
void function RunAllTests()
|
||||
{
|
||||
printt( "Running all tests!" )
|
||||
|
||||
foreach ( category, categoryTests in file.tests )
|
||||
{
|
||||
foreach ( test in categoryTests )
|
||||
{
|
||||
RunTest( test )
|
||||
}
|
||||
}
|
||||
|
||||
PrintAllTestResults()
|
||||
}
|
||||
|
||||
void function RunTestsByCategory( string category )
|
||||
{
|
||||
if ( !( category in file.tests ) )
|
||||
{
|
||||
printt( format( "Category '%s' has no tests registered", category ) )
|
||||
return
|
||||
}
|
||||
|
||||
foreach ( categoryTest in file.tests[ category ] )
|
||||
{
|
||||
RunTest( categoryTest )
|
||||
}
|
||||
}
|
||||
|
||||
void function RunTestByCategoryAndName( string category, string testName )
|
||||
{
|
||||
// find test
|
||||
if ( !( category in file.tests ) )
|
||||
{
|
||||
printt( format( "Category '%s' has no tests registered", category ) )
|
||||
return
|
||||
}
|
||||
|
||||
TestInfo ornull foundTest = null
|
||||
foreach ( categoryTest in file.tests[ category ] )
|
||||
{
|
||||
if ( categoryTest.testName == testName )
|
||||
{
|
||||
foundTest = categoryTest
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ( !foundTest )
|
||||
{
|
||||
printt( format( "Category '%s' does not contain a test with name '%s'", category, testName ) )
|
||||
return
|
||||
}
|
||||
|
||||
expect TestInfo( foundTest )
|
||||
|
||||
printt( "Running test!" )
|
||||
// run test
|
||||
RunTest( foundTest )
|
||||
// print result
|
||||
PrintTestResult( foundTest )
|
||||
}
|
||||
|
||||
void function RunTest( TestInfo test )
|
||||
{
|
||||
test.completed = false
|
||||
test.passed = false
|
||||
test.actualResult = null
|
||||
test.error = ""
|
||||
|
||||
try
|
||||
{
|
||||
test.actualResult = test.callback()
|
||||
test.completed = true
|
||||
test.passed = test.actualResult == test.expectedResult
|
||||
}
|
||||
catch ( exception )
|
||||
{
|
||||
test.completed = false
|
||||
test.error = exception
|
||||
}
|
||||
}
|
||||
|
||||
void function PrintAllTestResults()
|
||||
{
|
||||
int totalSucceeded = 0
|
||||
int totalFailed = 0
|
||||
int totalErrored = 0
|
||||
|
||||
foreach ( category, categoryTests in file.tests )
|
||||
{
|
||||
int categorySucceeded = 0
|
||||
int categoryFailed = 0
|
||||
int categoryErrored = 0
|
||||
|
||||
printt( format( "Results for category: '%s'", category ) )
|
||||
foreach ( test in categoryTests )
|
||||
{
|
||||
if ( test.completed )
|
||||
{
|
||||
if ( test.passed )
|
||||
{
|
||||
printt( "\t", test.testName, "- Passed!" )
|
||||
categorySucceeded++
|
||||
}
|
||||
else
|
||||
{
|
||||
printt( "\t", test.testName, "- Failed!" )
|
||||
printt( "\t\tExpected:", test.expectedResult )
|
||||
printt( "\t\tActual: ", test.actualResult )
|
||||
categoryFailed++
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printt( "\t", test.testName, "- Errored!" )
|
||||
printt( "\t\tError:", test.error )
|
||||
categoryErrored++
|
||||
}
|
||||
}
|
||||
|
||||
printt( "Succeeded:", categorySucceeded, "Failed:", categoryFailed, "Errored:", categoryErrored )
|
||||
|
||||
totalSucceeded += categorySucceeded
|
||||
totalFailed += categoryFailed
|
||||
totalErrored += categoryErrored
|
||||
}
|
||||
|
||||
printt( "TOTAL SUCCEEDED:", totalSucceeded, "TOTAL FAILED:", totalFailed, "TOTAL ERRORED:", totalErrored )
|
||||
}
|
||||
|
||||
void function PrintCategoryResults( string category )
|
||||
{
|
||||
int categorySucceeded = 0
|
||||
int categoryFailed = 0
|
||||
int categoryErrored = 0
|
||||
|
||||
printt( format( "Results for category: '%s'", category ) )
|
||||
foreach ( test in file.tests[ category ] )
|
||||
{
|
||||
if ( test.completed )
|
||||
{
|
||||
if ( test.passed )
|
||||
{
|
||||
printt( "\t", test.testName, "- Passed!" )
|
||||
categorySucceeded++
|
||||
}
|
||||
else
|
||||
{
|
||||
printt( "\t", test.testName, "- Failed!" )
|
||||
printt( "\t\tExpected:", test.expectedResult )
|
||||
printt( "\t\tActual: ", test.actualResult )
|
||||
categoryFailed++
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printt( "\t", test.testName, "- Errored!" )
|
||||
printt( "\t\tError:", test.error )
|
||||
categoryErrored++
|
||||
}
|
||||
}
|
||||
|
||||
printt( "Succeeded:", categorySucceeded, "Failed:", categoryFailed, "Errored:", categoryErrored )
|
||||
}
|
||||
|
||||
void function PrintTestResult( TestInfo test )
|
||||
{
|
||||
string resultString = test.testName
|
||||
|
||||
if ( test.completed )
|
||||
{
|
||||
if ( test.passed )
|
||||
resultString += " - Passed!"
|
||||
else
|
||||
{
|
||||
resultString += " - Failed!"
|
||||
resultString += "\n\tExpected: " + test.expectedResult
|
||||
resultString += "\n\tActual: " + test.actualResult
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resultString += " - Not completed!"
|
||||
resultString += "\n\tError: " + test.error
|
||||
}
|
||||
|
||||
printt( resultString )
|
||||
}
|
||||
|
||||
void function AddTest( string testCategory, string testName, var functionref() testFunc, var expectedResult )
|
||||
{
|
||||
TestInfo newTest
|
||||
newTest.testName = testName
|
||||
newTest.callback = testFunc
|
||||
newTest.expectedResult = expectedResult
|
||||
|
||||
// create the test category if it doesn't exist
|
||||
if ( !( testCategory in file.tests ) )
|
||||
file.tests[ testCategory ] <- [ newTest ]
|
||||
else
|
||||
file.tests[ testCategory ].append( newTest )
|
||||
}
|
Loading…
Reference in New Issue