From 721036d8c1eacd9cf3a18a861c0a8151f37d7a05 Mon Sep 17 00:00:00 2001 From: Christopher Dwyer-Perkins Date: Sun, 11 Feb 2024 15:39:54 -0400 Subject: [PATCH 01/13] Added some FN tracking --- .../lib/rooibos/CodeCoverageProcessor.spec.ts | 176 +++++++++--------- .../src/lib/rooibos/CodeCoverageProcessor.ts | 66 +++++-- bsc-plugin/src/lib/rooibos/FileFactory.ts | 3 +- framework/src/source/CodeCoverage.brs | 15 +- framework/src/source/CodeCoverage.xml | 1 + framework/src/source/Coverage.bs | 4 +- 6 files changed, 164 insertions(+), 101 deletions(-) diff --git a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts index 1a038d3d..e17b01ba 100644 --- a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts +++ b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts @@ -22,7 +22,7 @@ describe('RooibosPlugin', () => { return undent(contents); } - describe('CodeCoverageProcessor', () => { + describe.only('CodeCoverageProcessor', () => { beforeEach(() => { plugin = new RooibosPlugin(); options = { @@ -91,41 +91,42 @@ describe('RooibosPlugin', () => { let a = getContents('source/code.brs'); let b = undent(` function new(a1, a2) - RBS_CC_1_reportLine("2", 1) + RBS_CC_1_reportLine("2", 1, 0) c = 0 - RBS_CC_1_reportLine("3", 1) + RBS_CC_1_reportLine("3", 1, 0) text = "" - RBS_CC_1_reportLine("4", 1): for i = 0 to 10 - RBS_CC_1_reportLine("5", 1) + RBS_CC_1_reportLine("4", 1, 0): for i = 0 to 10 + RBS_CC_1_reportLine("5", 1, 0) text = text + "hello" - RBS_CC_1_reportLine("6", 1) + RBS_CC_1_reportLine("6", 1, 0) c++ - RBS_CC_1_reportLine("7", 1) + RBS_CC_1_reportLine("7", 1, 0) c += 1 - if RBS_CC_1_reportLine("8", 2) and (c = 2) - RBS_CC_1_reportLine("8", 3) - RBS_CC_1_reportLine("9", 1) + if RBS_CC_1_reportLine("8", 2, 0) and (c = 2) + RBS_CC_1_reportLine("8", 3, 0) + RBS_CC_1_reportLine("9", 1, 0) ? "is true" end if - if RBS_CC_1_reportLine("12", 2) and (c = 3) - RBS_CC_1_reportLine("12", 3) - RBS_CC_1_reportLine("13", 1) + if RBS_CC_1_reportLine("12", 2, 0) and (c = 3) + RBS_CC_1_reportLine("12", 3, 0) + RBS_CC_1_reportLine("13", 1, 0) ? "free" else - RBS_CC_1_reportLine("14", 3) - RBS_CC_1_reportLine("15", 1) + RBS_CC_1_reportLine("14", 3, 0) + RBS_CC_1_reportLine("15", 1, 0) ? "not free" end if end for end function - function RBS_CC_1_reportLine(lineNumber, reportType = 1) + function RBS_CC_1_reportLine(lineNumber, reportType = 1, funcId = -1) _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { "f": "1" "l": lineNumber "r": reportType + "fn": funcId } return true end if @@ -135,6 +136,7 @@ describe('RooibosPlugin', () => { "f": "1" "l": lineNumber "r": reportType + "fn": funcId } m._rbs_ccn = _rbs_ccn return true @@ -175,41 +177,42 @@ describe('RooibosPlugin', () => { let a = getContents('source/code.brs'); let b = undent(` function new(a1, a2) - RBS_CC_1_reportLine("2", 1) + RBS_CC_1_reportLine("2", 1, 0) c = 0 - RBS_CC_1_reportLine("3", 1) + RBS_CC_1_reportLine("3", 1, 0) text = "" - RBS_CC_1_reportLine("4", 1): for i = 0 to 10 - RBS_CC_1_reportLine("5", 1) + RBS_CC_1_reportLine("4", 1, 0): for i = 0 to 10 + RBS_CC_1_reportLine("5", 1, 0) text = text + "hello" - RBS_CC_1_reportLine("6", 1) + RBS_CC_1_reportLine("6", 1, 0) c++ - RBS_CC_1_reportLine("7", 1) + RBS_CC_1_reportLine("7", 1, 0) c += 1 - if RBS_CC_1_reportLine("8", 2) and (c = 2) - RBS_CC_1_reportLine("8", 3) - RBS_CC_1_reportLine("9", 1) + if RBS_CC_1_reportLine("8", 2, 0) and (c = 2) + RBS_CC_1_reportLine("8", 3, 0) + RBS_CC_1_reportLine("9", 1, 0) ? "is true" end if - if RBS_CC_1_reportLine("12", 2) and (c = 3) - RBS_CC_1_reportLine("12", 3) - RBS_CC_1_reportLine("13", 1) + if RBS_CC_1_reportLine("12", 2, 0) and (c = 3) + RBS_CC_1_reportLine("12", 3, 0) + RBS_CC_1_reportLine("13", 1, 0) ? "free" else - RBS_CC_1_reportLine("14", 3) - RBS_CC_1_reportLine("15", 1) + RBS_CC_1_reportLine("14", 3, 0) + RBS_CC_1_reportLine("15", 1, 0) ? "not free" end if end for end function - function RBS_CC_1_reportLine(lineNumber, reportType = 1) + function RBS_CC_1_reportLine(lineNumber, reportType = 1, funcId = -1) _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { "f": "1" "l": lineNumber "r": reportType + "fn": funcId } return true end if @@ -219,6 +222,7 @@ describe('RooibosPlugin', () => { "f": "1" "l": lineNumber "r": reportType + "fn": funcId } m._rbs_ccn = _rbs_ccn return true @@ -272,29 +276,29 @@ describe('RooibosPlugin', () => { instance.new = function(a1, a2) m.field1 = invalid m.field2 = invalid - RBS_CC_1_reportLine("6", 1) + RBS_CC_1_reportLine("6", 1, 0) c = 0 - RBS_CC_1_reportLine("7", 1) + RBS_CC_1_reportLine("7", 1, 0) text = "" - RBS_CC_1_reportLine("8", 1): for i = 0 to 10 - RBS_CC_1_reportLine("9", 1) + RBS_CC_1_reportLine("8", 1, 0): for i = 0 to 10 + RBS_CC_1_reportLine("9", 1, 0) text = text + "hello" - RBS_CC_1_reportLine("10", 1) + RBS_CC_1_reportLine("10", 1, 0) c++ - RBS_CC_1_reportLine("11", 1) + RBS_CC_1_reportLine("11", 1, 0) c += 1 - if RBS_CC_1_reportLine("12", 2) and (c = 2) - RBS_CC_1_reportLine("12", 3) - RBS_CC_1_reportLine("13", 1) + if RBS_CC_1_reportLine("12", 2, 0) and (c = 2) + RBS_CC_1_reportLine("12", 3, 0) + RBS_CC_1_reportLine("13", 1, 0) ? "is true" end if - if RBS_CC_1_reportLine("16", 2) and (c = 3) - RBS_CC_1_reportLine("16", 3) - RBS_CC_1_reportLine("17", 1) + if RBS_CC_1_reportLine("16", 2, 0) and (c = 3) + RBS_CC_1_reportLine("16", 3, 0) + RBS_CC_1_reportLine("17", 1, 0) ? "free" else - RBS_CC_1_reportLine("18", 3) - RBS_CC_1_reportLine("19", 1) + RBS_CC_1_reportLine("18", 3, 0) + RBS_CC_1_reportLine("19", 1, 0) ? "not free" end if end for @@ -307,13 +311,14 @@ describe('RooibosPlugin', () => { return instance end function - function RBS_CC_1_reportLine(lineNumber, reportType = 1) + function RBS_CC_1_reportLine(lineNumber, reportType = 1, funcId = -1) _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { "f": "1" "l": lineNumber "r": reportType + "fn": funcId } return true end if @@ -323,6 +328,7 @@ describe('RooibosPlugin', () => { "f": "1" "l": lineNumber "r": reportType + "fn": funcId } m._rbs_ccn = _rbs_ccn return true @@ -351,25 +357,26 @@ describe('RooibosPlugin', () => { let a = getContents('source/code.brs'); let b = undent(` sub foo() - RBS_CC_1_reportLine("1", 1) + RBS_CC_1_reportLine("1", 1, 0) x = function(y) - if RBS_CC_1_reportLine("2", 2) and ((true)) then - RBS_CC_1_reportLine("2", 3) - RBS_CC_1_reportLine("3", 1) + if RBS_CC_1_reportLine("2", 2, 1) and ((true)) then + RBS_CC_1_reportLine("2", 3, 1) + RBS_CC_1_reportLine("3", 1, 1) return 1 end if - RBS_CC_1_reportLine("5", 1) + RBS_CC_1_reportLine("5", 1, 1) return 0 end function end sub - function RBS_CC_1_reportLine(lineNumber, reportType = 1) + function RBS_CC_1_reportLine(lineNumber, reportType = 1, funcId = -1) _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { "f": "1" "l": lineNumber "r": reportType + "fn": funcId } return true end if @@ -379,6 +386,7 @@ describe('RooibosPlugin', () => { "f": "1" "l": lineNumber "r": reportType + "fn": funcId } m._rbs_ccn = _rbs_ccn return true @@ -425,56 +433,57 @@ describe('RooibosPlugin', () => { let a = getContents('source/code.brs'); let b = undent(` sub foo(action as string) - if RBS_CC_1_reportLine("2", 2) and (action = "action1") then - RBS_CC_1_reportLine("2", 3) - RBS_CC_1_reportLine("3", 1) + if RBS_CC_1_reportLine("2", 2, 0) and (action = "action1") then + RBS_CC_1_reportLine("2", 3, 0) + RBS_CC_1_reportLine("3", 1, 0) print "action1" - else if RBS_CC_1_reportLine("4", 2) and (action = "action2" or action = "action2") then - RBS_CC_1_reportLine("4", 3) - RBS_CC_1_reportLine("5", 1) + else if RBS_CC_1_reportLine("4", 2, 0) and (action = "action2" or action = "action2") then + RBS_CC_1_reportLine("4", 3, 0) + RBS_CC_1_reportLine("5", 1, 0) print "action2" - else if RBS_CC_1_reportLine("6", 2) and (action = "action3") then - RBS_CC_1_reportLine("6", 3) - RBS_CC_1_reportLine("7", 1) + else if RBS_CC_1_reportLine("6", 2, 0) and (action = "action3") then + RBS_CC_1_reportLine("6", 3, 0) + RBS_CC_1_reportLine("7", 1, 0) print "action3" - else if RBS_CC_1_reportLine("8", 2) and (action = "action4") then - RBS_CC_1_reportLine("8", 3) - else if RBS_CC_1_reportLine("9", 2) and (action = "action5") then - RBS_CC_1_reportLine("9", 3) - RBS_CC_1_reportLine("10", 1) + else if RBS_CC_1_reportLine("8", 2, 0) and (action = "action4") then + RBS_CC_1_reportLine("8", 3, 0) + else if RBS_CC_1_reportLine("9", 2, 0) and (action = "action5") then + RBS_CC_1_reportLine("9", 3, 0) + RBS_CC_1_reportLine("10", 1, 0) print "action5" - else if RBS_CC_1_reportLine("11", 2) and (action = "action6") then - RBS_CC_1_reportLine("11", 3) - RBS_CC_1_reportLine("12", 1) + else if RBS_CC_1_reportLine("11", 2, 0) and (action = "action6") then + RBS_CC_1_reportLine("11", 3, 0) + RBS_CC_1_reportLine("12", 1, 0) print "action6" - else if RBS_CC_1_reportLine("13", 2) and (action = "action7") then - RBS_CC_1_reportLine("13", 3) - RBS_CC_1_reportLine("14", 1) + else if RBS_CC_1_reportLine("13", 2, 0) and (action = "action7") then + RBS_CC_1_reportLine("13", 3, 0) + RBS_CC_1_reportLine("14", 1, 0) print "action7" - else if RBS_CC_1_reportLine("15", 2) and (action = "action8") then - RBS_CC_1_reportLine("15", 3) - RBS_CC_1_reportLine("16", 1) + else if RBS_CC_1_reportLine("15", 2, 0) and (action = "action8") then + RBS_CC_1_reportLine("15", 3, 0) + RBS_CC_1_reportLine("16", 1, 0) print "action8" - else if RBS_CC_1_reportLine("17", 2) and (action = "action9") then - RBS_CC_1_reportLine("17", 3) - RBS_CC_1_reportLine("18", 1) + else if RBS_CC_1_reportLine("17", 2, 0) and (action = "action9") then + RBS_CC_1_reportLine("17", 3, 0) + RBS_CC_1_reportLine("18", 1, 0) print "action9" - else if RBS_CC_1_reportLine("19", 2) and (action = "action10") then - RBS_CC_1_reportLine("19", 3) - RBS_CC_1_reportLine("20", 1) + else if RBS_CC_1_reportLine("19", 2, 0) and (action = "action10") then + RBS_CC_1_reportLine("19", 3, 0) + RBS_CC_1_reportLine("20", 1, 0) print "action10" else - RBS_CC_1_reportLine("21", 3) + RBS_CC_1_reportLine("21", 3, 0) end if end sub - function RBS_CC_1_reportLine(lineNumber, reportType = 1) + function RBS_CC_1_reportLine(lineNumber, reportType = 1, funcId = -1) _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { "f": "1" "l": lineNumber "r": reportType + "fn": funcId } return true end if @@ -484,6 +493,7 @@ describe('RooibosPlugin', () => { "f": "1" "l": lineNumber "r": reportType + "fn": funcId } m._rbs_ccn = _rbs_ccn return true diff --git a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts index b0a48488..6507f1b7 100644 --- a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts +++ b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import type { BrsFile, Editor, ExpressionStatement, Program, ProgramBuilder, Statement } from 'brighterscript'; -import { Parser, WalkMode, createVisitor, BinaryExpression, createToken, TokenKind, GroupingExpression, isForStatement, isBlock } from 'brighterscript'; +import type { BrsFile, Editor, ExpressionStatement, FunctionExpression, Program, ProgramBuilder, Statement } from 'brighterscript'; +import { Parser, WalkMode, createVisitor, BinaryExpression, createToken, TokenKind, GroupingExpression, isForStatement, isBlock, isFunctionExpression, ParseMode } from 'brighterscript'; import type { RooibosConfig } from './RooibosConfig'; import { RawCodeStatement } from './RawCodeStatement'; import { BrsTranspileState } from 'brighterscript/dist/parser/BrsTranspileState'; @@ -18,16 +18,16 @@ export enum CodeCoverageLineType { export class CodeCoverageProcessor { private coverageBrsTemplate = ` - function RBS_CC_#ID#_reportLine(lineNumber, reportType = 1) + function RBS_CC_#ID#_reportLine(lineNumber, reportType = 1, funcId = -1) _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid - _rbs_ccn.entry = { "f": "#ID#", "l": lineNumber, "r": reportType } + _rbs_ccn.entry = { "f": "#ID#", "l": lineNumber, "r": reportType, "fn": funcId } return true end if _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid - _rbs_ccn.entry = { "f": "#ID#", "l": lineNumber, "r": reportType } + _rbs_ccn.entry = { "f": "#ID#", "l": lineNumber, "r": reportType, "fn": funcId } m._rbs_ccn = _rbs_ccn return true end if @@ -39,8 +39,11 @@ export class CodeCoverageProcessor { this.config = (builder.options as any).rooibos as RooibosConfig || {}; this.expectedCoverageMap = {}; this.filePathMap = {}; + this.functionMap = []; this.fileId = 0; + this.functionId = 0; this.fileFactory = fileFactory; + this.processedFunctions = new Set(); try { } catch (e) { console.log('Error:', e.stack); @@ -49,17 +52,20 @@ export class CodeCoverageProcessor { private config: RooibosConfig; private fileId: number; + private functionId: number; private filePathMap: any; + private functionMap: Array>; private expectedCoverageMap: any; private executableLines: Map; private transpileState: BrsTranspileState; private coverageMap: Map; private fileFactory: FileFactory; private processedStatements: Set; + private processedFunctions: Set; private astEditor: Editor; public generateMetadata(isUsingCoverage: boolean, program: Program) { - this.fileFactory.createCoverageComponent(program, this.expectedCoverageMap, this.filePathMap); + this.fileFactory.createCoverageComponent(program, this.expectedCoverageMap, this.filePathMap, this.functionMap); } public addCodeCoverage(file: BrsFile, astEditor: Editor) { @@ -79,12 +85,12 @@ export class CodeCoverageProcessor { file.ast.walk(createVisitor({ ForStatement: (ds, parent, owner, key) => { this.addStatement(ds); - ds.forToken.text = `${this.getFuncCallText(ds.range.start.line, CodeCoverageLineType.code)}: for`; + ds.forToken.text = `${this.getFuncCallText(ds.range.start.line, CodeCoverageLineType.code, ds)}: for`; }, IfStatement: (ifStatement, parent, owner, key) => { this.addStatement(ifStatement); (ifStatement as any).condition = new BinaryExpression( - new RawCodeExpression(this.getFuncCallText(ifStatement.condition.range.start.line, CodeCoverageLineType.condition)), + new RawCodeExpression(this.getFuncCallText(ifStatement.condition.range.start.line, CodeCoverageLineType.condition, ifStatement)), createToken(TokenKind.And), new GroupingExpression({ left: createToken(TokenKind.LeftParen), @@ -94,14 +100,14 @@ export class CodeCoverageProcessor { let blockStatements = ifStatement?.thenBranch?.statements; if (blockStatements) { - let coverageStatement = new RawCodeStatement(this.getFuncCallText(ifStatement.range.start.line, CodeCoverageLineType.branch)); + let coverageStatement = new RawCodeStatement(this.getFuncCallText(ifStatement.range.start.line, CodeCoverageLineType.branch, ifStatement)); blockStatements.splice(0, 0, coverageStatement); } // Handle the else blocks let elseBlock = ifStatement.elseBranch; if (isBlock(elseBlock) && elseBlock.statements) { - let coverageStatement = new RawCodeStatement(this.getFuncCallText(elseBlock.range.start.line - 1, CodeCoverageLineType.branch)); + let coverageStatement = new RawCodeStatement(this.getFuncCallText(elseBlock.range.start.line - 1, CodeCoverageLineType.branch, elseBlock)); elseBlock.statements.splice(0, 0, coverageStatement); } @@ -112,7 +118,7 @@ export class CodeCoverageProcessor { }, WhileStatement: (ds, parent, owner, key) => { - ds.tokens.while.text = `${this.getFuncCallText(ds.range.start.line, CodeCoverageLineType.code)}: while`; + ds.tokens.while.text = `${this.getFuncCallText(ds.range.start.line, CodeCoverageLineType.code, ds)}: while`; }, ReturnStatement: (ds, parent, owner, key) => { this.addStatement(ds); @@ -120,7 +126,7 @@ export class CodeCoverageProcessor { }, ForEachStatement: (ds, parent, owner, key) => { this.addStatement(ds); - ds.tokens.forEach.text = `${this.getFuncCallText(ds.range.start.line, CodeCoverageLineType.code)}: for each`; + ds.tokens.forEach.text = `${this.getFuncCallText(ds.range.start.line, CodeCoverageLineType.code, ds)}: for each`; }, ExitWhileStatement: (ds, parent, owner, key) => { @@ -173,7 +179,7 @@ export class CodeCoverageProcessor { const lineNumber = statement.range.start.line; this.coverageMap.set(lineNumber, coverageType); - const parsed = Parser.parse(this.getFuncCallText(lineNumber, coverageType)).ast.statements[0] as ExpressionStatement; + const parsed = Parser.parse(this.getFuncCallText(lineNumber, coverageType, statement)).ast.statements[0] as ExpressionStatement; this.astEditor.arraySplice(owner, key, 0, parsed); // store the statement in a set to avoid handling again after inserting statement above this.processedStatements.add(statement); @@ -190,8 +196,38 @@ export class CodeCoverageProcessor { } } - private getFuncCallText(lineNumber: number, lineType: CodeCoverageLineType) { + private getFuncCallText(lineNumber: number, lineType: CodeCoverageLineType, statement: Statement) { + const funcId = this.getFunctionIdInFile(statement, ParseMode.BrighterScript); this.coverageMap.set(lineNumber, lineType); - return `RBS_CC_${this.fileId}_reportLine("${lineNumber.toString().trim()}", ${lineType.toString().trim()})`; + return `RBS_CC_${this.fileId}_reportLine("${lineNumber.toString().trim()}", ${lineType.toString().trim()}, ${funcId})`; + } + + private getFunctionIdInFile(statement: Statement, parseMode: ParseMode) { + let originalFunc: FunctionExpression = statement.findAncestor(isFunctionExpression); + let func: FunctionExpression = originalFunc; + + let nameParts = []; + while (func.parentFunction) { + let index = func.parentFunction.childFunctionExpressions.indexOf(func); + nameParts.unshift(`anon${index}`); + func = func.parentFunction; + } + //get the index of this function in its parent + nameParts.unshift( + func.functionStatement.getName(parseMode) + ); + + const name = nameParts.join('$'); + + if (!this.processedFunctions.has(originalFunc)) { + this.processedFunctions.add(originalFunc); + if (!this.functionMap[this.fileId]) { + this.functionMap[this.fileId] = []; + } + + this.functionMap[this.fileId].push(name); + } + + return this.functionMap[this.fileId].indexOf(name); } } diff --git a/bsc-plugin/src/lib/rooibos/FileFactory.ts b/bsc-plugin/src/lib/rooibos/FileFactory.ts index 82ff914d..dd84a4e4 100644 --- a/bsc-plugin/src/lib/rooibos/FileFactory.ts +++ b/bsc-plugin/src/lib/rooibos/FileFactory.ts @@ -100,10 +100,11 @@ export class FileFactory { return contents; } - public createCoverageComponent(program: Program, coverageMap: any, filepathMap: Map) { + public createCoverageComponent(program: Program, coverageMap: any, filepathMap: Map, functionMap: Array>) { let template = this.coverageComponentBrsTemplate; template = template.replace(/\"\#EXPECTED_MAP\#\"/g, JSON.stringify(coverageMap ?? {})); template = template.replace(/\"\#FILE_PATH_MAP\#\"/g, JSON.stringify(filepathMap ?? {})); + template = template.replace(/\"\#FUNCTION_MAP\#\"/g, JSON.stringify(functionMap ?? [])); this.addFileToRootDir(program, path.join('components/rooibos', 'CodeCoverage.brs'), template); this.addFileToRootDir(program, path.join('components/rooibos', 'CodeCoverage.xml'), this.coverageComponentXmlTemplate); diff --git a/framework/src/source/CodeCoverage.brs b/framework/src/source/CodeCoverage.brs index 38d47c18..3bc4ad60 100644 --- a/framework/src/source/CodeCoverage.brs +++ b/framework/src/source/CodeCoverage.brs @@ -17,6 +17,10 @@ function setFilePathMap() m.top.filePathMap = "#FILE_PATH_MAP#" end function +function setFunctionMap() + m.top.functionMap = "#FUNCTION_MAP#" +end function + function onEntryChange() entry = m.top.entry ' defer till later @@ -45,7 +49,15 @@ function onSave() lineMap = {} m.resolvedMap[fileId] = lineMap end if - lineMap[entry.l] = entry.r + + if lineMap[entry.l] = invalid + lineMap[entry.l] = [] + end if + + lineMap[entry.l].push({ + r: entry.r + fn: entry.fn + }) end if end for m.top.resolvedMap = m.resolvedMap @@ -71,4 +83,5 @@ function onSave() #end if setExpectedMap() setFilePathMap() + setFunctionMap() end function \ No newline at end of file diff --git a/framework/src/source/CodeCoverage.xml b/framework/src/source/CodeCoverage.xml index 3aaff6ee..ac60a9be 100644 --- a/framework/src/source/CodeCoverage.xml +++ b/framework/src/source/CodeCoverage.xml @@ -11,5 +11,6 @@ + diff --git a/framework/src/source/Coverage.bs b/framework/src/source/Coverage.bs index 1a989bf4..a0a7e6c4 100644 --- a/framework/src/source/Coverage.bs +++ b/framework/src/source/Coverage.bs @@ -78,6 +78,7 @@ namespace rooibos.Coverage cc = m.global._rbs_ccn expectedMap = cc.expectedMap filePathMap = cc.filePathMap + functionMap = cc.functionMap resolvedMap = cc.resolvedMap results = [] @@ -94,12 +95,13 @@ namespace rooibos.Coverage buffer += "TN:" + chr(10) buffer += "SF:" + sanitizedPath + chr(10) + functionName = "" for each expected in expectedMap[moduleNumber] lineNumber = val(expected) SHIFT = 1 if resolvedMap[moduleNumber] <> invalid and resolvedMap[moduleNumber].doesExist(expected) - buffer += "DA:" + str(lineNumber + SHIFT).trim() + "," + str(resolvedMap[moduleNumber][expected]).trim() + chr(10) + buffer += "DA:" + str(lineNumber + SHIFT).trim() + "," + str(resolvedMap[moduleNumber][expected].count()).trim() + chr(10) else buffer += "DA:" + str(lineNumber + SHIFT).trim() + ",0" + chr(10) end if From 79dede23dc99fbd5319feb3938d7db6584ed3ed3 Mon Sep 17 00:00:00 2001 From: Christopher Dwyer-Perkins Date: Mon, 12 Feb 2024 15:02:05 -0400 Subject: [PATCH 02/13] Worked on new coverage map interface and function hit reporting --- .../lib/rooibos/CodeCoverageProcessor.spec.ts | 542 +++++++++++++----- .../src/lib/rooibos/CodeCoverageProcessor.ts | 246 +++++++- 2 files changed, 604 insertions(+), 184 deletions(-) diff --git a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts index e17b01ba..1b2d40b9 100644 --- a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts +++ b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts @@ -67,8 +67,8 @@ describe('RooibosPlugin', () => { it('adds code coverage to a brs file', async () => { program.setFile('source/code.brs', ` function new(a1, a2) - c = 0 - text = "" + c = 0 + text = "" for i = 0 to 10 text = text + "hello" c++ @@ -91,52 +91,99 @@ describe('RooibosPlugin', () => { let a = getContents('source/code.brs'); let b = undent(` function new(a1, a2) - RBS_CC_1_reportLine("2", 1, 0) + RBS_CC_0_reportFunction(0) + RBS_CC_0_reportLine(2) c = 0 - RBS_CC_1_reportLine("3", 1, 0) + RBS_CC_0_reportLine(3) text = "" - RBS_CC_1_reportLine("4", 1, 0): for i = 0 to 10 - RBS_CC_1_reportLine("5", 1, 0) + RBS_CC_0_reportLine(4): for i = 0 to 10 + RBS_CC_0_reportLine(5) text = text + "hello" - RBS_CC_1_reportLine("6", 1, 0) + RBS_CC_0_reportLine(6) c++ - RBS_CC_1_reportLine("7", 1, 0) + RBS_CC_0_reportLine(7) c += 1 - if RBS_CC_1_reportLine("8", 2, 0) and (c = 2) - RBS_CC_1_reportLine("8", 3, 0) - RBS_CC_1_reportLine("9", 1, 0) + if RBS_CC_0_reportLine(8) and (c = 2) + RBS_CC_0_reportLine(8) + RBS_CC_0_reportLine(9) ? "is true" end if - if RBS_CC_1_reportLine("12", 2, 0) and (c = 3) - RBS_CC_1_reportLine("12", 3, 0) - RBS_CC_1_reportLine("13", 1, 0) + if RBS_CC_0_reportLine(12) and (c = 3) + RBS_CC_0_reportLine(12) + RBS_CC_0_reportLine(13) ? "free" else - RBS_CC_1_reportLine("14", 3, 0) - RBS_CC_1_reportLine("15", 1, 0) + RBS_CC_0_reportLine(14) + RBS_CC_0_reportLine(15) ? "not free" end if end for end function - function RBS_CC_1_reportLine(lineNumber, reportType = 1, funcId = -1) + function RBS_CC_0_reportLine(lineNumber) _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "1" + "f": "0" "l": lineNumber - "r": reportType - "fn": funcId + "r": 1 } return true end if _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "1" + "f": "0" "l": lineNumber - "r": reportType - "fn": funcId + "r": 1 + } + m._rbs_ccn = _rbs_ccn + return true + end if + return true + end function + + function RBS_CC_0_reportBranch(blockId, branchId) + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "bl": blockId + "br": branchId + "r": 3 + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "bl": blockId + "br": branchId + "r": 3 + } + m._rbs_ccn = _rbs_ccn + return true + end if + return true + end function + + function RBS_CC_0_reportFunction(functionId) + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "fn": functionId + "r": 4 + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "fn": functionId + "r": 4 } m._rbs_ccn = _rbs_ccn return true @@ -177,52 +224,99 @@ describe('RooibosPlugin', () => { let a = getContents('source/code.brs'); let b = undent(` function new(a1, a2) - RBS_CC_1_reportLine("2", 1, 0) + RBS_CC_0_reportFunction(0) + RBS_CC_0_reportLine(2) c = 0 - RBS_CC_1_reportLine("3", 1, 0) + RBS_CC_0_reportLine(3) text = "" - RBS_CC_1_reportLine("4", 1, 0): for i = 0 to 10 - RBS_CC_1_reportLine("5", 1, 0) + RBS_CC_0_reportLine(4): for i = 0 to 10 + RBS_CC_0_reportLine(5) text = text + "hello" - RBS_CC_1_reportLine("6", 1, 0) + RBS_CC_0_reportLine(6) c++ - RBS_CC_1_reportLine("7", 1, 0) + RBS_CC_0_reportLine(7) c += 1 - if RBS_CC_1_reportLine("8", 2, 0) and (c = 2) - RBS_CC_1_reportLine("8", 3, 0) - RBS_CC_1_reportLine("9", 1, 0) + if RBS_CC_0_reportLine(8) and (c = 2) + RBS_CC_0_reportLine(8) + RBS_CC_0_reportLine(9) ? "is true" end if - if RBS_CC_1_reportLine("12", 2, 0) and (c = 3) - RBS_CC_1_reportLine("12", 3, 0) - RBS_CC_1_reportLine("13", 1, 0) + if RBS_CC_0_reportLine(12) and (c = 3) + RBS_CC_0_reportLine(12) + RBS_CC_0_reportLine(13) ? "free" else - RBS_CC_1_reportLine("14", 3, 0) - RBS_CC_1_reportLine("15", 1, 0) + RBS_CC_0_reportLine(14) + RBS_CC_0_reportLine(15) ? "not free" end if end for end function - function RBS_CC_1_reportLine(lineNumber, reportType = 1, funcId = -1) + function RBS_CC_0_reportLine(lineNumber) _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "1" + "f": "0" "l": lineNumber - "r": reportType - "fn": funcId + "r": 1 } return true end if _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "1" + "f": "0" "l": lineNumber - "r": reportType - "fn": funcId + "r": 1 + } + m._rbs_ccn = _rbs_ccn + return true + end if + return true + end function + + function RBS_CC_0_reportBranch(blockId, branchId) + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "bl": blockId + "br": branchId + "r": 3 + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "bl": blockId + "br": branchId + "r": 3 + } + m._rbs_ccn = _rbs_ccn + return true + end if + return true + end function + + function RBS_CC_0_reportFunction(functionId) + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "fn": functionId + "r": 4 + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "fn": functionId + "r": 4 } m._rbs_ccn = _rbs_ccn return true @@ -271,70 +365,117 @@ describe('RooibosPlugin', () => { await builder.transpile(); let a = getContents('source/code.brs'); let b = undent(` - function __BasicClass_builder() - instance = {} - instance.new = function(a1, a2) - m.field1 = invalid - m.field2 = invalid - RBS_CC_1_reportLine("6", 1, 0) - c = 0 - RBS_CC_1_reportLine("7", 1, 0) - text = "" - RBS_CC_1_reportLine("8", 1, 0): for i = 0 to 10 - RBS_CC_1_reportLine("9", 1, 0) - text = text + "hello" - RBS_CC_1_reportLine("10", 1, 0) - c++ - RBS_CC_1_reportLine("11", 1, 0) - c += 1 - if RBS_CC_1_reportLine("12", 2, 0) and (c = 2) - RBS_CC_1_reportLine("12", 3, 0) - RBS_CC_1_reportLine("13", 1, 0) - ? "is true" - end if - if RBS_CC_1_reportLine("16", 2, 0) and (c = 3) - RBS_CC_1_reportLine("16", 3, 0) - RBS_CC_1_reportLine("17", 1, 0) - ? "free" - else - RBS_CC_1_reportLine("18", 3, 0) - RBS_CC_1_reportLine("19", 1, 0) - ? "not free" - end if - end for + function __BasicClass_builder() + instance = {} + instance.new = function(a1, a2) + m.field1 = invalid + m.field2 = invalid + RBS_CC_0_reportLine(6) + RBS_CC_0_reportFunction(0) + c = 0 + RBS_CC_0_reportLine(7) + text = "" + RBS_CC_0_reportLine(8): for i = 0 to 10 + RBS_CC_0_reportLine(9) + text = text + "hello" + RBS_CC_0_reportLine(10) + c++ + RBS_CC_0_reportLine(11) + c += 1 + if RBS_CC_0_reportLine(12) and (c = 2) + RBS_CC_0_reportLine(12) + RBS_CC_0_reportLine(13) + ? "is true" + end if + if RBS_CC_0_reportLine(16) and (c = 3) + RBS_CC_0_reportLine(16) + RBS_CC_0_reportLine(17) + ? "free" + else + RBS_CC_0_reportLine(18) + RBS_CC_0_reportLine(19) + ? "not free" + end if + end for + end function + return instance + end function + function BasicClass(a1, a2) + instance = __BasicClass_builder() + instance.new(a1, a2) + return instance + end function + + function RBS_CC_0_reportLine(lineNumber) + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "l": lineNumber + "r": 1 + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "l": lineNumber + "r": 1 + } + m._rbs_ccn = _rbs_ccn + return true + end if + return true end function - return instance - end function - function BasicClass(a1, a2) - instance = __BasicClass_builder() - instance.new(a1, a2) - return instance - end function - function RBS_CC_1_reportLine(lineNumber, reportType = 1, funcId = -1) - _rbs_ccn = m._rbs_ccn - if _rbs_ccn <> invalid - _rbs_ccn.entry = { - "f": "1" - "l": lineNumber - "r": reportType - "fn": funcId - } + function RBS_CC_0_reportBranch(blockId, branchId) + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "bl": blockId + "br": branchId + "r": 3 + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "bl": blockId + "br": branchId + "r": 3 + } + m._rbs_ccn = _rbs_ccn + return true + end if return true - end if - _rbs_ccn = m?.global?._rbs_ccn - if _rbs_ccn <> invalid - _rbs_ccn.entry = { - "f": "1" - "l": lineNumber - "r": reportType - "fn": funcId - } - m._rbs_ccn = _rbs_ccn + end function + + function RBS_CC_0_reportFunction(functionId) + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "fn": functionId + "r": 4 + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "fn": functionId + "r": 4 + } + m._rbs_ccn = _rbs_ccn + return true + end if return true - end if - return true - end function + end function `); expect(a).to.equal(b); }); @@ -357,36 +498,84 @@ describe('RooibosPlugin', () => { let a = getContents('source/code.brs'); let b = undent(` sub foo() - RBS_CC_1_reportLine("1", 1, 0) + RBS_CC_0_reportFunction(0) + RBS_CC_0_reportLine(1) x = function(y) - if RBS_CC_1_reportLine("2", 2, 1) and ((true)) then - RBS_CC_1_reportLine("2", 3, 1) - RBS_CC_1_reportLine("3", 1, 1) + RBS_CC_0_reportFunction(1) + if RBS_CC_0_reportLine(2) and ((true)) then + RBS_CC_0_reportLine(2) + RBS_CC_0_reportLine(3) return 1 end if - RBS_CC_1_reportLine("5", 1, 1) + RBS_CC_0_reportLine(5) return 0 end function end sub - function RBS_CC_1_reportLine(lineNumber, reportType = 1, funcId = -1) + function RBS_CC_0_reportLine(lineNumber) _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "1" + "f": "0" "l": lineNumber - "r": reportType - "fn": funcId + "r": 1 } return true end if _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "1" + "f": "0" "l": lineNumber - "r": reportType - "fn": funcId + "r": 1 + } + m._rbs_ccn = _rbs_ccn + return true + end if + return true + end function + + function RBS_CC_0_reportBranch(blockId, branchId) + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "bl": blockId + "br": branchId + "r": 3 + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "bl": blockId + "br": branchId + "r": 3 + } + m._rbs_ccn = _rbs_ccn + return true + end if + return true + end function + + function RBS_CC_0_reportFunction(functionId) + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "fn": functionId + "r": 4 + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "fn": functionId + "r": 4 } m._rbs_ccn = _rbs_ccn return true @@ -433,67 +622,114 @@ describe('RooibosPlugin', () => { let a = getContents('source/code.brs'); let b = undent(` sub foo(action as string) - if RBS_CC_1_reportLine("2", 2, 0) and (action = "action1") then - RBS_CC_1_reportLine("2", 3, 0) - RBS_CC_1_reportLine("3", 1, 0) + RBS_CC_0_reportFunction(0) + if RBS_CC_0_reportLine(2) and (action = "action1") then + RBS_CC_0_reportLine(2) + RBS_CC_0_reportLine(3) print "action1" - else if RBS_CC_1_reportLine("4", 2, 0) and (action = "action2" or action = "action2") then - RBS_CC_1_reportLine("4", 3, 0) - RBS_CC_1_reportLine("5", 1, 0) + else if RBS_CC_0_reportLine(4) and (action = "action2" or action = "action2") then + RBS_CC_0_reportLine(4) + RBS_CC_0_reportLine(5) print "action2" - else if RBS_CC_1_reportLine("6", 2, 0) and (action = "action3") then - RBS_CC_1_reportLine("6", 3, 0) - RBS_CC_1_reportLine("7", 1, 0) + else if RBS_CC_0_reportLine(6) and (action = "action3") then + RBS_CC_0_reportLine(6) + RBS_CC_0_reportLine(7) print "action3" - else if RBS_CC_1_reportLine("8", 2, 0) and (action = "action4") then - RBS_CC_1_reportLine("8", 3, 0) - else if RBS_CC_1_reportLine("9", 2, 0) and (action = "action5") then - RBS_CC_1_reportLine("9", 3, 0) - RBS_CC_1_reportLine("10", 1, 0) + else if RBS_CC_0_reportLine(8) and (action = "action4") then + RBS_CC_0_reportLine(8) + else if RBS_CC_0_reportLine(9) and (action = "action5") then + RBS_CC_0_reportLine(9) + RBS_CC_0_reportLine(10) print "action5" - else if RBS_CC_1_reportLine("11", 2, 0) and (action = "action6") then - RBS_CC_1_reportLine("11", 3, 0) - RBS_CC_1_reportLine("12", 1, 0) + else if RBS_CC_0_reportLine(11) and (action = "action6") then + RBS_CC_0_reportLine(11) + RBS_CC_0_reportLine(12) print "action6" - else if RBS_CC_1_reportLine("13", 2, 0) and (action = "action7") then - RBS_CC_1_reportLine("13", 3, 0) - RBS_CC_1_reportLine("14", 1, 0) + else if RBS_CC_0_reportLine(13) and (action = "action7") then + RBS_CC_0_reportLine(13) + RBS_CC_0_reportLine(14) print "action7" - else if RBS_CC_1_reportLine("15", 2, 0) and (action = "action8") then - RBS_CC_1_reportLine("15", 3, 0) - RBS_CC_1_reportLine("16", 1, 0) + else if RBS_CC_0_reportLine(15) and (action = "action8") then + RBS_CC_0_reportLine(15) + RBS_CC_0_reportLine(16) print "action8" - else if RBS_CC_1_reportLine("17", 2, 0) and (action = "action9") then - RBS_CC_1_reportLine("17", 3, 0) - RBS_CC_1_reportLine("18", 1, 0) + else if RBS_CC_0_reportLine(17) and (action = "action9") then + RBS_CC_0_reportLine(17) + RBS_CC_0_reportLine(18) print "action9" - else if RBS_CC_1_reportLine("19", 2, 0) and (action = "action10") then - RBS_CC_1_reportLine("19", 3, 0) - RBS_CC_1_reportLine("20", 1, 0) + else if RBS_CC_0_reportLine(19) and (action = "action10") then + RBS_CC_0_reportLine(19) + RBS_CC_0_reportLine(20) print "action10" else - RBS_CC_1_reportLine("21", 3, 0) + RBS_CC_0_reportLine(21) end if end sub - function RBS_CC_1_reportLine(lineNumber, reportType = 1, funcId = -1) + function RBS_CC_0_reportLine(lineNumber) _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "1" + "f": "0" "l": lineNumber - "r": reportType - "fn": funcId + "r": 1 } return true end if _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "1" + "f": "0" "l": lineNumber - "r": reportType - "fn": funcId + "r": 1 + } + m._rbs_ccn = _rbs_ccn + return true + end if + return true + end function + + function RBS_CC_0_reportBranch(blockId, branchId) + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "bl": blockId + "br": branchId + "r": 3 + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "bl": blockId + "br": branchId + "r": 3 + } + m._rbs_ccn = _rbs_ccn + return true + end if + return true + end function + + function RBS_CC_0_reportFunction(functionId) + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "fn": functionId + "r": 4 + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "0" + "fn": functionId + "r": 4 } m._rbs_ccn = _rbs_ccn return true diff --git a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts index 6507f1b7..89ca7c3a 100644 --- a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts +++ b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import type { BrsFile, Editor, ExpressionStatement, FunctionExpression, Program, ProgramBuilder, Statement } from 'brighterscript'; -import { Parser, WalkMode, createVisitor, BinaryExpression, createToken, TokenKind, GroupingExpression, isForStatement, isBlock, isFunctionExpression, ParseMode } from 'brighterscript'; +import type { BrsFile, Editor, ExpressionStatement, FunctionExpression, Identifier, Program, ProgramBuilder, Statement } from 'brighterscript'; +import { Parser, WalkMode, createVisitor, BinaryExpression, createToken, TokenKind, GroupingExpression, isForStatement, isBlock, isFunctionExpression, ParseMode, isFunctionStatement, isCallExpression, isVariableExpression } from 'brighterscript'; import type { RooibosConfig } from './RooibosConfig'; import { RawCodeStatement } from './RawCodeStatement'; import { BrsTranspileState } from 'brighterscript/dist/parser/BrsTranspileState'; @@ -12,22 +12,55 @@ export enum CodeCoverageLineType { noCode = 0, code = 1, condition = 2, - branch = 3 + branch = 3, + function = 4 } export class CodeCoverageProcessor { private coverageBrsTemplate = ` - function RBS_CC_#ID#_reportLine(lineNumber, reportType = 1, funcId = -1) + function RBS_CC_#ID#_reportLine(lineNumber) _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid - _rbs_ccn.entry = { "f": "#ID#", "l": lineNumber, "r": reportType, "fn": funcId } + _rbs_ccn.entry = { "f": "#ID#", "l": lineNumber, "r": ${CodeCoverageLineType.code} } return true end if _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid - _rbs_ccn.entry = { "f": "#ID#", "l": lineNumber, "r": reportType, "fn": funcId } + _rbs_ccn.entry = { "f": "#ID#", "l": lineNumber, "r": ${CodeCoverageLineType.code} } + m._rbs_ccn = _rbs_ccn + return true + end if + return true + end function + + function RBS_CC_#ID#_reportBranch(blockId, branchId) + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { "f": "#ID#", "bl": blockId, "br": branchId, "r": ${CodeCoverageLineType.branch} } + return true + end if + + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { "f": "#ID#", "bl": blockId, "br": branchId, "r": ${CodeCoverageLineType.branch} } + m._rbs_ccn = _rbs_ccn + return true + end if + return true + end function + + function RBS_CC_#ID#_reportFunction(functionId) + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { "f": "#ID#", "fn": functionId, "r": ${CodeCoverageLineType.function} } + return true + end if + + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { "f": "#ID#", "fn": functionId, "r": ${CodeCoverageLineType.function} } m._rbs_ccn = _rbs_ccn return true end if @@ -44,12 +77,16 @@ export class CodeCoverageProcessor { this.functionId = 0; this.fileFactory = fileFactory; this.processedFunctions = new Set(); + this.baseCoverageReport = { + files: [] + }; try { } catch (e) { console.log('Error:', e.stack); } } + private baseCoverageReport: CoverageMap; private config: RooibosConfig; private fileId: number; private functionId: number; @@ -64,6 +101,10 @@ export class CodeCoverageProcessor { private processedFunctions: Set; private astEditor: Editor; + private foundLines: Array; + private foundFunctions: Array; + private foundBlocks: Array; + public generateMetadata(isUsingCoverage: boolean, program: Program) { this.fileFactory.createCoverageComponent(program, this.expectedCoverageMap, this.filePathMap, this.functionMap); } @@ -72,25 +113,32 @@ export class CodeCoverageProcessor { if (this.config.isRecordingCodeCoverage) { this.transpileState = new BrsTranspileState(file); this._processFile(file, astEditor); + this.fileId++; } } public _processFile(file: BrsFile, astEditor: Editor) { - this.fileId++; + this.foundLines = []; + this.foundFunctions = []; + this.foundBlocks = []; + this.coverageMap = new Map(); this.executableLines = new Map(); this.processedStatements = new Set(); this.astEditor = astEditor; file.ast.walk(createVisitor({ + FunctionStatement: (statement, parent, owner, key) => { + this.getFunctionIdInFile(statement, ParseMode.BrighterScript, owner, key); + }, ForStatement: (ds, parent, owner, key) => { - this.addStatement(ds); - ds.forToken.text = `${this.getFuncCallText(ds.range.start.line, CodeCoverageLineType.code, ds)}: for`; + this.addStatement(ds, ds.range.start.line); + ds.forToken.text = `${this.getReportLineHitFuncCallText(ds.range.start.line, CodeCoverageLineType.code, ds, owner, key)}: for`; }, IfStatement: (ifStatement, parent, owner, key) => { - this.addStatement(ifStatement); + this.addStatement(ifStatement, ifStatement.range.start.line); (ifStatement as any).condition = new BinaryExpression( - new RawCodeExpression(this.getFuncCallText(ifStatement.condition.range.start.line, CodeCoverageLineType.condition, ifStatement)), + new RawCodeExpression(this.getReportLineHitFuncCallText(ifStatement.condition.range.start.line, CodeCoverageLineType.condition, ifStatement, owner, key)), createToken(TokenKind.And), new GroupingExpression({ left: createToken(TokenKind.LeftParen), @@ -100,65 +148,69 @@ export class CodeCoverageProcessor { let blockStatements = ifStatement?.thenBranch?.statements; if (blockStatements) { - let coverageStatement = new RawCodeStatement(this.getFuncCallText(ifStatement.range.start.line, CodeCoverageLineType.branch, ifStatement)); + let coverageStatement = new RawCodeStatement(this.getReportLineHitFuncCallText(ifStatement.range.start.line, CodeCoverageLineType.branch, ifStatement, owner, key)); blockStatements.splice(0, 0, coverageStatement); } // Handle the else blocks let elseBlock = ifStatement.elseBranch; if (isBlock(elseBlock) && elseBlock.statements) { - let coverageStatement = new RawCodeStatement(this.getFuncCallText(elseBlock.range.start.line - 1, CodeCoverageLineType.branch, elseBlock)); + let coverageStatement = new RawCodeStatement(this.getReportLineHitFuncCallText(elseBlock.range.start.line - 1, CodeCoverageLineType.branch, elseBlock, owner, key)); elseBlock.statements.splice(0, 0, coverageStatement); } }, GotoStatement: (ds, parent, owner, key) => { - this.addStatement(ds); + this.addStatement(ds, ds.range.start.line); this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key); }, WhileStatement: (ds, parent, owner, key) => { - ds.tokens.while.text = `${this.getFuncCallText(ds.range.start.line, CodeCoverageLineType.code, ds)}: while`; + ds.tokens.while.text = `${this.getReportLineHitFuncCallText(ds.range.start.line, CodeCoverageLineType.code, ds, owner, key)}: while`; }, ReturnStatement: (ds, parent, owner, key) => { - this.addStatement(ds); + this.addStatement(ds, ds.range.start.line); 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, ds)}: for each`; + this.addStatement(ds, ds.range.start.line); + ds.tokens.forEach.text = `${this.getReportLineHitFuncCallText(ds.range.start.line, CodeCoverageLineType.code, ds, owner, key)}: for each`; }, ExitWhileStatement: (ds, parent, owner, key) => { }, PrintStatement: (ds, parent, owner, key) => { - this.addStatement(ds); + this.addStatement(ds, ds.range.start.line); this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key); }, DottedSetStatement: (ds, parent, owner, key) => { - this.addStatement(ds); + this.addStatement(ds, ds.range.start.line); this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key); }, IndexedSetStatement: (ds, parent, owner, key) => { - this.addStatement(ds); + this.addStatement(ds, ds.range.start.line); this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key); }, IncrementStatement: (ds, parent, owner, key) => { - this.addStatement(ds); + this.addStatement(ds, ds.range.start.line); this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key); }, AssignmentStatement: (ds, parent, owner, key) => { if (!isForStatement(parent)) { - this.addStatement(ds); + this.addStatement(ds, ds.range.start.line); this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key); } }, ExpressionStatement: (ds, parent, owner, key) => { - this.addStatement(ds); + if (isCallExpression(ds.expression) && isVariableExpression(ds.expression.callee) && ds.expression.callee.name.text.startsWith('RBS_CC_')) { + return; + } + + this.addStatement(ds, ds.range.start.line); this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key); } }), { walkMode: WalkMode.visitAllRecursive }); @@ -170,6 +222,20 @@ export class CodeCoverageProcessor { this.expectedCoverageMap[this.fileId.toString().trim()] = coverageMapObject; this.filePathMap[this.fileId] = file.pkgPath; this.addBrsAPIText(file, astEditor); + + this.baseCoverageReport.files[this.fileId] = { + sourceFile: file.pkgPath.replace('pkg:', '.').replace('\\', '/'), + lines: this.foundLines.sort((a, b) => a.lineNumber - b.lineNumber), + lineTotalFound: this.foundLines.length, + lineTotalHit: 0, + functions: this.foundFunctions.sort((a, b) => a.startLine - b.startLine), + functionTotalFound: this.foundFunctions.length, + functionTotalHit: 0, + blocks: this.foundBlocks, + branchTotalFound: this.foundBlocks.reduce((currentCount, block) => currentCount + block.branches.length, 0), + branchTotalHit: 0 + }; + console.log(this.baseCoverageReport); } private convertStatementToCoverageStatement(statement: Statement, coverageType: CodeCoverageLineType, owner: any, key: any) { @@ -179,7 +245,7 @@ export class CodeCoverageProcessor { const lineNumber = statement.range.start.line; this.coverageMap.set(lineNumber, coverageType); - const parsed = Parser.parse(this.getFuncCallText(lineNumber, coverageType, statement)).ast.statements[0] as ExpressionStatement; + const parsed = Parser.parse(this.getReportLineHitFuncCallText(lineNumber, coverageType, statement, owner, key)).ast.statements[0] as ExpressionStatement; this.astEditor.arraySplice(owner, key, 0, parsed); // store the statement in a set to avoid handling again after inserting statement above this.processedStatements.add(statement); @@ -190,20 +256,39 @@ export class CodeCoverageProcessor { astEditor.arrayPush(file.ast.statements, ...astCodeToInject); } - private addStatement(statement: Statement, lineNumber?: number) { + private addStatement(statement: Statement, lineNumber: number) { if (!this.executableLines.has(lineNumber)) { this.executableLines.set(lineNumber, statement); + + this.foundLines.push({ + lineNumber: lineNumber, + totalHit: 0 + }); } } - private getFuncCallText(lineNumber: number, lineType: CodeCoverageLineType, statement: Statement) { - const funcId = this.getFunctionIdInFile(statement, ParseMode.BrighterScript); + private getReportLineHitFuncCallText(lineNumber: number, lineType: CodeCoverageLineType, statement: Statement, owner: any, key: any) { + const funcId = this.getFunctionIdInFile(statement, ParseMode.BrighterScript, owner, key); this.coverageMap.set(lineNumber, lineType); - return `RBS_CC_${this.fileId}_reportLine("${lineNumber.toString().trim()}", ${lineType.toString().trim()}, ${funcId})`; + return `RBS_CC_${this.fileId}_reportLine(${lineNumber})`; + } + + private getReportBranchHitFuncCallText(blockId: number, branchId: number, statement: Statement, owner: any, key: any) { + const funcId = this.getFunctionIdInFile(statement, ParseMode.BrighterScript, owner, key); + return `RBS_CC_${this.fileId}_reportBranch(${blockId}, ${branchId})`; } - private getFunctionIdInFile(statement: Statement, parseMode: ParseMode) { - let originalFunc: FunctionExpression = statement.findAncestor(isFunctionExpression); + private getReportFunctionHitFuncCallText(functionId: number, statement: Statement) { + return `RBS_CC_${this.fileId}_reportFunction(${functionId})`; + } + + private getFunctionIdInFile(statement: Statement, parseMode: ParseMode, owner: any, key: any) { + let originalFunc: FunctionExpression; + if (isFunctionStatement(statement)) { + originalFunc = statement.func; + } else { + originalFunc = statement.findAncestor(isFunctionExpression); + } let func: FunctionExpression = originalFunc; let nameParts = []; @@ -225,9 +310,108 @@ export class CodeCoverageProcessor { this.functionMap[this.fileId] = []; } + const parsed = Parser.parse(this.getReportFunctionHitFuncCallText(this.functionMap[this.fileId].length, statement)).ast.statements[0] as ExpressionStatement; + this.astEditor.addToArray(originalFunc.body.statements, 0, parsed); + + this.foundFunctions.push({ + name: name, + startLine: originalFunc.range.start.line, + endLine: originalFunc.range.end.line, + totalHit: 0 + }); this.functionMap[this.fileId].push(name); } return this.functionMap[this.fileId].indexOf(name); } } + + +interface CoverageMap { + files: Array; +} + +interface FileCoverage { + sourceFile: string; + lineTotalFound: number; + lineTotalHit: number; + lines: Array; + functionTotalFound: number; + functionTotalHit: number; + functions: Array; + branchTotalFound: number; + branchTotalHit: number; + blocks: Array; +} + +interface BranchCoverage { + id: string; + branches: Array<{ + id: number; + totalHit: number; + line: number; + }>; +} +interface FunctionCoverage { + name: string; + totalHit: number; + startLine: number; + endLine: number; +} + +interface LineCoverage { + lineNumber: number; + totalHit: number; +} + +function createCovMap(files: Array) { + + let report = ''; + + let covrageMap: CoverageMap = { + files: [] + }; + + for (const file of files) { + report += `TN:\n`; + report += `SF:${file.sourceFile}\n`; + report += `VER:\n`; + + // Add all the found functions for the file + for (const func of file.functions) { + report += `FN:${func.startLine},${func.endLine},${func.name}\n`; + } + + // Write function related data + for (const func of file.functions) { + if (func.totalHit > 0) { + report += `FNDA:${func.totalHit},${func.name}\n`; + } + } + + report += `FNF:${file.functionTotalFound}\n`; + report += `FNH:${file.functionTotalHit}\n`; + + // Write branch related data + for (const block of file.blocks) { + for (const branch of block.branches) { + if (branch.totalHit > 0) { + report += `BRDA:${branch.line},${block.id},${branch.id},${branch.totalHit}\n`; + } + } + } + + report += `BRF:${file.branchTotalFound}\n`; + report += `BRH:${file.branchTotalHit}\n`; + + // Write the per line related data + for (const line of file.lines) { + report += `DA:${line.lineNumber},${line.totalHit}`; + } + + report += `LF:${file.lineTotalFound}\n`; + report += `LH:${file.lineTotalHit}\n`; + report += `end_of_record\n`; + } +} + From 3042933461979f0d8a59f22cb0e13a9eaffc966e Mon Sep 17 00:00:00 2001 From: Christopher Dwyer-Perkins Date: Mon, 12 Feb 2024 15:52:53 -0400 Subject: [PATCH 03/13] Started working on block and branch injection --- .../lib/rooibos/CodeCoverageProcessor.spec.ts | 45 ++++++++++--------- .../src/lib/rooibos/CodeCoverageProcessor.ts | 40 +++++++++++------ 2 files changed, 51 insertions(+), 34 deletions(-) diff --git a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts index 1b2d40b9..c14fab6b 100644 --- a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts +++ b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts @@ -97,6 +97,7 @@ describe('RooibosPlugin', () => { RBS_CC_0_reportLine(3) text = "" RBS_CC_0_reportLine(4): for i = 0 to 10 + RBS_CC_0_reportBranch(0, 0) RBS_CC_0_reportLine(5) text = text + "hello" RBS_CC_0_reportLine(6) @@ -104,16 +105,16 @@ describe('RooibosPlugin', () => { RBS_CC_0_reportLine(7) c += 1 if RBS_CC_0_reportLine(8) and (c = 2) - RBS_CC_0_reportLine(8) + RBS_CC_0_reportBranch(1, 1) RBS_CC_0_reportLine(9) ? "is true" end if if RBS_CC_0_reportLine(12) and (c = 3) - RBS_CC_0_reportLine(12) + RBS_CC_0_reportBranch(2, 2) RBS_CC_0_reportLine(13) ? "free" else - RBS_CC_0_reportLine(14) + RBS_CC_0_reportBranch(3, 3) RBS_CC_0_reportLine(15) ? "not free" end if @@ -230,6 +231,7 @@ describe('RooibosPlugin', () => { RBS_CC_0_reportLine(3) text = "" RBS_CC_0_reportLine(4): for i = 0 to 10 + RBS_CC_0_reportBranch(0, 0) RBS_CC_0_reportLine(5) text = text + "hello" RBS_CC_0_reportLine(6) @@ -237,16 +239,16 @@ describe('RooibosPlugin', () => { RBS_CC_0_reportLine(7) c += 1 if RBS_CC_0_reportLine(8) and (c = 2) - RBS_CC_0_reportLine(8) + RBS_CC_0_reportBranch(1, 1) RBS_CC_0_reportLine(9) ? "is true" end if if RBS_CC_0_reportLine(12) and (c = 3) - RBS_CC_0_reportLine(12) + RBS_CC_0_reportBranch(2, 2) RBS_CC_0_reportLine(13) ? "free" else - RBS_CC_0_reportLine(14) + RBS_CC_0_reportBranch(3, 3) RBS_CC_0_reportLine(15) ? "not free" end if @@ -376,6 +378,7 @@ describe('RooibosPlugin', () => { RBS_CC_0_reportLine(7) text = "" RBS_CC_0_reportLine(8): for i = 0 to 10 + RBS_CC_0_reportBranch(0, 0) RBS_CC_0_reportLine(9) text = text + "hello" RBS_CC_0_reportLine(10) @@ -383,16 +386,16 @@ describe('RooibosPlugin', () => { RBS_CC_0_reportLine(11) c += 1 if RBS_CC_0_reportLine(12) and (c = 2) - RBS_CC_0_reportLine(12) + RBS_CC_0_reportBranch(1, 1) RBS_CC_0_reportLine(13) ? "is true" end if if RBS_CC_0_reportLine(16) and (c = 3) - RBS_CC_0_reportLine(16) + RBS_CC_0_reportBranch(2, 2) RBS_CC_0_reportLine(17) ? "free" else - RBS_CC_0_reportLine(18) + RBS_CC_0_reportBranch(3, 3) RBS_CC_0_reportLine(19) ? "not free" end if @@ -503,7 +506,7 @@ describe('RooibosPlugin', () => { x = function(y) RBS_CC_0_reportFunction(1) if RBS_CC_0_reportLine(2) and ((true)) then - RBS_CC_0_reportLine(2) + RBS_CC_0_reportBranch(0, 0) RBS_CC_0_reportLine(3) return 1 end if @@ -624,45 +627,45 @@ describe('RooibosPlugin', () => { sub foo(action as string) RBS_CC_0_reportFunction(0) if RBS_CC_0_reportLine(2) and (action = "action1") then - RBS_CC_0_reportLine(2) + RBS_CC_0_reportBranch(0, 0) RBS_CC_0_reportLine(3) print "action1" else if RBS_CC_0_reportLine(4) and (action = "action2" or action = "action2") then - RBS_CC_0_reportLine(4) + RBS_CC_0_reportBranch(1, 1) RBS_CC_0_reportLine(5) print "action2" else if RBS_CC_0_reportLine(6) and (action = "action3") then - RBS_CC_0_reportLine(6) + RBS_CC_0_reportBranch(2, 2) RBS_CC_0_reportLine(7) print "action3" else if RBS_CC_0_reportLine(8) and (action = "action4") then - RBS_CC_0_reportLine(8) + RBS_CC_0_reportBranch(3, 3) else if RBS_CC_0_reportLine(9) and (action = "action5") then - RBS_CC_0_reportLine(9) + RBS_CC_0_reportBranch(4, 4) RBS_CC_0_reportLine(10) print "action5" else if RBS_CC_0_reportLine(11) and (action = "action6") then - RBS_CC_0_reportLine(11) + RBS_CC_0_reportBranch(5, 5) RBS_CC_0_reportLine(12) print "action6" else if RBS_CC_0_reportLine(13) and (action = "action7") then - RBS_CC_0_reportLine(13) + RBS_CC_0_reportBranch(6, 6) RBS_CC_0_reportLine(14) print "action7" else if RBS_CC_0_reportLine(15) and (action = "action8") then - RBS_CC_0_reportLine(15) + RBS_CC_0_reportBranch(7, 7) RBS_CC_0_reportLine(16) print "action8" else if RBS_CC_0_reportLine(17) and (action = "action9") then - RBS_CC_0_reportLine(17) + RBS_CC_0_reportBranch(8, 8) RBS_CC_0_reportLine(18) print "action9" else if RBS_CC_0_reportLine(19) and (action = "action10") then - RBS_CC_0_reportLine(19) + RBS_CC_0_reportBranch(9, 9) RBS_CC_0_reportLine(20) print "action10" else - RBS_CC_0_reportLine(21) + RBS_CC_0_reportBranch(10, 10) end if end sub diff --git a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts index 89ca7c3a..f589e119 100644 --- a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts +++ b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import type { BrsFile, Editor, ExpressionStatement, FunctionExpression, Identifier, Program, ProgramBuilder, Statement } from 'brighterscript'; +import type { BrsFile, Editor, ExpressionStatement, FunctionExpression, Program, ProgramBuilder, Statement } from 'brighterscript'; import { Parser, WalkMode, createVisitor, BinaryExpression, createToken, TokenKind, GroupingExpression, isForStatement, isBlock, isFunctionExpression, ParseMode, isFunctionStatement, isCallExpression, isVariableExpression } from 'brighterscript'; import type { RooibosConfig } from './RooibosConfig'; import { RawCodeStatement } from './RawCodeStatement'; @@ -89,6 +89,8 @@ export class CodeCoverageProcessor { private baseCoverageReport: CoverageMap; private config: RooibosConfig; private fileId: number; + private blockId: number; + private branchId: number; private functionId: number; private filePathMap: any; private functionMap: Array>; @@ -112,6 +114,8 @@ export class CodeCoverageProcessor { public addCodeCoverage(file: BrsFile, astEditor: Editor) { if (this.config.isRecordingCodeCoverage) { this.transpileState = new BrsTranspileState(file); + this.blockId = 0; + this.branchId = 0; this._processFile(file, astEditor); this.fileId++; } @@ -131,6 +135,16 @@ export class CodeCoverageProcessor { FunctionStatement: (statement, parent, owner, key) => { this.getFunctionIdInFile(statement, ParseMode.BrighterScript, owner, key); }, + Block: (statement, parent, owner, key) => { + if (!isFunctionExpression(parent)) { + + const lineNumber = statement.range.start.line; + const parsed = Parser.parse(this.getReportBranchHitFuncCallText(this.blockId, this.branchId, statement, owner, key)).ast.statements[0] as ExpressionStatement; + this.astEditor.addToArray(statement.statements, 0, parsed); + this.blockId++; + this.branchId++; + } + }, ForStatement: (ds, parent, owner, key) => { this.addStatement(ds, ds.range.start.line); ds.forToken.text = `${this.getReportLineHitFuncCallText(ds.range.start.line, CodeCoverageLineType.code, ds, owner, key)}: for`; @@ -146,18 +160,18 @@ export class CodeCoverageProcessor { }, ifStatement.condition) ); - let blockStatements = ifStatement?.thenBranch?.statements; - if (blockStatements) { - let coverageStatement = new RawCodeStatement(this.getReportLineHitFuncCallText(ifStatement.range.start.line, CodeCoverageLineType.branch, ifStatement, owner, key)); - blockStatements.splice(0, 0, coverageStatement); - } - - // Handle the else blocks - let elseBlock = ifStatement.elseBranch; - if (isBlock(elseBlock) && elseBlock.statements) { - let coverageStatement = new RawCodeStatement(this.getReportLineHitFuncCallText(elseBlock.range.start.line - 1, CodeCoverageLineType.branch, elseBlock, owner, key)); - elseBlock.statements.splice(0, 0, coverageStatement); - } + // let blockStatements = ifStatement?.thenBranch?.statements; + // if (blockStatements) { + // let coverageStatement = new RawCodeStatement(this.getReportLineHitFuncCallText(ifStatement.range.start.line, CodeCoverageLineType.branch, ifStatement, owner, key)); + // blockStatements.splice(0, 0, coverageStatement); + // } + + // // Handle the else blocks + // let elseBlock = ifStatement.elseBranch; + // if (isBlock(elseBlock) && elseBlock.statements) { + // let coverageStatement = new RawCodeStatement(this.getReportLineHitFuncCallText(elseBlock.range.start.line - 1, CodeCoverageLineType.branch, elseBlock, owner, key)); + // elseBlock.statements.splice(0, 0, coverageStatement); + // } }, GotoStatement: (ds, parent, owner, key) => { From 2a0b6a33a0f426a97d63124a390300760b02c120 Mon Sep 17 00:00:00 2001 From: Christopher Dwyer-Perkins Date: Mon, 12 Feb 2024 15:55:27 -0400 Subject: [PATCH 04/13] Update bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts --- bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts index c14fab6b..ddcdebde 100644 --- a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts +++ b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts @@ -22,7 +22,7 @@ describe('RooibosPlugin', () => { return undent(contents); } - describe.only('CodeCoverageProcessor', () => { + describe('CodeCoverageProcessor', () => { beforeEach(() => { plugin = new RooibosPlugin(); options = { From c5138d3d7cb6ca77150ee23e8bb2e0adb7488744 Mon Sep 17 00:00:00 2001 From: Christopher Dwyer-Perkins Date: Mon, 12 Feb 2024 18:02:33 -0400 Subject: [PATCH 05/13] Branching and repotting from framwork --- .../lib/rooibos/CodeCoverageProcessor.spec.ts | 60 ++--- .../src/lib/rooibos/CodeCoverageProcessor.ts | 223 +++++++++++++++++- bsc-plugin/src/lib/rooibos/FileFactory.ts | 5 +- framework/src/source/CodeCoverage.brs | 146 +++++++----- framework/src/source/CodeCoverage.xml | 9 +- framework/src/source/Coverage.bs | 135 +++++++++-- framework/src/source/TestRunner.bs | 1 + 7 files changed, 455 insertions(+), 124 deletions(-) diff --git a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts index ddcdebde..a1d7f9b3 100644 --- a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts +++ b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts @@ -125,7 +125,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "l": lineNumber "r": 1 } @@ -134,7 +134,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "l": lineNumber "r": 1 } @@ -148,7 +148,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "bl": blockId "br": branchId "r": 3 @@ -158,7 +158,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "bl": blockId "br": branchId "r": 3 @@ -173,7 +173,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "fn": functionId "r": 4 } @@ -182,7 +182,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "fn": functionId "r": 4 } @@ -259,7 +259,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "l": lineNumber "r": 1 } @@ -268,7 +268,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "l": lineNumber "r": 1 } @@ -282,7 +282,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "bl": blockId "br": branchId "r": 3 @@ -292,7 +292,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "bl": blockId "br": branchId "r": 3 @@ -307,7 +307,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "fn": functionId "r": 4 } @@ -316,7 +316,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "fn": functionId "r": 4 } @@ -413,7 +413,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "l": lineNumber "r": 1 } @@ -422,7 +422,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "l": lineNumber "r": 1 } @@ -436,7 +436,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "bl": blockId "br": branchId "r": 3 @@ -446,7 +446,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "bl": blockId "br": branchId "r": 3 @@ -461,7 +461,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "fn": functionId "r": 4 } @@ -470,7 +470,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "fn": functionId "r": 4 } @@ -519,7 +519,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "l": lineNumber "r": 1 } @@ -528,7 +528,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "l": lineNumber "r": 1 } @@ -542,7 +542,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "bl": blockId "br": branchId "r": 3 @@ -552,7 +552,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "bl": blockId "br": branchId "r": 3 @@ -567,7 +567,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "fn": functionId "r": 4 } @@ -576,7 +576,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "fn": functionId "r": 4 } @@ -673,7 +673,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "l": lineNumber "r": 1 } @@ -682,7 +682,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "l": lineNumber "r": 1 } @@ -696,7 +696,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "bl": blockId "br": branchId "r": 3 @@ -706,7 +706,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "bl": blockId "br": branchId "r": 3 @@ -721,7 +721,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "fn": functionId "r": 4 } @@ -730,7 +730,7 @@ describe('RooibosPlugin', () => { _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid _rbs_ccn.entry = { - "f": "0" + "f": 0 "fn": functionId "r": 4 } diff --git a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts index f589e119..b3234a01 100644 --- a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts +++ b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts @@ -22,13 +22,13 @@ export class CodeCoverageProcessor { function RBS_CC_#ID#_reportLine(lineNumber) _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid - _rbs_ccn.entry = { "f": "#ID#", "l": lineNumber, "r": ${CodeCoverageLineType.code} } + _rbs_ccn.entry = { "f": #ID#, "l": lineNumber, "r": ${CodeCoverageLineType.code} } return true end if _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid - _rbs_ccn.entry = { "f": "#ID#", "l": lineNumber, "r": ${CodeCoverageLineType.code} } + _rbs_ccn.entry = { "f": #ID#, "l": lineNumber, "r": ${CodeCoverageLineType.code} } m._rbs_ccn = _rbs_ccn return true end if @@ -38,13 +38,13 @@ export class CodeCoverageProcessor { function RBS_CC_#ID#_reportBranch(blockId, branchId) _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid - _rbs_ccn.entry = { "f": "#ID#", "bl": blockId, "br": branchId, "r": ${CodeCoverageLineType.branch} } + _rbs_ccn.entry = { "f": #ID#, "bl": blockId, "br": branchId, "r": ${CodeCoverageLineType.branch} } return true end if _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid - _rbs_ccn.entry = { "f": "#ID#", "bl": blockId, "br": branchId, "r": ${CodeCoverageLineType.branch} } + _rbs_ccn.entry = { "f": #ID#, "bl": blockId, "br": branchId, "r": ${CodeCoverageLineType.branch} } m._rbs_ccn = _rbs_ccn return true end if @@ -54,13 +54,13 @@ export class CodeCoverageProcessor { function RBS_CC_#ID#_reportFunction(functionId) _rbs_ccn = m._rbs_ccn if _rbs_ccn <> invalid - _rbs_ccn.entry = { "f": "#ID#", "fn": functionId, "r": ${CodeCoverageLineType.function} } + _rbs_ccn.entry = { "f": #ID#, "fn": functionId, "r": ${CodeCoverageLineType.function} } return true end if _rbs_ccn = m?.global?._rbs_ccn if _rbs_ccn <> invalid - _rbs_ccn.entry = { "f": "#ID#", "fn": functionId, "r": ${CodeCoverageLineType.function} } + _rbs_ccn.entry = { "f": #ID#, "fn": functionId, "r": ${CodeCoverageLineType.function} } m._rbs_ccn = _rbs_ccn return true end if @@ -108,7 +108,7 @@ export class CodeCoverageProcessor { private foundBlocks: Array; public generateMetadata(isUsingCoverage: boolean, program: Program) { - this.fileFactory.createCoverageComponent(program, this.expectedCoverageMap, this.filePathMap, this.functionMap); + this.fileFactory.createCoverageComponent(program, this.expectedCoverageMap, this.filePathMap, this.baseCoverageReport); } public addCodeCoverage(file: BrsFile, astEditor: Editor) { @@ -141,8 +141,17 @@ export class CodeCoverageProcessor { const lineNumber = statement.range.start.line; const parsed = Parser.parse(this.getReportBranchHitFuncCallText(this.blockId, this.branchId, statement, owner, key)).ast.statements[0] as ExpressionStatement; this.astEditor.addToArray(statement.statements, 0, parsed); + this.foundBlocks.push({ + id: this.branchId, + branches: [{ + id: this.branchId, + line: lineNumber, + totalHit: 0 + }] + }); this.blockId++; this.branchId++; + } }, ForStatement: (ds, parent, owner, key) => { @@ -249,7 +258,7 @@ export class CodeCoverageProcessor { branchTotalFound: this.foundBlocks.reduce((currentCount, block) => currentCount + block.branches.length, 0), branchTotalHit: 0 }; - console.log(this.baseCoverageReport); + // console.log(this.baseCoverageReport); } private convertStatementToCoverageStatement(statement: Statement, coverageType: CodeCoverageLineType, owner: any, key: any) { @@ -341,7 +350,7 @@ export class CodeCoverageProcessor { } -interface CoverageMap { +export interface CoverageMap { files: Array; } @@ -359,7 +368,7 @@ interface FileCoverage { } interface BranchCoverage { - id: string; + id: number; branches: Array<{ id: number; totalHit: number; @@ -429,3 +438,197 @@ function createCovMap(files: Array) { } } + + + +// function write_info($$$) { +// my $self = $_[0]; +// local *INFO_HANDLE = $_[1]; +// my $checksum = defined($_[2]) ? $_[2] : 0; +// my $br_found; +// my $br_hit; +// my $ln_total_found = 0; +// my $ln_total_hit = 0; +// my $fn_total_found = 0; +// my $fn_total_hit = 0; +// my $br_total_found = 0; +// my $br_total_hit = 0; + +// my $srcReader = ReadCurrentSource->new() +// if (lcovutil::is_filter_enabled()); + +// foreach my $source_file (sort($self->files())) { +// next if lcovutil::is_external($source_file); +// my $entry = $self->data($source_file); +// die("expected TraceInfo, got '" . ref($entry) . "'") +// unless('TraceInfo' eq ref($entry)); + +// my ($testdata, $sumcount, $funcdata, $checkdata, $testfncdata, +// $testbrdata, $sumbrcount, $found, $hit, +// $f_found, $f_hit, $br_found, $br_hit) = $entry->get_info(); + +// # munge the source file name, if requested +// $source_file = lcovutil::subst_file_name($source_file); +// # Add to totals +// $ln_total_found += $found; +// $ln_total_hit += $hit; +// $fn_total_found += $f_found; +// $fn_total_hit += $f_hit; +// $br_total_found += $br_found; +// $br_total_hit += $br_hit; + +// foreach my $testname (sort($testdata->keylist())) { +// my $testcount = $testdata->value($testname); +// my $testfnccount = $testfncdata->value($testname); +// my $testbrcount = $testbrdata->value($testname); +// $found = 0; +// $hit = 0; + +// print(INFO_HANDLE "TN:$testname\n"); +// print(INFO_HANDLE "SF:$source_file\n"); +// print(INFO_HANDLE "VER:" . $entry->version() . "\n") +// if defined($entry->version()); +// if (defined($srcReader)) { +// $srcReader->close(); +// if (is_c_file($source_file)) { +// lcovutil::debug("reading $source_file for lcov filtering\n"); +// if (-e $source_file) { +// $srcReader->open($source_file); +// } else { +// lcovutil::ignorable_error($lcovutil::ERROR_SOURCE, +// "'$source_file' not found (for filtering)") +// if (lcovutil::warn_once($source_file)); +// } +// } else { +// lcovutil::debug("not reading $source_file: no ext match\n"); +// } +// } +// my $functionMap = $testfncdata->{$testname}; +// # Write function related data - sort by line number +// foreach my $key ( sort({$functionMap->findKey($a)->line() <=> $functionMap->findKey($b)->line()} +// $functionMap->keylist())) { +// my $data = $functionMap->findKey($key); +// my $aliases = $data->aliases(); +// foreach my $alias (keys %$aliases) { +// print(INFO_HANDLE "FN:" . $data->line(). ",$alias\n"); +// } +// } +// my $f_found = 0; +// my $f_hit = 0; +// foreach my $key ($functionMap->keylist()) { +// my $data = $functionMap->findKey($key); +// my $aliases = $data->aliases(); +// foreach my $alias (keys %$aliases) { +// my $hit = $aliases->{$alias}; +// ++ $f_found; +// ++ $f_hit if $hit > 0; +// print(INFO_HANDLE "FNDA:$hit,$alias\n"); +// } +// } +// print(INFO_HANDLE "FNF:$f_found\n"); +// print(INFO_HANDLE "FNH:$f_hit\n"); + +// # Write branch related data +// $br_found = 0; +// $br_hit = 0; +// my $currentBranchLine; +// my $skipBranch = 0; +// my $reader = $srcReader +// if (defined($srcReader) && $srcReader->notEmpty()); +// my $branchHistogram = $cov_filter[$FILTER_BRANCH_NO_COND] +// if $reader; + +// foreach my $line (sort({$a <=> $b} +// $testbrcount->keylist())) { + +// # omit if line excluded or branches excluded on this line +// next +// if (defined($reader) && +// ($reader->isOutOfRange($line, 'branch') || +// $reader->isExcluded($line, 1))); + +// my $brdata = $testbrcount->value($line); +// if (defined($branchHistogram)) { +// $skipBranch = ! $reader->containsConditional($line); +// if ($skipBranch) { +// ++ $branchHistogram->[0]; # one line where we skip +// $branchHistogram->[1] += scalar($brdata->blocks()); +// lcovutil::info(2, "skip BRDA '" . +// $reader->getLine($line) . +// "' $source_file:$line\n"); +// next; +// } +// } +// # want the block_id to be treated as 32-bit unsigned integer +// # (need masking to match regression tests) +// my $mask = (1<<32) -1; +// foreach my $block_id ($brdata->blocks()) { +// my $blockData = $brdata->getBlock($block_id); +// $block_id &= $mask; +// foreach my $br (@$blockData) { +// my $taken = $br->data(); +// my $branch_id = $br->id(); +// my $branch_expr = $br->expr(); +// # mostly for Verilog: if there is a branch expression: use it. +// printf(INFO_HANDLE "BRDA:%u,%u,%s,%s\n", +// $line, $block_id, +// defined($branch_expr) ? $branch_expr : $branch_id, $taken); +// $br_found++; +// $br_hit++ +// if ($taken ne '-' && $taken > 0); +// } +// } +// } +// if ($br_found > 0) { +// print(INFO_HANDLE "BRF:$br_found\n"); +// print(INFO_HANDLE "BRH:$br_hit\n"); +// } + +// # Write line related data +// my ($brace_histogram, $blank_histogram); +// if (defined($reader)) { +// $brace_histogram = $cov_filter[$FILTER_LINE_CLOSE_BRACE]; +// $blank_histogram = $cov_filter[$FILTER_BLANK_LINE]; +// } +// foreach my $line (sort({$a <=> $b} $testcount->keylist())) { +// next +// if (defined($reader) && +// ($reader->isOutOfRange($line, 'line') || $reader->isExcluded($line))); + +// my $l_hit = $testcount->value($line); +// if ( ! defined($sumbrcount->value($line))) { +// # don't suppresss if this line has associated branch data + +// if ($brace_histogram && +// $reader->suppressCloseBrace($line, $l_hit, $testcount)) { +// lcovutil::info(2, "skip DA '" . $reader->getLine($line) +// . "' $source_file:$line\n"); +// ++$brace_histogram->[0]; # one location where this applied +// ++$brace_histogram->[1]; # one coverpoint suppressed +// next; +// } elsif ($blank_histogram && +// $l_hit == 0 && +// $reader->isBlank($line)) { +// lcovutil::info(2, "skip DA (empty) $source_file:$line\n"); +// ++ $blank_histogram->[0]; # one location where this applied +// ++ $blank_histogram->[1]; # one coverpoint suppressed +// next; +// } +// } +// my $chk = $checkdata->{$line}; +// print(INFO_HANDLE "DA:$line,$l_hit" . +// (defined($chk) && $checksum ? ",". $chk : "") +// ."\n"); +// $found++; +// $hit++ +// if ($l_hit > 0); +// } +// print(INFO_HANDLE "LF:$found\n"); +// print(INFO_HANDLE "LH:$hit\n"); +// print(INFO_HANDLE "end_of_record\n"); +// } +// } + +// return ($ln_total_found, $ln_total_hit, $fn_total_found, $fn_total_hit, +// $br_total_found, $br_total_hit); +// } \ No newline at end of file diff --git a/bsc-plugin/src/lib/rooibos/FileFactory.ts b/bsc-plugin/src/lib/rooibos/FileFactory.ts index dd84a4e4..e44e1a30 100644 --- a/bsc-plugin/src/lib/rooibos/FileFactory.ts +++ b/bsc-plugin/src/lib/rooibos/FileFactory.ts @@ -3,6 +3,7 @@ import { standardizePath as s } from 'brighterscript'; import * as path from 'path'; import * as fs from 'fs'; import * as fse from 'fs-extra'; +import type { CoverageMap } from './CodeCoverageProcessor'; export class FileFactory { private coverageComponentXmlTemplate; @@ -100,11 +101,11 @@ export class FileFactory { return contents; } - public createCoverageComponent(program: Program, coverageMap: any, filepathMap: Map, functionMap: Array>) { + public createCoverageComponent(program: Program, coverageMap: any, filepathMap: Map, baseCoverageReport: CoverageMap) { let template = this.coverageComponentBrsTemplate; template = template.replace(/\"\#EXPECTED_MAP\#\"/g, JSON.stringify(coverageMap ?? {})); template = template.replace(/\"\#FILE_PATH_MAP\#\"/g, JSON.stringify(filepathMap ?? {})); - template = template.replace(/\"\#FUNCTION_MAP\#\"/g, JSON.stringify(functionMap ?? [])); + template = template.replace(/\"\#BASE_COVERAGE_REPORT\#\"/g, JSON.stringify(baseCoverageReport ?? [])); this.addFileToRootDir(program, path.join('components/rooibos', 'CodeCoverage.brs'), template); this.addFileToRootDir(program, path.join('components/rooibos', 'CodeCoverage.xml'), this.coverageComponentXmlTemplate); diff --git a/framework/src/source/CodeCoverage.brs b/framework/src/source/CodeCoverage.brs index 3bc4ad60..bdf3cfb6 100644 --- a/framework/src/source/CodeCoverage.brs +++ b/framework/src/source/CodeCoverage.brs @@ -17,71 +17,101 @@ function setFilePathMap() m.top.filePathMap = "#FILE_PATH_MAP#" end function -function setFunctionMap() - m.top.functionMap = "#FUNCTION_MAP#" +function getBaseCoverageMap() + return "#BASE_COVERAGE_REPORT#" end function function onEntryChange() entry = m.top.entry ' defer till later - - #if rooibos_poc_enhanced_lcov_support - testName = m.top.testName - if testName <> "" - if not m.resultsByTest.doesExist(testName) - m.resultsByTest[testName] = [] - end if - m.resultsByTest[testName].push(entry) - end if - #end if - m.results.push(entry) end function +' enum CodeCoverageLineType +' noCode = 0 +' code = 1 +' condition = 2 +' branch = 3 +' function = 4 +' end enum + function onSave() ? "saving data" - for each entry in m.results - if entry <> invalid - fileId = entry.f - lineMap = m.resolvedMap[fileId] - - if lineMap = invalid - lineMap = {} - m.resolvedMap[fileId] = lineMap - end if - - if lineMap[entry.l] = invalid - lineMap[entry.l] = [] - end if - - lineMap[entry.l].push({ - r: entry.r - fn: entry.fn - }) - end if - end for - m.top.resolvedMap = m.resolvedMap - - #if rooibos_poc_enhanced_lcov_support - for each testName in m.resultsByTest - resolvedTest = m.resultsByTest[testName] - m.resolvedTestMap[testName] = {} - for each entry in resolvedTest - if entry <> invalid - fileId = entry.f - lineMap = m.resolvedTestMap[testName][fileId] - - if lineMap = invalid - lineMap = {} - m.resolvedTestMap[testName][fileId] = lineMap - end if - lineMap[entry.l] = entry.r - end if - end for - end for - m.top.resolvedTestMap = m.resolvedTestMap - #end if - setExpectedMap() - setFilePathMap() - setFunctionMap() -end function \ No newline at end of file + + ' coverageMap = getBaseCoverageMap() + m.top.baseCoverageMap = getBaseCoverageMap() + m.top.resolved = m.results + + ' for each entry in m.results + ' if entry <> invalid + ' if entry.r = 4 ' CodeCoverageLineType.function + ' coverageMap.files[entry.f].functions[entry.fn].totalHit ++ + ' else if entry.r = 3 ' CodeCoverageLineType.branch + ' for each branch in coverageMap.files[entry.f].blocks[entry.bl].branches + ' if branch.id = entry.br + ' branch.totalHit ++ + ' exit for + ' end if + ' end for + ' else if entry.r = 1 ' CodeCoverageLineType.code + ' for each line in coverageMap.files[entry.f].lines + ' if line.lineNumber = entry.l + ' line.totalHit ++ + ' exit for + ' end if + ' end for + ' end if + ' end if + ' end for + + ' for each file in coverageMap.files + ' for each func in file.functions + ' if func.totalHit > 0 then file.functionTotalHit ++ + ' end for + + ' for each block in file.blocks + ' for each branch in block.branches + ' if branch.totalHit > 0 then file.branchTotalHit ++ + ' end for + ' end for + + ' for each line in file.lines + ' if line.totalHit > 0 then file.lineTotalHit ++ + ' end for + ' end for + + ' m.top.results = coverageMap + ' m.top.resolvedMap = m.resolvedMap + + ' setExpectedMap() + ' setFilePathMap() +end function + +#if false +sub test() + player = m.player + + report = false + if player = invalid or (player.duration > 0 and player.state = "playing") then + report = true + end if + + if report = true then + player.control = "stop" + end if +end sub + + +sub test() + player = m.player + + report = false + if RBS_CC_0_reportCondition(109, 1, player = invalid) or RBS_CC_0_reportCondition(109, 2, (RBS_CC_0_reportCondition(109, 3, player.duration > 0) and RBS_CC_0_reportCondition(109, 4, player.state = "playing"))) then + report = true + end if + + if report = true then + player.control = "stop" + end if +end sub +#end if \ No newline at end of file diff --git a/framework/src/source/CodeCoverage.xml b/framework/src/source/CodeCoverage.xml index ac60a9be..bf262e5d 100644 --- a/framework/src/source/CodeCoverage.xml +++ b/framework/src/source/CodeCoverage.xml @@ -5,12 +5,11 @@