Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
d22534388d | |||
e258b2d62e | |||
5afe6e6981 | |||
5d071d0299 | |||
180bfcb353 | |||
3161e6b4eb | |||
6129388a20 | |||
8f0cfe1a06 | |||
39926fb08b | |||
36594b64f2 | |||
9f898b6579 | |||
b1725b636b | |||
df3f1ea9d6 | |||
d749476d0c | |||
4456cd68d0 | |||
8f61b5648f | |||
5e1b378ac6 | |||
a0ed5c7a16 | |||
7a20c0a27f | |||
12414d7b5d | |||
addf9e51e9 | |||
24a6b7480b |
@ -26,6 +26,7 @@ mirror:
|
|||||||
snyk:
|
snyk:
|
||||||
stage: security
|
stage: security
|
||||||
script:
|
script:
|
||||||
|
- npmci npm prepare
|
||||||
- npmci command npm install -g snyk
|
- npmci command npm install -g snyk
|
||||||
- npmci command npm install --ignore-scripts
|
- npmci command npm install --ignore-scripts
|
||||||
- npmci command snyk test
|
- npmci command snyk test
|
||||||
@ -36,21 +37,11 @@ snyk:
|
|||||||
# ====================
|
# ====================
|
||||||
# test stage
|
# test stage
|
||||||
# ====================
|
# ====================
|
||||||
testLEGACY:
|
|
||||||
stage: test
|
|
||||||
script:
|
|
||||||
- npmci node install legacy
|
|
||||||
- npmci npm install
|
|
||||||
- npmci npm test
|
|
||||||
coverage: /\d+.?\d+?\%\s*coverage/
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
allow_failure: true
|
|
||||||
|
|
||||||
testLTS:
|
testLTS:
|
||||||
stage: test
|
stage: test
|
||||||
script:
|
script:
|
||||||
|
- npmci npm prepare
|
||||||
- npmci node install lts
|
- npmci node install lts
|
||||||
- npmci npm install
|
- npmci npm install
|
||||||
- npmci npm test
|
- npmci npm test
|
||||||
@ -62,6 +53,7 @@ testLTS:
|
|||||||
testSTABLE:
|
testSTABLE:
|
||||||
stage: test
|
stage: test
|
||||||
script:
|
script:
|
||||||
|
- npmci npm prepare
|
||||||
- npmci node install stable
|
- npmci node install stable
|
||||||
- npmci npm install
|
- npmci npm install
|
||||||
- npmci npm test
|
- npmci npm test
|
||||||
@ -118,6 +110,7 @@ pages:
|
|||||||
stage: metadata
|
stage: metadata
|
||||||
script:
|
script:
|
||||||
- npmci command npm install -g typedoc typescript
|
- npmci command npm install -g typedoc typescript
|
||||||
|
- npmci npm prepare
|
||||||
- npmci npm install
|
- npmci npm install
|
||||||
- npmci command typedoc --module "commonjs" --target "ES2016" --out public/ ts/
|
- npmci command typedoc --module "commonjs" --target "ES2016" --out public/ ts/
|
||||||
tags:
|
tags:
|
||||||
@ -130,13 +123,3 @@ pages:
|
|||||||
paths:
|
paths:
|
||||||
- public
|
- public
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
|
|
||||||
windowsCompatibility:
|
|
||||||
image: stefanscherer/node-windows:10-build-tools
|
|
||||||
stage: metadata
|
|
||||||
script:
|
|
||||||
- npm install & npm test
|
|
||||||
coverage: /\d+.?\d+?\%\s*coverage/
|
|
||||||
tags:
|
|
||||||
- windows
|
|
||||||
allow_failure: true
|
|
||||||
|
3
contribute.md
Normal file
3
contribute.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# How to contribute
|
||||||
|
|
||||||
|
Start with `tstest.classes.tstest.ts` to understand whats happening
|
1096
package-lock.json
generated
1096
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@gitzone/tstest",
|
"name": "@gitzone/tstest",
|
||||||
"version": "1.0.8",
|
"version": "1.0.19",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "a test utility to run tests that match test/**/*.ts",
|
"description": "a test utility to run tests that match test/**/*.ts",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
@ -19,15 +19,17 @@
|
|||||||
"build": "(tsbuild)"
|
"build": "(tsbuild)"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@gitzone/tsbuild": "^2.0.21",
|
"@gitzone/tsbuild": "^2.1.8",
|
||||||
"@pushrocks/tapbundle": "^3.0.1"
|
"@pushrocks/tapbundle": "^3.0.7"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gitzone/tsrun": "^1.1.9",
|
"@gitzone/tsrun": "^1.2.5",
|
||||||
"@pushrocks/consolecolor": "^2.0.1",
|
"@pushrocks/consolecolor": "^2.0.1",
|
||||||
"@pushrocks/smartfile": "^6.0.3",
|
"@pushrocks/smartfile": "^7.0.2",
|
||||||
"@pushrocks/smartlog": "^2.0.1",
|
"@pushrocks/smartlog": "^2.0.19",
|
||||||
"@pushrocks/smartpromise": "^2.0.5",
|
"@pushrocks/smartpromise": "^3.0.2",
|
||||||
"@pushrocks/smartshell": "^2.0.5"
|
"@pushrocks/smartshell": "^2.0.13",
|
||||||
|
"@types/figures": "^2.0.0",
|
||||||
|
"figures": "^2.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
48
ts/tstest.classes.tap.combinator.ts
Normal file
48
ts/tstest.classes.tap.combinator.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// ============
|
||||||
|
// combines different tap test files to an overall result
|
||||||
|
// ============
|
||||||
|
import * as plugins from './tstest.plugins';
|
||||||
|
import { coloredString as cs } from '@pushrocks/consolecolor';
|
||||||
|
|
||||||
|
import { TapParser } from './tstest.classes.tap.parser';
|
||||||
|
import * as logPrefixes from './tstest.logprefixes';
|
||||||
|
|
||||||
|
export class TapCombinator {
|
||||||
|
tapParserStore: TapParser[] = [];
|
||||||
|
addTapParser(tapParserArg: TapParser) {
|
||||||
|
this.tapParserStore.push(tapParserArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluate() {
|
||||||
|
console.log(
|
||||||
|
`${logPrefixes.TsTestPrefix} RESULTS FOR ${this.tapParserStore.length} TESTFILE(S):`
|
||||||
|
);
|
||||||
|
|
||||||
|
let failGlobal = false; // determine wether tstest should fail
|
||||||
|
for (const tapParser of this.tapParserStore) {
|
||||||
|
if (tapParser.getErrorTests().length === 0) {
|
||||||
|
let overviewString =
|
||||||
|
logPrefixes.TsTestPrefix +
|
||||||
|
cs(` ${tapParser.fileName} ${plugins.figures.tick}`, 'green') +
|
||||||
|
` ${plugins.figures.pointer} ` +
|
||||||
|
tapParser.getTestOverviewAsString();
|
||||||
|
console.log(overviewString);
|
||||||
|
} else {
|
||||||
|
let overviewString =
|
||||||
|
logPrefixes.TsTestPrefix +
|
||||||
|
cs(` ${tapParser.fileName} ${plugins.figures.cross}`, 'red') +
|
||||||
|
` ${plugins.figures.pointer} ` +
|
||||||
|
tapParser.getTestOverviewAsString();
|
||||||
|
console.log(overviewString);
|
||||||
|
failGlobal = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(cs(plugins.figures.hamburger.repeat(48), 'cyan'));
|
||||||
|
if (!failGlobal) {
|
||||||
|
console.log(cs('FINAL RESULT: SUCCESS!', 'green'));
|
||||||
|
} else {
|
||||||
|
console.log(cs('FINAL RESULT: FAIL!', 'red'));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
184
ts/tstest.classes.tap.parser.ts
Normal file
184
ts/tstest.classes.tap.parser.ts
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
import { ChildProcess } from 'child_process';
|
||||||
|
import { coloredString as cs } from '@pushrocks/consolecolor';
|
||||||
|
|
||||||
|
// ============
|
||||||
|
// combines different tap test files to an overall result
|
||||||
|
// ============
|
||||||
|
import * as plugins from './tstest.plugins';
|
||||||
|
import { TapTestResult } from './tstest.classes.tap.testresult';
|
||||||
|
import * as logPrefixes from './tstest.logprefixes';
|
||||||
|
|
||||||
|
export class TapParser {
|
||||||
|
testStore: TapTestResult[] = [];
|
||||||
|
|
||||||
|
expectedTestsRegex = /([0-9]*)\.\.([0-9]*)$/;
|
||||||
|
expectedTests: number;
|
||||||
|
receivedTests: number;
|
||||||
|
|
||||||
|
testStatusRegex = /(ok|not\sok)\s([0-9]+)\s-\s(.*)\s#\stime=(.*)ms$/;
|
||||||
|
activeTapTestResult: TapTestResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the constructor for TapParser
|
||||||
|
*/
|
||||||
|
constructor(public fileName: string) {}
|
||||||
|
|
||||||
|
private _getNewTapTestResult() {
|
||||||
|
this.activeTapTestResult = new TapTestResult(this.testStore.length + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _processLog(logChunk: Buffer | string) {
|
||||||
|
if (Buffer.isBuffer(logChunk)) {
|
||||||
|
logChunk = logChunk.toString();
|
||||||
|
}
|
||||||
|
const logLineArray = logChunk.split('\n');
|
||||||
|
if (logLineArray[logLineArray.length - 1] === '') {
|
||||||
|
logLineArray.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// lets parse the log information
|
||||||
|
for (const logLine of logLineArray) {
|
||||||
|
let logLineIsTapProtocol = false;
|
||||||
|
if (!this.expectedTests && this.expectedTestsRegex.test(logLine)) {
|
||||||
|
logLineIsTapProtocol = true;
|
||||||
|
const regexResult = this.expectedTestsRegex.exec(logLine);
|
||||||
|
this.expectedTests = parseInt(regexResult[2]);
|
||||||
|
console.log(
|
||||||
|
`${logPrefixes.TapPrefix} ${cs(`Expecting ${this.expectedTests} tests!`, 'blue')}`
|
||||||
|
);
|
||||||
|
|
||||||
|
// initiating first TapResult
|
||||||
|
this._getNewTapTestResult();
|
||||||
|
} else if (this.testStatusRegex.test(logLine)) {
|
||||||
|
logLineIsTapProtocol = true;
|
||||||
|
const regexResult = this.testStatusRegex.exec(logLine);
|
||||||
|
const testId = parseInt(regexResult[2]);
|
||||||
|
const testOk = (() => {
|
||||||
|
if (regexResult[1] === 'ok') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})();
|
||||||
|
|
||||||
|
const testSubject = regexResult[3];
|
||||||
|
const testDuration = parseInt(regexResult[4]);
|
||||||
|
|
||||||
|
// test for protocol error
|
||||||
|
if (testId !== this.activeTapTestResult.id) {
|
||||||
|
console.log(
|
||||||
|
`${logPrefixes.TapErrorPrefix} Something is strange! Test Ids are not equal!`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.activeTapTestResult.setTestResult(testOk);
|
||||||
|
|
||||||
|
if (testOk) {
|
||||||
|
console.log(
|
||||||
|
logPrefixes.TapPrefix,
|
||||||
|
`${cs(`T${testId} ${plugins.figures.tick}`, 'green')} ${plugins.figures.arrowRight} ` +
|
||||||
|
cs(testSubject, 'blue') +
|
||||||
|
` | ${cs(`${testDuration} ms`, 'orange')}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
logPrefixes.TapPrefix,
|
||||||
|
`${cs(`T${testId} ${plugins.figures.cross}`, 'red')} ${plugins.figures.arrowRight} ` +
|
||||||
|
cs(testSubject, 'blue') +
|
||||||
|
` | ${cs(`${testDuration} ms`, 'orange')}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!logLineIsTapProtocol) {
|
||||||
|
if (this.activeTapTestResult) {
|
||||||
|
this.activeTapTestResult.addLogLine(logLine);
|
||||||
|
}
|
||||||
|
console.log(logLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.activeTapTestResult && this.activeTapTestResult.testSettled) {
|
||||||
|
this.testStore.push(this.activeTapTestResult);
|
||||||
|
this._getNewTapTestResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns all tests that are not completed
|
||||||
|
*/
|
||||||
|
getUncompletedTests() {
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns all tests that threw an error
|
||||||
|
*/
|
||||||
|
getErrorTests() {
|
||||||
|
return this.testStore.filter(tapTestArg => {
|
||||||
|
return !tapTestArg.testOk;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a test overview as string
|
||||||
|
*/
|
||||||
|
getTestOverviewAsString() {
|
||||||
|
let overviewString = '';
|
||||||
|
for (let test of this.testStore) {
|
||||||
|
if (overviewString !== '') {
|
||||||
|
overviewString += ' | ';
|
||||||
|
}
|
||||||
|
if (test.testOk) {
|
||||||
|
overviewString += cs(`T${test.id} ${plugins.figures.tick}`, 'green');
|
||||||
|
} else {
|
||||||
|
overviewString += cs(`T${test.id} ${plugins.figures.cross}`, 'red');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return overviewString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handles a tap process
|
||||||
|
* @param childProcessArg
|
||||||
|
*/
|
||||||
|
async handleTapProcess(childProcessArg: ChildProcess) {
|
||||||
|
const done = plugins.smartpromise.defer();
|
||||||
|
childProcessArg.stdout.on('data', data => {
|
||||||
|
this._processLog(data);
|
||||||
|
});
|
||||||
|
childProcessArg.stderr.on('data', data => {
|
||||||
|
this._processLog(data);
|
||||||
|
});
|
||||||
|
childProcessArg.on('exit', () => {
|
||||||
|
this.receivedTests = this.testStore.length;
|
||||||
|
|
||||||
|
// check wether all tests ran
|
||||||
|
if (this.expectedTests === this.receivedTests) {
|
||||||
|
console.log(
|
||||||
|
`${logPrefixes.TapPrefix} ${cs(
|
||||||
|
`${this.receivedTests} out of ${this.expectedTests} Tests completed!`,
|
||||||
|
'green'
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
`${logPrefixes.TapErrorPrefix} ${cs(
|
||||||
|
`Only ${this.receivedTests} out of ${this.expectedTests} completed!`,
|
||||||
|
'red'
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.getErrorTests().length === 0) {
|
||||||
|
console.log(`${logPrefixes.TapPrefix} ${cs(`All tests are successfull!!!`, 'green')}`);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
`${logPrefixes.TapPrefix} ${cs(
|
||||||
|
`${this.getErrorTests().length} tests threw an error!!!`,
|
||||||
|
'red'
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
done.resolve();
|
||||||
|
});
|
||||||
|
await done.promise;
|
||||||
|
}
|
||||||
|
}
|
@ -3,9 +3,9 @@ import * as paths from './tstest.paths';
|
|||||||
import { Smartfile } from '@pushrocks/smartfile';
|
import { Smartfile } from '@pushrocks/smartfile';
|
||||||
|
|
||||||
// tap related stuff
|
// tap related stuff
|
||||||
import { TapCombinator } from './tstest.tap.combinator';
|
import { TapCombinator } from './tstest.classes.tap.combinator';
|
||||||
import { TapParser } from './tstest.tap.parser';
|
import { TapParser } from './tstest.classes.tap.parser';
|
||||||
import { TapTestResult } from './tstest.tap.testresult';
|
import { TapTestResult } from './tstest.classes.tap.testresult';
|
||||||
|
|
||||||
export class TestDirectory {
|
export class TestDirectory {
|
||||||
/**
|
/**
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import * as plugins from './tstest.plugins';
|
import * as plugins from './tstest.plugins';
|
||||||
import * as paths from './tstest.paths';
|
import * as paths from './tstest.paths';
|
||||||
|
import * as logPrefixes from './tstest.logprefixes';
|
||||||
|
|
||||||
import { coloredString as cs } from '@pushrocks/consolecolor';
|
import { coloredString as cs } from '@pushrocks/consolecolor';
|
||||||
|
|
||||||
import { TestDirectory } from './tstest.classes.testdirectory';
|
import { TestDirectory } from './tstest.classes.testdirectory';
|
||||||
import { TapCombinator } from './tstest.tap.combinator';
|
import { TapCombinator } from './tstest.classes.tap.combinator';
|
||||||
import { TapParser } from './tstest.tap.parser';
|
import { TapParser } from './tstest.classes.tap.parser';
|
||||||
|
|
||||||
export class TsTest {
|
export class TsTest {
|
||||||
testDir: TestDirectory;
|
testDir: TestDirectory;
|
||||||
@ -15,11 +17,13 @@ export class TsTest {
|
|||||||
|
|
||||||
async run() {
|
async run() {
|
||||||
const fileNamesToRun: string[] = await this.testDir.getTestFilePathArray();
|
const fileNamesToRun: string[] = await this.testDir.getTestFilePathArray();
|
||||||
console.log(`Found ${fileNamesToRun.length} Testfile(s):`);
|
console.log(cs(plugins.figures.hamburger.repeat(80), 'cyan'));
|
||||||
|
console.log('');
|
||||||
|
console.log(`${logPrefixes.TsTestPrefix} FOUND ${fileNamesToRun.length} TESTFILE(S):`);
|
||||||
for (const fileName of fileNamesToRun) {
|
for (const fileName of fileNamesToRun) {
|
||||||
console.log(cs(fileName, 'orange'));
|
console.log(`${logPrefixes.TsTestPrefix} ${cs(fileName, 'orange')}`);
|
||||||
}
|
}
|
||||||
console.log('-'.repeat(16));
|
console.log('-'.repeat(48));
|
||||||
console.log(''); // force new line
|
console.log(''); // force new line
|
||||||
const smartshellInstance = new plugins.smartshell.Smartshell({
|
const smartshellInstance = new plugins.smartshell.Smartshell({
|
||||||
executor: 'bash',
|
executor: 'bash',
|
||||||
@ -30,8 +34,17 @@ export class TsTest {
|
|||||||
for (const fileName of fileNamesToRun) {
|
for (const fileName of fileNamesToRun) {
|
||||||
console.log(`${cs('=> ', 'blue')} Running ${cs(fileName, 'orange')}`);
|
console.log(`${cs('=> ', 'blue')} Running ${cs(fileName, 'orange')}`);
|
||||||
console.log(cs(`=`.repeat(16), 'cyan'));
|
console.log(cs(`=`.repeat(16), 'cyan'));
|
||||||
const tapParser = new TapParser();
|
const tapParser = new TapParser(fileName);
|
||||||
const execResultStreaming = await smartshellInstance.execStreamingSilent(`tsrun ${fileName}`);
|
|
||||||
|
// tsrun options
|
||||||
|
let tsrunOptions = '';
|
||||||
|
if (process.argv.includes('--web')) {
|
||||||
|
tsrunOptions += ' --web';
|
||||||
|
}
|
||||||
|
|
||||||
|
const execResultStreaming = await smartshellInstance.execStreamingSilent(
|
||||||
|
`tsrun ${fileName}${tsrunOptions}`
|
||||||
|
);
|
||||||
await tapParser.handleTapProcess(execResultStreaming.childProcess);
|
await tapParser.handleTapProcess(execResultStreaming.childProcess);
|
||||||
console.log(cs(`^`.repeat(16), 'cyan'));
|
console.log(cs(`^`.repeat(16), 'cyan'));
|
||||||
console.log(''); // force new line
|
console.log(''); // force new line
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
import * as plugins from './tstest.plugins';
|
import * as plugins from './tstest.plugins';
|
||||||
|
import { coloredString as cs } from '@pushrocks/consolecolor';
|
||||||
|
|
||||||
export const TapPrefix = plugins.consolecolor.coloredString(`:::TAP:::`, 'green', 'black');
|
export const TapPrefix = cs(`::TAP::`, 'pink', 'black');
|
||||||
|
export const TapErrorPrefix = cs(` !!!TAP PROTOCOL ERROR!!! `, 'red', 'black');
|
||||||
|
|
||||||
|
export const TsTestPrefix = cs(`**TSTEST**`, 'pink', 'black');
|
||||||
|
@ -8,4 +8,7 @@ import * as smartlog from '@pushrocks/smartlog';
|
|||||||
import * as smartpromise from '@pushrocks/smartpromise';
|
import * as smartpromise from '@pushrocks/smartpromise';
|
||||||
import * as smartshell from '@pushrocks/smartshell';
|
import * as smartshell from '@pushrocks/smartshell';
|
||||||
|
|
||||||
export { consolecolor, path, smartfile, smartlog, smartpromise, smartshell };
|
// sindresorhus
|
||||||
|
import * as figures from 'figures';
|
||||||
|
|
||||||
|
export { consolecolor, figures, path, smartfile, smartlog, smartpromise, smartshell };
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
// ============
|
|
||||||
// combines different tap test files to an overall result
|
|
||||||
// ============
|
|
||||||
import * as plugins from './tstest.plugins';
|
|
||||||
import { coloredString as cs } from '@pushrocks/consolecolor';
|
|
||||||
|
|
||||||
import { TapParser } from './tstest.tap.parser';
|
|
||||||
|
|
||||||
export class TapCombinator {
|
|
||||||
tapParserStore: TapParser[] = [];
|
|
||||||
addTapParser(tapParserArg: TapParser) {
|
|
||||||
this.tapParserStore.push(tapParserArg);
|
|
||||||
}
|
|
||||||
|
|
||||||
evaluate() {
|
|
||||||
console.log(`Ran ${this.tapParserStore.length} Testfiles!`);
|
|
||||||
for (const tapParser of this.tapParserStore) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,108 +0,0 @@
|
|||||||
import { ChildProcess } from 'child_process';
|
|
||||||
import { coloredString as cs } from '@pushrocks/consolecolor';
|
|
||||||
|
|
||||||
// ============
|
|
||||||
// combines different tap test files to an overall result
|
|
||||||
// ============
|
|
||||||
import * as plugins from './tstest.plugins';
|
|
||||||
import { TapTestResult } from './tstest.tap.testresult';
|
|
||||||
import * as logPrefixes from './tstest.logprefixes';
|
|
||||||
|
|
||||||
export class TapParser {
|
|
||||||
resultStore: TapTestResult[] = [];
|
|
||||||
|
|
||||||
expectedTestsRegex = /([0-9]*)\.\.([0-9]*)/;
|
|
||||||
expectedTests: number;
|
|
||||||
|
|
||||||
testStatusRegex = /(ok|not\sok)\s([0-9]+)\s-\s(.*)\s#\stime=(.*)ms$/;
|
|
||||||
activeTapTestResult: TapTestResult;
|
|
||||||
|
|
||||||
private _getNewTapTestResult() {
|
|
||||||
this.activeTapTestResult = new TapTestResult(this.resultStore.length + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _processLog(logChunk: Buffer | string) {
|
|
||||||
if (Buffer.isBuffer(logChunk)) {
|
|
||||||
logChunk = logChunk.toString();
|
|
||||||
}
|
|
||||||
const logLineArray = logChunk.split('\n');
|
|
||||||
if (logLineArray[logLineArray.length - 1] === '') {
|
|
||||||
logLineArray.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// lets parse the log information
|
|
||||||
for (const logLine of logLineArray) {
|
|
||||||
let logLineIsTapProtocol = false;
|
|
||||||
if (!this.expectedTests && this.expectedTestsRegex.test(logLine)) {
|
|
||||||
logLineIsTapProtocol = true;
|
|
||||||
const regexResult = this.expectedTestsRegex.exec(logLine);
|
|
||||||
this.expectedTests = parseInt(regexResult[2]);
|
|
||||||
console.log(`:::TAP::: Expecting ${this.expectedTests} tests!`);
|
|
||||||
|
|
||||||
// initiating first TapResult
|
|
||||||
this._getNewTapTestResult();
|
|
||||||
} else if (this.testStatusRegex.test(logLine)) {
|
|
||||||
logLineIsTapProtocol = true;
|
|
||||||
const regexResult = this.testStatusRegex.exec(logLine);
|
|
||||||
const testId = parseInt(regexResult[2]);
|
|
||||||
const testOk = (() => {
|
|
||||||
if (regexResult[1] === 'ok') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
})();
|
|
||||||
|
|
||||||
const testSubject = regexResult[3];
|
|
||||||
const testDuration = parseInt(regexResult[4]);
|
|
||||||
|
|
||||||
// test for protocol error
|
|
||||||
if (testId !== this.activeTapTestResult.id) {
|
|
||||||
console.log(`:::TAP PROTOCOL ERROR::: Something is strange! Test Ids are not equal!`);
|
|
||||||
}
|
|
||||||
this.activeTapTestResult.setTestResult(testOk);
|
|
||||||
|
|
||||||
if (testOk) {
|
|
||||||
console.log(
|
|
||||||
logPrefixes.TapPrefix,
|
|
||||||
` ${cs(`Test ${testId} -> Success!`, 'green')} | ` +
|
|
||||||
cs(testSubject, 'blue') +
|
|
||||||
` | ${cs(`${testDuration} milliseconds`, 'orange')}`
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
console.log(
|
|
||||||
logPrefixes.TapPrefix,
|
|
||||||
` ${cs(`Test ${testId} -> Error!`, 'red')} | ` +
|
|
||||||
cs(testSubject, 'blue') +
|
|
||||||
` | ${cs(`${testDuration} milliseconds`, 'orange')}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!logLineIsTapProtocol) {
|
|
||||||
if (this.activeTapTestResult) {
|
|
||||||
this.activeTapTestResult.addLogLine(logLine);
|
|
||||||
}
|
|
||||||
console.log(logLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.activeTapTestResult && this.activeTapTestResult.testSettled) {
|
|
||||||
this.resultStore.push(this.activeTapTestResult);
|
|
||||||
this._getNewTapTestResult();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleTapProcess(childProcessArg: ChildProcess) {
|
|
||||||
const done = plugins.smartpromise.defer();
|
|
||||||
childProcessArg.stdout.on('data', data => {
|
|
||||||
this._processLog(data);
|
|
||||||
});
|
|
||||||
childProcessArg.stderr.on('data', data => {
|
|
||||||
this._processLog(data);
|
|
||||||
});
|
|
||||||
childProcessArg.on('exit', () => {
|
|
||||||
done.resolve();
|
|
||||||
});
|
|
||||||
await done.promise;
|
|
||||||
}
|
|
||||||
}
|
|
16
tslint.json
16
tslint.json
@ -1,3 +1,17 @@
|
|||||||
{
|
{
|
||||||
"extends": "tslint-config-standard"
|
"extends": ["tslint:latest", "tslint-config-prettier"],
|
||||||
|
"rules": {
|
||||||
|
"semicolon": [true, "always"],
|
||||||
|
"no-console": false,
|
||||||
|
"ordered-imports": false,
|
||||||
|
"object-literal-sort-keys": false,
|
||||||
|
"member-ordering": {
|
||||||
|
"options":{
|
||||||
|
"order": [
|
||||||
|
"static-method"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultSeverity": "warning"
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user