UNPKG

vscode-tmgrammar-test

Version:
351 lines 14.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ConsoleFullReporter = exports.ConsoleCompactReporter = exports.XunitGitlabReporter = exports.XunitGenericReporter = exports.CompositeReporter = void 0; const chalk_1 = __importDefault(require("chalk")); const fs = __importStar(require("fs")); const p = __importStar(require("path")); const tty = __importStar(require("tty")); const os_1 = require("os"); const path_1 = require("path"); class CompositeReporter { constructor(...reporters) { this.reporters = reporters; } reportTestResult(filename, testCase, failures) { this.reporters.forEach(r => r.reportTestResult(filename, testCase, failures)); } reportGrammarTestError(filename, testCase, reason) { this.reporters.forEach(r => r.reportGrammarTestError(filename, testCase, reason)); } reportParseError(filename, error) { this.reporters.forEach(r => r.reportParseError(filename, error)); } reportSuiteResult() { this.reporters.forEach(r => r.reportSuiteResult()); } } exports.CompositeReporter = CompositeReporter; class XunitReportPerTestReporter { constructor(reportPath) { this.reportPath = reportPath; // follows this schema https://maven.apache.org/surefire/maven-surefire-plugin/xsd/surefire-test-report.xsd // produces report in a way which looks nice when viewed in GitLab CI/CD web GUI, but is not neccesarily semantically correct this.suites = []; } reportParseError(filename, error) { const suite = this.getSuite(filename); suite.cases.push({ name: "Parse test file", classname: this.caseClassname(filename), failures: [{ type: 'error', message: "Failed to parse test file", body: `${error}` }] }); } reportGrammarTestError(filename, parsedFile, reason) { const suite = this.getSuite(filename, parsedFile); suite.cases.push({ name: "Run grammar tests", classname: this.caseClassname(filename), failures: [{ type: 'error', message: "Error when running grammar tests", body: `${reason}` }] }); } red(text) { return text; } gray(text) { return text; } whiteBright(text) { return text; } getSuite(filename, parsedFile) { const suite = { file: `TEST-${filename.replaceAll(path_1.sep, '.')}.xml`, name: parsedFile?.metadata.description || filename, cases: [] }; this.suites.push(suite); return suite; } getCase(suite, filename, assertion) { const name = `${filename}:${assertion.testCaseLineNumber + 1}`; for (const c of suite.cases) { if (c.name === name) { return c; } } const c = { name, classname: this.caseClassname(filename), failures: [] }; suite.cases.push(c); return c; } reportSuiteResult() { fs.mkdirSync(this.reportPath, { recursive: true }); for (const suite of this.suites.values()) { fs.writeFileSync(p.resolve(this.reportPath, suite.file), this.renderSuite(suite)); } } renderSuite(s) { return ` <testsuite xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://maven.apache.org/surefire/maven-surefire-plugin/xsd/surefire-test-report.xsd" name="${s.name}" tests="${s.cases.length}" failures="${this.suiteFailuresCount(s)}" errors="${this.suiteErrorsCount(s)}" skipped="0" >${s.cases.reduce((a, c) => a + "\n" + this.renderCase(c), "")} </testsuite> `; } renderCase(c) { return ` <testcase name="${c.name}" ${this.classnameAttr(c)}time="0">${c.failures.reduce((a, f) => a + "\n" + this.renderFailure(f), "")}${this.newlineIfHasItems(c.failures)}</testcase>`; } classnameAttr(c) { return c.classname ? `classname="${c.classname}" ` : ""; } renderFailure(f) { return ` <${f.type} message="${f.message}" type="${f.type === 'failure' ? 'TestFailure' : 'GrammarTestError'}">${this.escapedXml(f.body)}</${f.type}>`; } newlineIfHasItems(arr) { return arr.length === 0 ? "" : "\n"; } escapedXml(raw) { return raw .replace(/&/g, '&amp;') .replace(/"/g, '&quot;') .replace(/'/g, '&apos;') .replace(/</g, '&lt;') .replace(/>/g, '&gt;'); } } class XunitGenericReporter extends XunitReportPerTestReporter { // follows this schema https://maven.apache.org/surefire/maven-surefire-plugin/xsd/surefire-test-report.xsd and produces one report file per test file // if some CI requires single report file may also implement reporter for this format https://github.com/windyroad/JUnit-Schema/blob/master/JUnit.xsd constructor(reportPath) { super(reportPath); } reportTestResult(filename, parsedFile, failures) { const suite = this.getSuite(filename, parsedFile); // source line in the test file is treated as testcase // and every failed assertion associated with this source line is failure in that testcase for (const assertion of parsedFile.assertions) { const c = this.getCase(suite, filename, assertion); for (const failure of failures) { if (failure.line !== assertion.testCaseLineNumber) { continue; } const { l, s, e } = getCorrectedOffsets(failure); const bodyLines = []; printSourceLine(parsedFile, failure, '', 200, m => bodyLines.push(m), this); printReason(parsedFile, failure, '', m => bodyLines.push(m), this); c.failures.push({ type: 'failure', message: `Assertion failed at ${l}:${s}:${e}`, body: bodyLines.join("\n") }); } } } caseClassname(filename) { return undefined; } suiteFailuresCount(s) { return s.cases.reduce((accSuite, c) => accSuite + c.failures.reduce((accCase, f) => accCase + (f.type === 'failure' ? 1 : 0), 0), 0); } suiteErrorsCount(s) { return s.cases.reduce((accSuite, c) => accSuite + c.failures.reduce((accCase, f) => accCase + (f.type === 'error' ? 1 : 0), 0), 0); } } exports.XunitGenericReporter = XunitGenericReporter; class XunitGitlabReporter extends XunitReportPerTestReporter { // follows this schema https://maven.apache.org/surefire/maven-surefire-plugin/xsd/surefire-test-report.xsd // produces report in a way which looks nice when viewed in GitLab CI/CD web GUI, but is not neccesarily semantically correct constructor(reportPath) { super(reportPath); } reportTestResult(filename, parsedFile, failures) { const suite = this.getSuite(filename, parsedFile); for (const assertion of parsedFile.assertions) { const c = this.getCase(suite, filename, assertion); const bodyLines = []; for (const failure of failures) { if (failure.line !== assertion.testCaseLineNumber) { continue; } printAssertionLocation(filename, failure, '', m => bodyLines.push(m), this); printSourceLine(parsedFile, failure, '', 200, m => bodyLines.push(m), this); printReason(parsedFile, failure, '', m => bodyLines.push(m), this); bodyLines.push(""); } if (bodyLines.length > 0) { c.failures.push({ type: 'failure', message: `Failed at soure line ${assertion.testCaseLineNumber + 1}`, body: bodyLines.join("\n") }); } } } caseClassname(filename) { return filename; } suiteFailuresCount(s) { return s.cases.reduce((accSuite, c) => accSuite + (c.failures.some(f => f.type === 'failure') ? 1 : 0), 0); } suiteErrorsCount(s) { return s.cases.reduce((accSuite, c) => accSuite + (c.failures.some(f => f.type === 'error') ? 1 : 0), 0); } } exports.XunitGitlabReporter = XunitGitlabReporter; const symbols = { ok: '✓', err: '✖', dot: '․', comma: ',', bang: '!' }; if (process.platform === 'win32') { symbols.ok = '\u221A'; symbols.err = '\u00D7'; symbols.dot = '.'; } const Padding = ' '; let isatty = tty.isatty(1) && tty.isatty(2); let terminalWidth = 75; if (isatty) { terminalWidth = process.stdout.getWindowSize()[0]; } function handleGrammarTestError(filename, testCase, reason) { console.log(chalk_1.default.red(symbols.err) + ' testcase ' + chalk_1.default.gray(filename) + ' aborted due to an error'); console.log(reason); } function handleParseError(filename, error) { console.log(chalk_1.default.red('ERROR') + " can't parse testcase: " + chalk_1.default.whiteBright(filename) + ''); console.log(error); } class ConsoleCompactReporter { constructor() { this.reportParseError = handleParseError; this.reportGrammarTestError = handleGrammarTestError; } reportTestResult(filename, testCase, failures) { if (failures.length === 0) { console.log(chalk_1.default.green(symbols.ok) + ' ' + chalk_1.default.whiteBright(filename) + ` run successfuly.`); } else { failures.forEach((failure) => { console.log(`ERROR ${filename}:${failure.line + 1}:${failure.start + 1}:${failure.end + 1} ${this.renderCompactErrorMsg(testCase, failure)}`); }); } } renderCompactErrorMsg(testCase, failure) { let res = ''; if (failure.missing && failure.missing.length > 0) { res += `Missing required scopes: [ ${failure.missing.join(' ')} ] `; } if (failure.unexpected && failure.unexpected.length > 0) { res += `Prohibited scopes: [ ${failure.unexpected.join(' ')} ] `; } if (failure.actual !== undefined) { res += `actual scopes: [${failure.actual.join(' ')}]`; } return res; } reportSuiteResult() { } } exports.ConsoleCompactReporter = ConsoleCompactReporter; class ConsoleFullReporter { constructor() { this.reportParseError = handleParseError; this.reportGrammarTestError = handleGrammarTestError; } reportTestResult(filename, testCase, failures) { if (failures.length === 0) { console.log(chalk_1.default.green(symbols.ok) + ' ' + chalk_1.default.whiteBright(filename) + ` run successfuly.`); } else { console.log(chalk_1.default.red(symbols.err + ' ' + filename + ' failed')); failures.forEach((failure) => { printAssertionLocation(filename, failure, Padding, console.log, chalk_1.default); printSourceLine(testCase, failure, Padding, terminalWidth, console.log, chalk_1.default); printReason(testCase, failure, Padding, console.log, chalk_1.default); console.log(os_1.EOL); }); console.log(''); } } reportSuiteResult() { } } exports.ConsoleFullReporter = ConsoleFullReporter; function printAssertionLocation(filename, failure, padding, sink, colorizer) { const { l, s, e } = getCorrectedOffsets(failure); sink(padding + 'at [' + colorizer.whiteBright(`${filename}:${l}:${s}:${e}`) + ']:'); } function getCorrectedOffsets(failure) { return { l: failure.line + 1, s: failure.start + 1, e: failure.end + 1 }; } function printSourceLine(testCase, failure, padding, terminalWidth, sink, colorizer) { const line = testCase.source[failure.srcLine]; const pos = failure.line + 1 + ': '; const accents = ' '.repeat(failure.start) + '^'.repeat(failure.end - failure.start); const termWidth = terminalWidth - pos.length - Padding.length - 5; const trimLeft = failure.end > termWidth ? Math.max(0, failure.start - 8) : 0; const line1 = line.substr(trimLeft); const accents1 = accents.substr(trimLeft); sink(padding + colorizer.gray(pos) + line1.substr(0, termWidth)); sink(padding + ' '.repeat(pos.length) + accents1.substr(0, termWidth)); } function printReason(testCase, failure, padding, sink, colorizer) { if (failure.missing && failure.missing.length > 0) { sink(colorizer.red(padding + 'missing required scopes: ') + colorizer.gray(failure.missing.join(' '))); } if (failure.unexpected && failure.unexpected.length > 0) { sink(colorizer.red(padding + 'prohibited scopes: ') + colorizer.gray(failure.unexpected.join(' '))); } if (failure.actual !== undefined) { sink(colorizer.red(padding + 'actual: ') + colorizer.gray(failure.actual.join(' '))); } } //# sourceMappingURL=reporter.js.map