From 793e81461ea51013aaf8631ab3d0fb4733439cee Mon Sep 17 00:00:00 2001 From: Christopher Dwyer-Perkins Date: Thu, 1 Feb 2024 16:42:17 -0500 Subject: [PATCH] Code cov perf and bug fix in if statements (#264) * Added function to bast test suite to store global mocked functions * Moved some logic to the utils * Added logic to inject code that adds global mock checks at the start of function bodys * Fixed a reversed check * Removed new api in favor of expanding stubcall and updated injection code * Updated some of the global function detection logic * Unit tests, fixes, sample test project update * removed console logs * Transpile the file if we had to touch modify it * Fixed global mocks and stubs not clearing * updated some of the checks around transforming stubcall functions * Made some code reusable and fixed some imports * Added back the disablemocking logic and removed unused code * Fixed bad ast related to noEarlyExit * Updated bsc in tests app * added tests for global stubcall on device * Fixed some device tests * Fixed more on device tests * More test fixes as the result of moving to ast editor * Fixed some indenting * Fixed node test xml files being added after modifying assertions leading to crashes * Updated the modify stub detection logic for globals * more tests for global stub call modifications * Fixed some race conditons and more global function detection refinments * Removed some raw code statements for the session and fixed test formatting at a result * removed trimLeading from mock util tests * Removed some raw code statements in code cov and updated test file format * Added a test showing the issue * Fixed the code cov handling of if statements * Updated test app for better covrage * Fixed a bug with the reporting of missed files * Improved code cov reporting perfomance * perf optimization to cc reporting * Some perf changed for code cov * Fixed device by zero crash in reports for cov * Fixed some issues picking the wrong scope and make sure stubcall worked with async tests * Moved global stub clearing to clearStubs() --- .../lib/rooibos/CodeCoverageProcessor.spec.ts | 330 ++++++++++++------ .../src/lib/rooibos/CodeCoverageProcessor.ts | 68 ++-- framework/src/source/CodeCoverage.brs | 26 +- framework/src/source/Coverage.bs | 36 +- framework/src/source/Rooibos.bs | 5 +- tests/src/components/NodeExample.bs | 21 -- tests/src/components/NodeExample.xml | 6 + tests/src/source/Main.bs | 3 - tests/src/source/NewExpectSyntax.spec.bs | 26 ++ tests/src/source/NodeExample.spec.bs | 23 ++ 10 files changed, 355 insertions(+), 189 deletions(-) diff --git a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts index 2171592e..1a038d3d 100644 --- a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts +++ b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.spec.ts @@ -91,53 +91,54 @@ 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) c = 0 - RBS_CC_1_reportLine(3, 1) + RBS_CC_1_reportLine("3", 1) text = "" - RBS_CC_1_reportLine(4, 1): for i = 0 to 10 - RBS_CC_1_reportLine(5, 1) + RBS_CC_1_reportLine("4", 1): for i = 0 to 10 + RBS_CC_1_reportLine("5", 1) text = text + "hello" - RBS_CC_1_reportLine(6, 1) + RBS_CC_1_reportLine("6", 1) c++ - RBS_CC_1_reportLine(7, 1) + RBS_CC_1_reportLine("7", 1) c += 1 - if RBS_CC_1_reportLine(8, 3) and c = 2 - RBS_CC_1_reportLine(9, 1) + if RBS_CC_1_reportLine("8", 2) and (c = 2) + RBS_CC_1_reportLine("8", 3) + RBS_CC_1_reportLine("9", 1) ? "is true" end if - if RBS_CC_1_reportLine(12, 3) and c = 3 - RBS_CC_1_reportLine(13, 1) + if RBS_CC_1_reportLine("12", 2) and (c = 3) + RBS_CC_1_reportLine("12", 3) + RBS_CC_1_reportLine("13", 1) ? "free" else - RBS_CC_1_reportLine(14, 3) - RBS_CC_1_reportLine(15, 1) + RBS_CC_1_reportLine("14", 3) + RBS_CC_1_reportLine("15", 1) ? "not free" end if end for end function function RBS_CC_1_reportLine(lineNumber, reportType = 1) - if m.global = invalid - '? "global is not available in this scope!! it is not possible to record coverage: #FILE_PATH#(lineNumber)" + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "1" + "l": lineNumber + "r": reportType + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "1" + "l": lineNumber + "r": reportType + } + m._rbs_ccn = _rbs_ccn return true - else - if m._rbs_ccn = invalid - '? "Coverage maps are not created - creating now" - if m.global._rbs_ccn = invalid - '? "Coverage maps are not created - creating now" - m.global.addFields({ - "_rbs_ccn": createObject("roSGNode", "CodeCoverage") - }) - end if - m._rbs_ccn = m.global._rbs_ccn - end if end if - m._rbs_ccn.entry = { - "f": "1" - "l": stri(lineNumber) - "r": reportType - } return true end function `); @@ -174,53 +175,54 @@ 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) c = 0 - RBS_CC_1_reportLine(3, 1) + RBS_CC_1_reportLine("3", 1) text = "" - RBS_CC_1_reportLine(4, 1): for i = 0 to 10 - RBS_CC_1_reportLine(5, 1) + RBS_CC_1_reportLine("4", 1): for i = 0 to 10 + RBS_CC_1_reportLine("5", 1) text = text + "hello" - RBS_CC_1_reportLine(6, 1) + RBS_CC_1_reportLine("6", 1) c++ - RBS_CC_1_reportLine(7, 1) + RBS_CC_1_reportLine("7", 1) c += 1 - if RBS_CC_1_reportLine(8, 3) and c = 2 - RBS_CC_1_reportLine(9, 1) + if RBS_CC_1_reportLine("8", 2) and (c = 2) + RBS_CC_1_reportLine("8", 3) + RBS_CC_1_reportLine("9", 1) ? "is true" end if - if RBS_CC_1_reportLine(12, 3) and c = 3 - RBS_CC_1_reportLine(13, 1) + if RBS_CC_1_reportLine("12", 2) and (c = 3) + RBS_CC_1_reportLine("12", 3) + RBS_CC_1_reportLine("13", 1) ? "free" else - RBS_CC_1_reportLine(14, 3) - RBS_CC_1_reportLine(15, 1) + RBS_CC_1_reportLine("14", 3) + RBS_CC_1_reportLine("15", 1) ? "not free" end if end for end function function RBS_CC_1_reportLine(lineNumber, reportType = 1) - if m.global = invalid - '? "global is not available in this scope!! it is not possible to record coverage: #FILE_PATH#(lineNumber)" + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "1" + "l": lineNumber + "r": reportType + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "1" + "l": lineNumber + "r": reportType + } + m._rbs_ccn = _rbs_ccn return true - else - if m._rbs_ccn = invalid - '? "Coverage maps are not created - creating now" - if m.global._rbs_ccn = invalid - '? "Coverage maps are not created - creating now" - m.global.addFields({ - "_rbs_ccn": createObject("roSGNode", "CodeCoverage") - }) - end if - m._rbs_ccn = m.global._rbs_ccn - end if end if - m._rbs_ccn.entry = { - "f": "1" - "l": stri(lineNumber) - "r": reportType - } return true end function `); @@ -270,27 +272,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) c = 0 - RBS_CC_1_reportLine(7, 1) + RBS_CC_1_reportLine("7", 1) text = "" - RBS_CC_1_reportLine(8, 1): for i = 0 to 10 - RBS_CC_1_reportLine(9, 1) + RBS_CC_1_reportLine("8", 1): for i = 0 to 10 + RBS_CC_1_reportLine("9", 1) text = text + "hello" - RBS_CC_1_reportLine(10, 1) + RBS_CC_1_reportLine("10", 1) c++ - RBS_CC_1_reportLine(11, 1) + RBS_CC_1_reportLine("11", 1) c += 1 - if RBS_CC_1_reportLine(12, 3) and c = 2 - RBS_CC_1_reportLine(13, 1) + if RBS_CC_1_reportLine("12", 2) and (c = 2) + RBS_CC_1_reportLine("12", 3) + RBS_CC_1_reportLine("13", 1) ? "is true" end if - if RBS_CC_1_reportLine(16, 3) and c = 3 - RBS_CC_1_reportLine(17, 1) + if RBS_CC_1_reportLine("16", 2) and (c = 3) + RBS_CC_1_reportLine("16", 3) + RBS_CC_1_reportLine("17", 1) ? "free" else - RBS_CC_1_reportLine(18, 3) - RBS_CC_1_reportLine(19, 1) + RBS_CC_1_reportLine("18", 3) + RBS_CC_1_reportLine("19", 1) ? "not free" end if end for @@ -304,26 +308,25 @@ describe('RooibosPlugin', () => { end function function RBS_CC_1_reportLine(lineNumber, reportType = 1) - if m.global = invalid - '? "global is not available in this scope!! it is not possible to record coverage: #FILE_PATH#(lineNumber)" + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "1" + "l": lineNumber + "r": reportType + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "1" + "l": lineNumber + "r": reportType + } + m._rbs_ccn = _rbs_ccn return true - else - if m._rbs_ccn = invalid - '? "Coverage maps are not created - creating now" - if m.global._rbs_ccn = invalid - '? "Coverage maps are not created - creating now" - m.global.addFields({ - "_rbs_ccn": createObject("roSGNode", "CodeCoverage") - }) - end if - m._rbs_ccn = m.global._rbs_ccn - end if end if - m._rbs_ccn.entry = { - "f": "1" - "l": stri(lineNumber) - "r": reportType - } return true end function `); @@ -348,38 +351,143 @@ 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) x = function(y) - if RBS_CC_1_reportLine(2, 3) and (true) then - RBS_CC_1_reportLine(3, 1) + if RBS_CC_1_reportLine("2", 2) and ((true)) then + RBS_CC_1_reportLine("2", 3) + RBS_CC_1_reportLine("3", 1) return 1 end if - RBS_CC_1_reportLine(5, 1) + RBS_CC_1_reportLine("5", 1) return 0 end function end sub function RBS_CC_1_reportLine(lineNumber, reportType = 1) - if m.global = invalid - '? "global is not available in this scope!! it is not possible to record coverage: #FILE_PATH#(lineNumber)" + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "1" + "l": lineNumber + "r": reportType + } return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "1" + "l": lineNumber + "r": reportType + } + m._rbs_ccn = _rbs_ccn + return true + end if + return true + end function + `); + + expect(a).to.equal(b); + }); + + it('correctly transpiles some statements', async () => { + const source = ` + sub foo(action as string) + if action = "action1" then + print "action1" + else if action = "action2" or action = "action2" then + print "action2" + else if action = "action3" then + print "action3" + else if action = "action4" then + else if action = "action5" then + print "action5" + else if action = "action6" then + print "action6" + else if action = "action7" then + print "action7" + else if action = "action8" then + print "action8" + else if action = "action9" then + print "action9" + else if action = "action10" then + print "action10" else - if m._rbs_ccn = invalid - '? "Coverage maps are not created - creating now" - if m.global._rbs_ccn = invalid - '? "Coverage maps are not created - creating now" - m.global.addFields({ - "_rbs_ccn": createObject("roSGNode", "CodeCoverage") - }) - end if - m._rbs_ccn = m.global._rbs_ccn - end if end if - m._rbs_ccn.entry = { - "f": "1" - "l": stri(lineNumber) - "r": reportType - } + end sub + `; + + program.setFile('source/code.bs', source); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + await builder.transpile(); + + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + print "action10" + else + RBS_CC_1_reportLine("21", 3) + end if + end sub + + function RBS_CC_1_reportLine(lineNumber, reportType = 1) + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "1" + "l": lineNumber + "r": reportType + } + return true + end if + _rbs_ccn = m?.global?._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { + "f": "1" + "l": lineNumber + "r": reportType + } + m._rbs_ccn = _rbs_ccn + return true + end if return true end function `); diff --git a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts index 65567b1e..d065db15 100644 --- a/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts +++ b/bsc-plugin/src/lib/rooibos/CodeCoverageProcessor.ts @@ -1,8 +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, isIfStatement, WalkMode, createVisitor } from 'brighterscript'; -import * as brighterscript from 'brighterscript'; +import { Parser, WalkMode, createVisitor, BinaryExpression, createToken, TokenKind, GroupingExpression, isForStatement, isBlock } from 'brighterscript'; import type { RooibosConfig } from './RooibosConfig'; import { RawCodeStatement } from './RawCodeStatement'; import { BrsTranspileState } from 'brighterscript/dist/parser/BrsTranspileState'; @@ -20,23 +19,18 @@ export class CodeCoverageProcessor { private coverageBrsTemplate = ` function RBS_CC_#ID#_reportLine(lineNumber, reportType = 1) - if m.global = invalid - '? "global is not available in this scope!! it is not possible to record coverage: #FILE_PATH#(lineNumber)" + _rbs_ccn = m._rbs_ccn + if _rbs_ccn <> invalid + _rbs_ccn.entry = { "f": "#ID#", "l": lineNumber, "r": reportType } return true - else - if m._rbs_ccn = invalid - '? "Coverage maps are not created - creating now" - if m.global._rbs_ccn = invalid - '? "Coverage maps are not created - creating now" - m.global.addFields({ - "_rbs_ccn": createObject("roSGNode", "CodeCoverage") - }) - end if - m._rbs_ccn = m.global._rbs_ccn - end if end if - m._rbs_ccn.entry = {"f":"#ID#", "l":stri(lineNumber), "r":reportType} + _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 `; @@ -65,9 +59,7 @@ export class CodeCoverageProcessor { private astEditor: Editor; public generateMetadata(isUsingCoverage: boolean, program: Program) { - if (isUsingCoverage) { - this.fileFactory.createCoverageComponent(program, this.expectedCoverageMap, this.filePathMap); - } + this.fileFactory.createCoverageComponent(program, this.expectedCoverageMap, this.filePathMap); } public addCodeCoverage(file: BrsFile, astEditor: Editor) { @@ -89,20 +81,30 @@ export class CodeCoverageProcessor { this.addStatement(ds); ds.forToken.text = `${this.getFuncCallText(ds.range.start.line, CodeCoverageLineType.code)}: for`; }, - IfStatement: (ds, parent, owner, key) => { - let ifStatement = ds; - while (isIfStatement(ifStatement)) { - this.addStatement(ds); - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - (ifStatement as any).condition = new brighterscript.BinaryExpression(new RawCodeExpression(this.getFuncCallText(ds.condition.range.start.line, CodeCoverageLineType.branch)), brighterscript.createToken(brighterscript.TokenKind.And), (ifStatement as any).condition); - ifStatement = ifStatement.elseBranch as any; - } - let blockStatements = (ifStatement as any)?.statements as any[] ?? []; - if (blockStatements?.length > 0) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - let coverageStatement = new RawCodeStatement(this.getFuncCallText((ifStatement as any).range.start.line - 1, CodeCoverageLineType.branch)); + 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)), + createToken(TokenKind.And), + new GroupingExpression({ + left: createToken(TokenKind.LeftParen), + right: createToken(TokenKind.RightParen) + }, ifStatement.condition) + ); + + let blockStatements = ifStatement?.thenBranch?.statements; + if (blockStatements) { + let coverageStatement = new RawCodeStatement(this.getFuncCallText(ifStatement.range.start.line, CodeCoverageLineType.branch)); 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.statements.splice(0, 0, coverageStatement); + } + }, GotoStatement: (ds, parent, owner, key) => { this.addStatement(ds); @@ -143,7 +145,7 @@ export class CodeCoverageProcessor { }, AssignmentStatement: (ds, parent, owner, key) => { - if (!brighterscript.isForStatement(parent)) { + if (!isForStatement(parent)) { this.addStatement(ds); this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key); } @@ -186,6 +188,6 @@ export class CodeCoverageProcessor { } private getFuncCallText(lineNumber: number, lineType: CodeCoverageLineType) { - return `RBS_CC_${this.fileId}_reportLine(${lineNumber.toString().trim()}, ${lineType.toString().trim()})`; + return `RBS_CC_${this.fileId}_reportLine("${lineNumber.toString().trim()}", ${lineType.toString().trim()})`; } } diff --git a/framework/src/source/CodeCoverage.brs b/framework/src/source/CodeCoverage.brs index 88b264b9..8bb7d5e0 100644 --- a/framework/src/source/CodeCoverage.brs +++ b/framework/src/source/CodeCoverage.brs @@ -2,7 +2,7 @@ function init() m.resolvedMap = {} m.top.observeField("entry", "onEntryChange") m.top.observeField("save", "onSave") - + m.results = [] end function function setExpectedMap() @@ -15,20 +15,24 @@ end function function onEntryChange() entry = m.top.entry - if entry <> invalid - lineMap = m.resolvedMap[entry.f] - - if lineMap = invalid - lineMap = {} - end if - lineMap[entry.l] = entry.r - - m.resolvedMap[entry.f] = lineMap - end if + ' defer till later + m.results.push(entry) end function 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 + lineMap[entry.l] = entry.r + end if + end for m.top.resolvedMap = m.resolvedMap setExpectedMap() setFilePathMap() diff --git a/framework/src/source/Coverage.bs b/framework/src/source/Coverage.bs index 512f4fda..1fac97e7 100644 --- a/framework/src/source/Coverage.bs +++ b/framework/src/source/Coverage.bs @@ -5,31 +5,46 @@ namespace rooibos.Coverage ? "There was no rooibos code coverage component - not generating coverage report" return end if + t = createObject("roTimespan") ? "" ? "...Generating code coverage report" ? "" m.global._rbs_ccn.save = true cc = m.global._rbs_ccn + expectedMap = cc.expectedMap + filePathMap = cc.filePathMap + resolvedMap = cc.resolvedMap + hitFiles = [] missFiles = [] allLinesCount = 0 allLinesHit = 0 - for each key in cc.expectedMap - filename = cc.filePathMap[key] - expectedCount = cc.expectedMap[key].count() + for each key in expectedMap + filename = filePathMap[key] + expectedCount = expectedMap[key].count() allLinesCount += expectedCount if expectedCount > 0 - if cc.resolvedMap[key] <> invalid - resolvedCount = cc.resolvedMap[key].count() + if resolvedMap[key] <> invalid + resolvedCount = resolvedMap[key].count() allLinesHit += resolvedCount - resolvedPercent = (resolvedCount / expectedCount) * 100 + if resolvedCount = 0 + resolvedPercent = 0 + else + resolvedPercent = (resolvedCount / expectedCount) * 100 + end if hitFiles.push({ percent: resolvedPercent, text: filename + ": " + str(resolvedPercent).trim() + "% (" + stri(resolvedCount).trim() + "/" + stri(expectedCount).trim() + ")" }) else missFiles.push(filename + ": MISS!") end if + else + missFiles.push(filename + ": MISS!") end if end for - allLinesPercent = (allLinesHit / allLinesCount) * 100 + if allLinesHit = 0 + allLinesPercent = 0 + else + allLinesPercent = (allLinesHit / allLinesCount) * 100 + end if ? "" ? "" ? "+++++++++++++++++++++++++++++++++++++++++++" @@ -37,7 +52,7 @@ namespace rooibos.Coverage ? "+++++++++++++++++++++++++++++++++++++++++++" ? "" ? "Total Coverage: " ; str(allLinesPercent).trim() ; "% (" ; stri(allLinesHit).trim() ; "/" + stri(allLinesCount).trim() ; ")" - ? "Files: " ; cc.resolvedMap.count(); "/" ; cc.expectedMap.count() + ? "Files: " ; resolvedMap.count(); "/" ; expectedMap.count() ? "" ? "HIT FILES" ? "---------" @@ -51,7 +66,10 @@ namespace rooibos.Coverage for i = 0 to missFiles.count() - 1 ? missFiles[i] end for - + ? "" + ? "+++++++++++++++++++++++++++++++++++++++++++" + ? "Code Coverage Report Complete"; t.totalMilliseconds(); "ms" + ? "+++++++++++++++++++++++++++++++++++++++++++" end function function createLCovOutput() diff --git a/framework/src/source/Rooibos.bs b/framework/src/source/Rooibos.bs index f44912be..d94575f4 100644 --- a/framework/src/source/Rooibos.bs +++ b/framework/src/source/Rooibos.bs @@ -18,7 +18,10 @@ namespace rooibos screen.show() m.global = screen.getGlobalNode() - m.global.addFields({ "testsScene": scene }) + m.global.addFields({ + "testsScene": scene + "_rbs_ccn": createObject("roSGNode", "CodeCoverage")' bs:disable-line + }) if scene.hasField("isReadyToStartTests") and scene.isReadyToStartTests = false ? "The scene is not ready yet - waiting for it to set isReadyToStartTests to true" diff --git a/tests/src/components/NodeExample.bs b/tests/src/components/NodeExample.bs index 2ab37287..30f1e129 100644 --- a/tests/src/components/NodeExample.bs +++ b/tests/src/components/NodeExample.bs @@ -16,27 +16,6 @@ function SetLabelText(newText = "") as void m.nameText.text = newText end function - -function r_real_Init() as void - if m.top.stubs["init"] <> invalid - 'mock call here - else - Init() - end if -end function - -function r_real_HelloFromNode(name, age) as string - return "HELLO " + name + " age:" + stri(age) -end function - -function r_real_UpdateState(newState) as void - m.top.state = newState -end function - -function r_real_SetLabelText(newText) as void - m.nameText.text = newText -end function - function delayCall(delay, callback) as void timer = createObject("roSgNode", "Timer") timer.update({ diff --git a/tests/src/components/NodeExample.xml b/tests/src/components/NodeExample.xml index 4b2d58a6..952e4d5f 100644 --- a/tests/src/components/NodeExample.xml +++ b/tests/src/components/NodeExample.xml @@ -2,4 +2,10 @@ + + + + + \ No newline at end of file diff --git a/tests/src/source/Main.bs b/tests/src/source/Main.bs index 627ac475..8f94acf7 100644 --- a/tests/src/source/Main.bs +++ b/tests/src/source/Main.bs @@ -1,8 +1,5 @@ function Main(args) - - ? "here is my code" - ? "hello" end function function globalFunctionWithReturn() as dynamic diff --git a/tests/src/source/NewExpectSyntax.spec.bs b/tests/src/source/NewExpectSyntax.spec.bs index efd6956b..e67c4c92 100644 --- a/tests/src/source/NewExpectSyntax.spec.bs +++ b/tests/src/source/NewExpectSyntax.spec.bs @@ -319,6 +319,15 @@ namespace tests @it("stubs namespace and then cleans it") function _() + getGlobalAA().wasCalled = false + m.stubCall(testNamespace.functionWithReturn, function() + m.wasCalled = true + return true + end function) + + m.assertTrue(testNamespace.functionWithReturn()) + m.assertTrue(getGlobalAA().wasCalled) + getGlobalAA().wasCalled = false m.stubCall(testNamespace.functionWithoutReturn, sub() m.wasCalled = true @@ -329,6 +338,10 @@ namespace tests m.cleanStubs() + m.assertFalse(testNamespace.functionWithReturn()) + m.assertFalse(getGlobalAA().wasCalled) + + getGlobalAA().wasCalled = true m.assertInvalid(testNamespace.functionWithoutReturn()) m.assertFalse(getGlobalAA().wasCalled) @@ -337,6 +350,15 @@ namespace tests @it("stubs global and then cleans it") function _() + getGlobalAA().wasCalled = false + m.stubCall(globalFunctionWithReturn, function() + m.wasCalled = true + return true + end function) + + m.assertTrue(globalFunctionWithReturn()) + m.assertTrue(getGlobalAA().wasCalled) + getGlobalAA().wasCalled = false m.stubCall(globalFunctionWithoutReturn, sub() m.wasCalled = true @@ -347,6 +369,10 @@ namespace tests m.cleanStubs() + m.assertFalse(globalFunctionWithReturn()) + m.assertFalse(getGlobalAA().wasCalled) + + getGlobalAA().wasCalled = true m.assertInvalid(globalFunctionWithoutReturn()) m.assertFalse(getGlobalAA().wasCalled) diff --git a/tests/src/source/NodeExample.spec.bs b/tests/src/source/NodeExample.spec.bs index 940f9831..ef470b7a 100644 --- a/tests/src/source/NodeExample.spec.bs +++ b/tests/src/source/NodeExample.spec.bs @@ -68,6 +68,29 @@ namespace tests m.timer.observeFieldScoped("fire", callback) m.timer.control = "start" end function + + @it("updates state") + @params("start") + @params("stop") + @params("error") + function _(state) + m.node.top.state = "" + UpdateState(state) + m.assertEqual(m.node.top.state, state) + end function + + @it("updates name text") + @params("jon") + @params("ringo") + @params("ringo") + @params("ringo") + @params("george") + @params("paul") + function _(text) + m.node.nameText.text = "" + SetLabelText(text) + m.assertEqual(m.node.nameText.text, text) + end function end class end namespace