rooibos-roku
Version:
simple, flexible, fun brightscript test framework for roku scenegraph apps - roku brighterscript plugin
165 lines (164 loc) • 8.54 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CodeCoverageProcessor = exports.CodeCoverageLineType = void 0;
const brighterscript_1 = require("brighterscript");
const RawCodeStatement_1 = require("./RawCodeStatement");
const RawCodeExpression_1 = require("./RawCodeExpression");
var CodeCoverageLineType;
(function (CodeCoverageLineType) {
CodeCoverageLineType[CodeCoverageLineType["noCode"] = 0] = "noCode";
CodeCoverageLineType[CodeCoverageLineType["code"] = 1] = "code";
CodeCoverageLineType[CodeCoverageLineType["condition"] = 2] = "condition";
CodeCoverageLineType[CodeCoverageLineType["branch"] = 3] = "branch";
})(CodeCoverageLineType = exports.CodeCoverageLineType || (exports.CodeCoverageLineType = {}));
class CodeCoverageProcessor {
constructor(builder, fileFactory) {
this.coverageBrsTemplate = `
function RBS_CC_#ID#_reportLine(lineNumber, reportType = 1)
_rbs_ccn = m._rbs_ccn
if _rbs_ccn <> invalid
_rbs_ccn.entry = { "f": "#ID#", "l": lineNumber, "r": reportType }
return true
end if
_rbs_ccn = m?.global?._rbs_ccn
if _rbs_ccn <> invalid
_rbs_ccn.entry = { "f": "#ID#", "l": lineNumber, "r": reportType }
m._rbs_ccn = _rbs_ccn
return true
end if
return true
end function
`;
this.config = builder.options.rooibos || {};
this.expectedCoverageMap = {};
this.filePathMap = {};
this.fileId = 0;
this.fileFactory = fileFactory;
try {
}
catch (e) {
console.log('Error:', e.stack);
}
}
generateMetadata(isUsingCoverage, program) {
this.fileFactory.createCoverageComponent(program, this.expectedCoverageMap, this.filePathMap);
}
addCodeCoverage(file, astEditor) {
if (this.config.isRecordingCodeCoverage) {
this._processFile(file, astEditor);
}
}
_processFile(file, astEditor) {
this.fileId++;
this.coverageMap = new Map();
this.executableLines = new Map();
this.processedStatements = new Set();
this.addedStatements = new Set();
this.astEditor = astEditor;
file.ast.walk((0, brighterscript_1.createVisitor)({
ForStatement: (ds, parent, owner, key) => {
this.addStatement(ds);
ds.forToken.text = `${this.getFuncCallText(ds.range.start.line, CodeCoverageLineType.code)}: for`;
},
IfStatement: (ifStatement, parent, owner, key) => {
var _a;
this.addStatement(ifStatement);
ifStatement.condition = new brighterscript_1.BinaryExpression(new RawCodeExpression_1.RawCodeExpression(this.getFuncCallText(ifStatement.condition.range.start.line, CodeCoverageLineType.condition)), (0, brighterscript_1.createToken)(brighterscript_1.TokenKind.And), new brighterscript_1.GroupingExpression({
left: (0, brighterscript_1.createToken)(brighterscript_1.TokenKind.LeftParen),
right: (0, brighterscript_1.createToken)(brighterscript_1.TokenKind.RightParen)
}, ifStatement.condition));
let blockStatements = (_a = ifStatement === null || ifStatement === void 0 ? void 0 : ifStatement.thenBranch) === null || _a === void 0 ? void 0 : _a.statements;
if (blockStatements) {
let coverageStatement = new RawCodeStatement_1.RawCodeStatement(this.getFuncCallText(ifStatement.range.start.line, CodeCoverageLineType.branch));
blockStatements.splice(0, 0, coverageStatement);
}
// Handle the else blocks
let elseBlock = ifStatement.elseBranch;
if ((0, brighterscript_1.isBlock)(elseBlock) && elseBlock.statements) {
let coverageStatement = new RawCodeStatement_1.RawCodeStatement(this.getFuncCallText(elseBlock.range.start.line - 1, CodeCoverageLineType.branch));
elseBlock.statements.splice(0, 0, coverageStatement);
}
},
GotoStatement: (ds, parent, owner, key) => {
this.addStatement(ds);
this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key);
},
WhileStatement: (ds, parent, owner, key) => {
ds.tokens.while.text = `${this.getFuncCallText(ds.range.start.line, CodeCoverageLineType.code)}: while`;
},
ReturnStatement: (ds, parent, owner, key) => {
this.addStatement(ds);
this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key);
},
ForEachStatement: (ds, parent, owner, key) => {
this.addStatement(ds);
ds.tokens.forEach.text = `${this.getFuncCallText(ds.range.start.line, CodeCoverageLineType.code)}: for each`;
},
ExitWhileStatement: (ds, parent, owner, key) => {
},
PrintStatement: (ds, parent, owner, key) => {
this.addStatement(ds);
this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key);
},
DottedSetStatement: (ds, parent, owner, key) => {
this.addStatement(ds);
this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key);
},
IndexedSetStatement: (ds, parent, owner, key) => {
this.addStatement(ds);
this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key);
},
IncrementStatement: (ds, parent, owner, key) => {
this.addStatement(ds);
this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key);
},
AssignmentStatement: (ds, parent, owner, key) => {
if (!(0, brighterscript_1.isForStatement)(parent)) {
this.addStatement(ds);
this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key);
}
},
ExpressionStatement: (ds, parent, owner, key) => {
this.addStatement(ds);
this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key);
}
}), { walkMode: brighterscript_1.WalkMode.visitAllRecursive });
const coverageMapObject = {};
for (let key of this.coverageMap.keys()) {
coverageMapObject[key] = this.coverageMap.get(key);
}
this.expectedCoverageMap[this.fileId.toString().trim()] = coverageMapObject;
this.filePathMap[this.fileId] = file.pkgPath;
this.addBrsAPIText(file, astEditor);
}
convertStatementToCoverageStatement(statement, coverageType, owner, key) {
if (this.processedStatements.has(statement) || this.addedStatements.has(statement)) {
return;
}
const lineNumber = statement.range.start.line;
this.coverageMap.set(lineNumber, coverageType);
const parsed = brighterscript_1.Parser.parse(this.getFuncCallText(lineNumber, coverageType)).ast.statements[0];
this.astEditor.arraySplice(owner, key, 0, parsed);
this.addedStatements.add(parsed);
// store the statement in a set to avoid handling again after inserting statement above
this.processedStatements.add(statement);
}
addBrsAPIText(file, astEditor) {
const astCodeToInject = brighterscript_1.Parser.parse(this.coverageBrsTemplate.replace(/\#ID\#/g, this.fileId.toString().trim())).ast.statements;
astEditor.arrayPush(file.ast.statements, ...astCodeToInject);
for (let statement of astCodeToInject) {
this.addedStatements.add(statement);
}
}
addStatement(statement, lineNumber) {
if (!this.executableLines.has(lineNumber)) {
this.executableLines.set(lineNumber, statement);
}
}
getFuncCallText(lineNumber, lineType) {
this.coverageMap.set(lineNumber, lineType);
return `RBS_CC_${this.fileId}_reportLine("${lineNumber.toString().trim()}", ${lineType.toString().trim()})`;
}
}
exports.CodeCoverageProcessor = CodeCoverageProcessor;
//# sourceMappingURL=CodeCoverageProcessor.js.map