Skip to content

Commit a830ef7

Browse files
committed
Add reporter and license
1 parent 5438698 commit a830ef7

File tree

4 files changed

+166
-0
lines changed

4 files changed

+166
-0
lines changed

CodewarsReporter.cfc

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* Renders TestResult from TestBox in Codewars format.
3+
* Based on `CLIRenderer@testbox-commands`.
4+
*/
5+
component {
6+
7+
/**
8+
* @print a print buffer to use
9+
* @testData test results from TestBox
10+
*/
11+
function render( print, testData ){
12+
for ( thisBundle in testData.bundleStats ) {
13+
// Check if the bundle threw a global exception
14+
if ( !isSimpleValue( thisBundle.globalException ) ) {
15+
var message = escapeLF(
16+
"#thisBundle.globalException.type#:#thisBundle.globalException.message#:#thisBundle.globalException.detail#"
17+
);
18+
print.line( prependLF( "<ERROR::>#message#" ) );
19+
20+
// ACF has an array for the stack trace
21+
if ( isSimpleValue( thisBundle.globalException.stacktrace ) ) {
22+
print.line( prependLF( "<LOG::-Stacktrace>#escapeLF( thisBundle.globalException.stacktrace )#" ) );
23+
}
24+
}
25+
26+
// Generate reports for each suite
27+
for ( var suiteStats in thisBundle.suiteStats ) {
28+
genSuiteReport( suiteStats = suiteStats, bundleStats = thisBundle, print = print );
29+
}
30+
}
31+
}
32+
33+
/**
34+
* Recursive Output for suites
35+
* @suiteStats Suite stats
36+
* @bundleStats Bundle stats
37+
* @print The print Buffer
38+
*/
39+
function genSuiteReport( required suiteStats, required bundleStats, required print ){
40+
print.line( prependLF( "<DESCRIBE::>#arguments.suiteStats.name#" ) );
41+
42+
for ( local.thisSpec in arguments.suiteStats.specStats ) {
43+
print.line( prependLF( "<IT::>#local.thisSpec.name#" ) );
44+
45+
if ( local.thisSpec.status == "passed" ) {
46+
print.line( prependLF( "<PASSED::>Test Passed" ) );
47+
} else if ( local.thisSpec.status == "failed" ) {
48+
print.line( prependLF( "<FAILED::>#escapeLF( local.thisSpec.failMessage )#" ) );
49+
} else if ( local.thisSpec.status == "error" ) {
50+
print.line( prependLF( "<ERROR::>#escapeLF( local.thisSpec.error.message )#" ) );
51+
52+
var errorStack = [];
53+
// If there's a tag context, show the file name and line number where the error occurred
54+
if (
55+
isDefined( "local.thisSpec.error.tagContext" ) && isArray( local.thisSpec.error.tagContext ) && local.thisSpec.error.tagContext.len()
56+
) {
57+
errorStack = thisSpec.error.tagContext;
58+
} else if (
59+
isDefined( "local.thisSpec.failOrigin" ) && isArray( local.thisSpec.failOrigin ) && local.thisSpec.failOrigin.len()
60+
) {
61+
errorStack = thisSpec.failOrigin;
62+
}
63+
64+
if ( errorStack.len() ) {
65+
var stacktrace = errorStack
66+
.slice( 1, 5 )
67+
.map( function( item ){
68+
return "at #item.template#:#item.line#";
69+
} )
70+
.toList( "<:LF:>" );
71+
print.line( prependLF( "<LOG::-Stacktrace>#stacktrace#" ) );
72+
}
73+
} else {
74+
print.line( prependLF( "<ERROR::>Unknown test status: #local.thisSpec.status#" ) );
75+
}
76+
77+
print.line( prependLF( "<COMPLETEDIN::>#local.thisSpec.totalDuration#" ) );
78+
}
79+
80+
// Handle nested Suites
81+
if ( arguments.suiteStats.suiteStats.len() ) {
82+
for ( local.nestedSuite in arguments.suiteStats.suiteStats ) {
83+
genSuiteReport( local.nestedSuite, arguments.bundleStats, print )
84+
}
85+
}
86+
87+
print.line( prependLF( "<COMPLETEDIN::>#arguments.suiteStats.totalDuration#" ) );
88+
}
89+
90+
private function escapeLF( required text ){
91+
return replace( text, chr( 10 ), "<:LF:>", "all" );
92+
}
93+
94+
private function prependLF( required text ){
95+
return "#chr( 10 )##text#";
96+
}
97+
98+
}

LICENSE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2020 Qualified Inc.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
## testbox-codewars
2+
3+
- `CodewarsReporter`: Custom reporter for TestBox to produce Codewars format
4+
- `TestRunner`: Runs TestBox tests and produces output for Codewars
5+
6+
### Usage
7+
8+
```
9+
box task run TestRunner
10+
```

TestRunner.cfc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* Runs TestBox test and outputs in Codewars format.
3+
* To use, run:
4+
* box task run TestRunner
5+
*/
6+
component {
7+
8+
function run(){
9+
// Bootstrap TestBox framework
10+
filesystemUtil.createMapping( "/testbox", getCWD() & "/testbox" );
11+
12+
// Create TestBox and run the tests
13+
testData = new testbox.system.TestBox()
14+
.runRaw(
15+
directory = {
16+
// Find all CFCs in this directory that ends with Test.
17+
mapping : filesystemUtil.makePathRelative( getCWD() ),
18+
recurse : false,
19+
filter = function( path ){
20+
return path.reFindNoCase( "Test.cfc$" );
21+
}
22+
}
23+
)
24+
.getMemento();
25+
26+
createObject( "CodewarsReporter" ).render( print, testData );
27+
28+
// Flush the buffer
29+
print.toConsole();
30+
31+
// Set exit code to 1 on failure
32+
if ( testData.totalFail || testData.totalError ) {
33+
return 1;
34+
}
35+
}
36+
37+
}

0 commit comments

Comments
 (0)