From 63e75d8ab6c7826ac1a1d318252c9c5cc3d48119 Mon Sep 17 00:00:00 2001 From: georgejecook Date: Sun, 22 Oct 2023 22:42:57 +0100 Subject: [PATCH] adds support for expecting on global functions and namespace functions --- bsc-plugin/src/lib/rooibos/MockUtil.spec.ts | 336 ++++++++++++++++++ bsc-plugin/src/lib/rooibos/MockUtil.ts | 94 +++++ bsc-plugin/src/lib/rooibos/RooibosConfig.ts | 2 + bsc-plugin/src/lib/rooibos/TestGroup.ts | 80 ++++- .../src/lib/rooibos/TestSuiteBuilder.spec.ts | 84 ++--- bsc-plugin/src/plugin.spec.ts | 152 +++++++- bsc-plugin/src/plugin.ts | 78 +++- docs/index.md | 14 +- framework/src/source/BaseTestSuite.bs | 289 ++++++++------- framework/src/source/CommonUtils.bs | 156 ++++---- framework/src/source/ConsoleTestReporter.bs | 16 +- framework/src/source/Matchers.bs | 12 +- framework/src/source/RooibosScene.xml | 2 +- framework/src/source/TestRunner.bs | 6 +- tests/bsconfig.json | 3 +- tests/src/manifest | 5 +- tests/src/source/Common.spec.bs | 10 +- tests/src/source/Expect.spec.bs | 1 + tests/src/source/Globals.bs | 9 + tests/src/source/NewExpectSyntax.spec.bs | 73 +++- 20 files changed, 1123 insertions(+), 299 deletions(-) create mode 100644 bsc-plugin/src/lib/rooibos/MockUtil.spec.ts create mode 100644 bsc-plugin/src/lib/rooibos/MockUtil.ts create mode 100644 tests/src/source/Globals.bs diff --git a/bsc-plugin/src/lib/rooibos/MockUtil.spec.ts b/bsc-plugin/src/lib/rooibos/MockUtil.spec.ts new file mode 100644 index 00000000..2964dcb5 --- /dev/null +++ b/bsc-plugin/src/lib/rooibos/MockUtil.spec.ts @@ -0,0 +1,336 @@ +/* eslint-disable @typescript-eslint/no-confusing-void-expression */ +import { Program, ProgramBuilder, util, standardizePath as s } from 'brighterscript'; +import { expect } from 'chai'; +import PluginInterface from 'brighterscript/dist/PluginInterface'; +import * as fsExtra from 'fs-extra'; +import { RooibosPlugin } from '../../plugin'; + +let tmpPath = s`${process.cwd()}/tmp`; +let _rootDir = s`${tmpPath}/rootDir`; +let _stagingFolderPath = s`${tmpPath}/staging`; + +function trimLeading(text: string) { + return text.split('\n').map((line) => line.trimStart()).join('\n'); +} + +describe('MockUtil', () => { + let program: Program; + let builder: ProgramBuilder; + let plugin: RooibosPlugin; + let options; + + function getContents(filename: string) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + return trimLeading(fsExtra.readFileSync(s`${_stagingFolderPath}/${filename}`).toString()); + } + + describe('MockUtil', () => { + beforeEach(() => { + plugin = new RooibosPlugin(); + options = { + rootDir: _rootDir, + stagingFolderPath: _stagingFolderPath, + rooibos: { + isGlobalMethodMockingEnabled: true, + globalMethodMockingExcludedFiles: [ + '**/*.coverageExcluded.bs' + ] + }, + allowBrighterScriptInBrightScript: true + }; + fsExtra.ensureDirSync(_stagingFolderPath); + fsExtra.ensureDirSync(_rootDir); + fsExtra.ensureDirSync(tmpPath); + + builder = new ProgramBuilder(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + builder.options = util.normalizeAndResolveConfig(options); + builder.program = new Program(builder.options); + program = builder.program; + program.logger = builder.logger; + builder.plugins = new PluginInterface([plugin], { logger: builder.logger }); + program.plugins = new PluginInterface([plugin], { logger: builder.logger }); + program.createSourceScope(); //ensure source scope is created + plugin.beforeProgramCreate(builder); + + }); + afterEach(() => { + plugin.afterProgramCreate(program); + fsExtra.ensureDirSync(tmpPath); + fsExtra.emptyDirSync(tmpPath); + builder.dispose(); + program.dispose(); + }); + + describe('basic brs tests', () => { + + // This test fails unless `allowBrighterScriptInBrightScript` is set to true when setting up the program + // in `beforeEach`. This is because the compiler normally skips processing .brs files and copies them as-is. + it('adds util code to a brs file', async () => { + program.setFile('source/code.brs', ` + function sayHello(a1, a2) + print "hello" + end function + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + await builder.transpile(); + let a = getContents('source/code.brs'); + let b = trimLeading(`function sayHello(a1, a2) + if RBS_CC_1_getMocksByFunctionName()["sayHello"] <> invalid + return RBS_CC_1_getMocksByFunctionName()["sayHello"](a1,a2) + end if + print "hello" + end function + + function RBS_CC_1_getMocksByFunctionName() + if m._rMocksByFunctionName = invalid + m._rMocksByFunctionName = {} + end if + return m._rMocksByFunctionName + end function +`); + expect(a).to.equal(b); + + }); + }); + describe('basic bs tests', () => { + + it('enables mocking on global functions', async () => { + program.setFile('source/code.bs', ` + function sayHello(a1, a2) + print "hello" + end function + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + await builder.transpile(); + let a = getContents('source/code.brs'); + let b = trimLeading(`function sayHello(a1, a2) + if RBS_CC_1_getMocksByFunctionName()["sayHello"] <> invalid + return RBS_CC_1_getMocksByFunctionName()["sayHello"](a1,a2) + end if + print "hello" + end function + + function RBS_CC_1_getMocksByFunctionName() + if m._rMocksByFunctionName = invalid + m._rMocksByFunctionName = {} + end if + return m._rMocksByFunctionName + end function +`); + expect(a).to.equal(b); + + }); + + it('enables mocking on global sub', async () => { + program.setFile('source/code.bs', ` + sub sayHello(a1, a2) + print "hello" + end sub + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + await builder.transpile(); + let a = getContents('source/code.brs'); + let b = trimLeading(`sub sayHello(a1, a2) + if RBS_CC_1_getMocksByFunctionName()["sayHello"] <> invalid + RBS_CC_1_getMocksByFunctionName()["sayHello"](a1,a2) + return + end if + print "hello" + end sub + + function RBS_CC_1_getMocksByFunctionName() + if m._rMocksByFunctionName = invalid + m._rMocksByFunctionName = {} + end if + return m._rMocksByFunctionName + end function +`); + expect(a).to.equal(b); + + }); + + it('enables mocking on namespaced function', async () => { + program.setFile('source/code.bs', ` + namespace person.utils + function sayHello(a1, a2) + print "hello" + end function + end namespace + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + await builder.transpile(); + let a = getContents('source/code.brs'); + let b = trimLeading(`function person_utils_sayHello(a1, a2) + if RBS_CC_1_getMocksByFunctionName()["person_utils_sayHello"] <> invalid + return RBS_CC_1_getMocksByFunctionName()["person_utils_sayHello"](a1,a2) + end if + print "hello" + end function + + function RBS_CC_1_getMocksByFunctionName() + if m._rMocksByFunctionName = invalid + m._rMocksByFunctionName = {} + end if + return m._rMocksByFunctionName + end function +`); + expect(a).to.equal(b); + + }); + + it('enables mocking on namespaced sub', async () => { + program.setFile('source/code.bs', ` + namespace person.utils + sub sayHello(a1, a2) + print "hello" + end sub + end namespace + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + await builder.transpile(); + let a = getContents('source/code.brs'); + let b = trimLeading(`sub person_utils_sayHello(a1, a2) + if RBS_CC_1_getMocksByFunctionName()["person_utils_sayHello"] <> invalid + RBS_CC_1_getMocksByFunctionName()["person_utils_sayHello"](a1,a2) + return + end if + print "hello" + end sub + + function RBS_CC_1_getMocksByFunctionName() + if m._rMocksByFunctionName = invalid + m._rMocksByFunctionName = {} + end if + return m._rMocksByFunctionName + end function +`); + expect(a).to.equal(b); + + }); + + it('does not affect class methods', async () => { + program.setFile('source/code.bs', ` + class Person + sub sayHello(a1, a2) + print "hello" + end sub + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + await builder.transpile(); + let a = getContents('source/code.brs'); + let b = trimLeading(`function __Person_builder() + instance = {} + instance.new = sub() + end sub + instance.sayHello = sub(a1, a2) + print "hello" + end sub + return instance + end function + function Person() + instance = __Person_builder() + instance.new() + return instance + end function`); + expect(a).to.equal(b); + + }); + it('will add stub code to namespace and global methods in a file with a class', async () => { + program.setFile('source/code.bs', ` + namespace beings + class Person + sub sayHello(a1, a2) + print "hello" + end sub + end class + function sayHello() + print "hello2" + end function + end namespace + function sayHello() + print "hello3" + end function + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + await builder.transpile(); + let a = getContents('source/code.brs'); + let b = trimLeading(`function __beings_Person_builder() + instance = {} + instance.new = sub() + end sub + instance.sayHello = sub(a1, a2) + print "hello" + end sub + return instance + end function + function beings_Person() + instance = __beings_Person_builder() + instance.new() + return instance + end function + + function beings_sayHello() + if RBS_CC_1_getMocksByFunctionName()["beings_sayHello"] <> invalid + return RBS_CC_1_getMocksByFunctionName()["beings_sayHello"]() + end if + print "hello2" + end function + + function sayHello() + if RBS_CC_1_getMocksByFunctionName()["sayHello"] <> invalid + return RBS_CC_1_getMocksByFunctionName()["sayHello"]() + end if + print "hello3" + end function + + function RBS_CC_1_getMocksByFunctionName() + if m._rMocksByFunctionName = invalid + m._rMocksByFunctionName = {} + end if + return m._rMocksByFunctionName + end function +`); + expect(a).to.equal(b); + + }); + + }); + + it('excludes files from coverage', async () => { + const source = `sub foo() + x = function(y) + if (true) then + return 1 + end if + return 0 + end function + end sub`; + + program.setFile('source/code.coverageExcluded.bs', source); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + await builder.transpile(); + + let a = getContents('source/code.coverageExcluded.brs'); + let b = `sub foo() +x = function(y) +if (true) then +return 1 +end if +return 0 +end function +end sub`; + + expect(a).to.equal(b); + }); + }); +}); diff --git a/bsc-plugin/src/lib/rooibos/MockUtil.ts b/bsc-plugin/src/lib/rooibos/MockUtil.ts new file mode 100644 index 00000000..0ade64c7 --- /dev/null +++ b/bsc-plugin/src/lib/rooibos/MockUtil.ts @@ -0,0 +1,94 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +import type { BrsFile, Editor, ProgramBuilder } from 'brighterscript'; +import { Position, isClassStatement } from 'brighterscript'; +import * as brighterscript from 'brighterscript'; +import type { RooibosConfig } from './RooibosConfig'; +import { RawCodeStatement } from './RawCodeStatement'; +import { Range } from 'vscode-languageserver-types'; +import type { FileFactory } from './FileFactory'; +import undent from 'undent'; + +export class MockUtil { + + constructor(builder: ProgramBuilder, fileFactory: FileFactory) { + this.config = (builder.options as any).rooibos as RooibosConfig || {}; + this.filePathMap = {}; + this.fileId = 0; + this.fileFactory = fileFactory; + try { + } catch (e) { + console.log('Error:', e.stack); + } + } + + private brsFileAdditions = ` + function RBS_CC_#ID#_getMocksByFunctionName() + if m._rMocksByFunctionName = invalid + m._rMocksByFunctionName = {} + end if + return m._rMocksByFunctionName + end function +`; + + private config: RooibosConfig; + private fileId: number; + private filePathMap: any; + private fileFactory: FileFactory; + private processedStatements: Set; + private astEditor: Editor; + + public enableGlobalMethodMocks(file: BrsFile, astEditor: Editor) { + if (this.config.isGlobalMethodMockingEnabled) { + this._processFile(file, astEditor); + } + } + + public _processFile(file: BrsFile, astEditor: Editor) { + this.fileId++; + this.processedStatements = new Set(); + this.astEditor = astEditor; + + for (let fs of file.parser.references.functionExpressions) { + this.enableMockOnFunction(fs); + } + + this.filePathMap[this.fileId] = file.pkgPath; + if (this.processedStatements.size > 0) { + this.addBrsAPIText(file); + } + } + + private enableMockOnFunction(functionExpression: brighterscript.FunctionExpression) { + if (isClassStatement(functionExpression.parent?.parent)) { + return; + } + if (this.processedStatements.has(functionExpression)) { + return; + } + + const methodName = functionExpression.functionStatement.getName(brighterscript.ParseMode.BrightScript); + for (let param of functionExpression.parameters) { + param.asToken = null; + } + const paramNames = functionExpression.parameters.map((param) => param.name.text).join(','); + + const returnStatement = (functionExpression.functionType.kind === brighterscript.TokenKind.Sub || functionExpression.returnTypeToken?.kind === brighterscript.TokenKind.Void) ? 'return' : 'return result'; + this.astEditor.addToArray(functionExpression.body.statements, 0, new RawCodeStatement(undent` + if RBS_CC_${this.fileId}_getMocksByFunctionName()["${methodName}"] <> invalid + result = RBS_CC_${this.fileId}_getMocksByFunctionName()["${methodName}"].callback(${paramNames}) + ${returnStatement} + end if + `)); + + this.processedStatements.add(functionExpression); + } + + public addBrsAPIText(file: BrsFile) { + //TODO should use ast editor! + const func = new RawCodeStatement(this.brsFileAdditions.replace(/\#ID\#/g, this.fileId.toString().trim()), file, Range.create(Position.create(1, 1), Position.create(1, 1))); + file.ast.statements.push(func); + } + +} + diff --git a/bsc-plugin/src/lib/rooibos/RooibosConfig.ts b/bsc-plugin/src/lib/rooibos/RooibosConfig.ts index 222cc38c..d9bcbf68 100644 --- a/bsc-plugin/src/lib/rooibos/RooibosConfig.ts +++ b/bsc-plugin/src/lib/rooibos/RooibosConfig.ts @@ -9,6 +9,8 @@ export enum RooibosLogLevel { export interface RooibosConfig { coverageExcludedFiles?: string[]; isRecordingCodeCoverage?: boolean; + isGlobalMethodMockingEnabled?: boolean; + globalMethodMockingExcludedFiles?: string[]; logLevel?: RooibosLogLevel; showOnlyFailures?: boolean; failFast?: boolean; diff --git a/bsc-plugin/src/lib/rooibos/TestGroup.ts b/bsc-plugin/src/lib/rooibos/TestGroup.ts index 51a2e22c..4d8fb107 100644 --- a/bsc-plugin/src/lib/rooibos/TestGroup.ts +++ b/bsc-plugin/src/lib/rooibos/TestGroup.ts @@ -11,6 +11,7 @@ import type { TestSuite } from './TestSuite'; import { TestBlock } from './TestSuite'; import { overrideAstTranspile, sanitizeBsJsonString } from './Utils'; import undent from 'undent'; +import type { NamespaceContainer } from '../../plugin'; export class TestGroup extends TestBlock { @@ -49,7 +50,7 @@ export class TestGroup extends TestBlock { return [...this.testCases.values()]; } - public modifyAssertions(testCase: TestCase, noEarlyExit: boolean, editor: AstEditor) { + public modifyAssertions(testCase: TestCase, noEarlyExit: boolean, editor: AstEditor, namespaceLookup: Map) { //for each method //if assertion //wrap with if is not fail @@ -66,13 +67,13 @@ export class TestGroup extends TestBlock { let assertRegex = /(?:fail|assert(?:[a-z0-9]*)|expect(?:[a-z0-9]*)|stubCall)/i; if (dge && assertRegex.test(dge.name.text)) { if (dge.name.text === 'stubCall') { - this.modifyModernRooibosExpectCallExpression(callExpression, editor); + this.modifyModernRooibosExpectCallExpression(callExpression, editor, namespaceLookup); return expressionStatement; } else { if (dge.name.text === 'expectCalled' || dge.name.text === 'expectNotCalled') { - this.modifyModernRooibosExpectCallExpression(callExpression, editor); + this.modifyModernRooibosExpectCallExpression(callExpression, editor, namespaceLookup); } //TODO change this to editor.setProperty(parentObj, parentKey, new SourceNode()) once bsc supports it overrideAstTranspile(editor, expressionStatement, '\n' + undent` @@ -94,7 +95,7 @@ export class TestGroup extends TestBlock { } } - private modifyModernRooibosExpectCallExpression(callExpression: CallExpression, editor: AstEditor) { + private modifyModernRooibosExpectCallExpression(callExpression: CallExpression, editor: AstEditor, namespaceLookup: Map) { let isNotCalled = false; let isStubCall = false; if (isDottedGetExpression(callExpression.callee)) { @@ -106,17 +107,46 @@ export class TestGroup extends TestBlock { //modify args let arg0 = callExpression.args[0]; if (brighterscript.isCallExpression(arg0) && isDottedGetExpression(arg0.callee)) { - let functionName = arg0.callee.name.text; - let fullPath = this.getStringPathFromDottedGet(arg0.callee.obj as DottedGetExpression); - editor.removeFromArray(callExpression.args, 0); - if (!isNotCalled && !isStubCall) { - const expectedArgs = new ArrayLiteralExpression(arg0.args, createToken(TokenKind.LeftSquareBracket), createToken(TokenKind.RightSquareBracket)); - editor.addToArray(callExpression.args, 0, expectedArgs); + + //is it a namespace? + let dg = arg0.callee; + let nameParts = this.getAllDottedGetParts(dg); + let name = nameParts.pop(); + + if (name) { + //is a namespace? + if (nameParts[0] && namespaceLookup.has(nameParts[0].toLowerCase())) { + //then this must be a namespace method + let fullPathName = nameParts.join('.').toLowerCase(); + let ns = namespaceLookup.get(fullPathName); + if (!ns) { + //TODO this is an error condition! + } + nameParts.push(name); + let functionName = nameParts.join('_').toLowerCase(); + editor.removeFromArray(callExpression.args, 0); + if (!isNotCalled && !isStubCall) { + const expectedArgs = new ArrayLiteralExpression(arg0.args, createToken(TokenKind.LeftSquareBracket), createToken(TokenKind.RightSquareBracket)); + editor.addToArray(callExpression.args, 0, expectedArgs); + } + editor.addToArray(callExpression.args, 0, createInvalidLiteral()); + editor.addToArray(callExpression.args, 0, createInvalidLiteral()); + editor.addToArray(callExpression.args, 0, createStringLiteral(functionName)); + editor.addToArray(callExpression.args, 0, brighterscript.createVariableExpression(functionName)); + } + } else { + let functionName = arg0.callee.name.text; + let fullPath = this.getStringPathFromDottedGet(arg0.callee.obj as DottedGetExpression); + editor.removeFromArray(callExpression.args, 0); + if (!isNotCalled && !isStubCall) { + const expectedArgs = new ArrayLiteralExpression(arg0.args, createToken(TokenKind.LeftSquareBracket), createToken(TokenKind.RightSquareBracket)); + editor.addToArray(callExpression.args, 0, expectedArgs); + } + editor.addToArray(callExpression.args, 0, fullPath ?? createInvalidLiteral()); + editor.addToArray(callExpression.args, 0, this.getRootObjectFromDottedGet(arg0.callee)); + editor.addToArray(callExpression.args, 0, createStringLiteral(functionName)); + editor.addToArray(callExpression.args, 0, arg0.callee.obj); } - editor.addToArray(callExpression.args, 0, fullPath ?? createInvalidLiteral()); - editor.addToArray(callExpression.args, 0, this.getRootObjectFromDottedGet(arg0.callee)); - editor.addToArray(callExpression.args, 0, createStringLiteral(functionName)); - editor.addToArray(callExpression.args, 0, arg0.callee.obj); } else if (brighterscript.isDottedGetExpression(arg0)) { let functionName = arg0.name.text; let fullPath = this.getStringPathFromDottedGet(arg0.obj as DottedGetExpression); @@ -145,6 +175,17 @@ export class TestGroup extends TestBlock { editor.addToArray(callExpression.args, 0, this.getRootObjectFromDottedGet(arg0.callee as DottedGetExpression)); editor.addToArray(callExpression.args, 0, createStringLiteral('callFunc')); editor.addToArray(callExpression.args, 0, arg0.callee); + } else if (brighterscript.isCallExpression(arg0) && brighterscript.isVariableExpression(arg0.callee)) { + let functionName = arg0.callee.getName(brighterscript.ParseMode.BrightScript); + editor.removeFromArray(callExpression.args, 0); + if (!isNotCalled && !isStubCall) { + const expectedArgs = new ArrayLiteralExpression(arg0.args, createToken(TokenKind.LeftSquareBracket), createToken(TokenKind.RightSquareBracket)); + editor.addToArray(callExpression.args, 0, expectedArgs); + } + editor.addToArray(callExpression.args, 0, createInvalidLiteral()); + editor.addToArray(callExpression.args, 0, createInvalidLiteral()); + editor.addToArray(callExpression.args, 0, createStringLiteral(functionName)); + editor.addToArray(callExpression.args, 0, brighterscript.createVariableExpression(functionName)); } } @@ -218,4 +259,15 @@ export class TestGroup extends TestBlock { return root; } + getAllDottedGetParts(dg: DottedGetExpression) { + let parts = [dg?.name?.text]; + let nextPart = dg.obj; + while (isDottedGetExpression(nextPart) || isVariableExpression(nextPart)) { + parts.push(nextPart?.name?.text); + nextPart = isDottedGetExpression(nextPart) ? nextPart.obj : undefined; + } + return parts.reverse(); + } + + } diff --git a/bsc-plugin/src/lib/rooibos/TestSuiteBuilder.spec.ts b/bsc-plugin/src/lib/rooibos/TestSuiteBuilder.spec.ts index a6fc7d5e..75c8e18f 100644 --- a/bsc-plugin/src/lib/rooibos/TestSuiteBuilder.spec.ts +++ b/bsc-plugin/src/lib/rooibos/TestSuiteBuilder.spec.ts @@ -78,7 +78,7 @@ describe('TestSuiteBuilder tests ', () => { it('duplicate suite name - different files', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -90,7 +90,7 @@ describe('TestSuiteBuilder tests ', () => { assertSuite(ts, 1); let testSuite2 = createTestSuite('test2.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -106,7 +106,7 @@ describe('TestSuiteBuilder tests ', () => { it('duplicate suite name - same file', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -114,7 +114,7 @@ describe('TestSuiteBuilder tests ', () => { end function end class @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -129,7 +129,7 @@ describe('TestSuiteBuilder tests ', () => { it('duplicate group', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -150,7 +150,7 @@ describe('TestSuiteBuilder tests ', () => { it('duplicate test', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -173,7 +173,7 @@ describe('TestSuiteBuilder tests ', () => { let testSuite = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @describe("group1") @@ -194,7 +194,7 @@ end namespace let testSuite = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @describe("group1") @@ -218,7 +218,7 @@ end namespace let testSuite = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @describe("group1") @@ -248,7 +248,7 @@ end namespace let testSuite = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @@ -274,7 +274,7 @@ end namespace let testSuite = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @@ -294,7 +294,7 @@ end namespace let testSuite = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @@ -316,7 +316,7 @@ end namespace let testSuite = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @@ -344,7 +344,7 @@ end namespace let ts = createTestSuite('test1.bs', `namespace Tests @only @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -370,7 +370,7 @@ end namespace it('only group', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @only @describe("group1") @@ -397,7 +397,7 @@ end namespace it('only test', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @only @@ -424,7 +424,7 @@ end namespace it('two tests', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @only @@ -451,7 +451,7 @@ end namespace it('two tests and group', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @only @describe("group1") @@ -480,7 +480,7 @@ end namespace let ts = createTestSuite('test1.bs', `namespace Tests @only @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @only @describe("group1") @@ -509,7 +509,7 @@ end namespace let ts = createTestSuite('test1.bs', `namespace Tests @only @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @only @describe("group1") @@ -546,7 +546,7 @@ end namespace let ts = createTestSuite('test1.bs', `namespace Tests @only @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @only @describe("group1") @@ -582,7 +582,7 @@ end namespace it('only on param block', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @Only @@ -615,7 +615,7 @@ end namespace it('onlyparams', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -647,7 +647,7 @@ end namespace it('onlyparams 2', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -683,7 +683,7 @@ end namespace let ts = createTestSuite('test1.bs', `namespace Tests @ignore @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -708,7 +708,7 @@ end namespace it('ignore group', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @ignore @describe("group1") @@ -733,7 +733,7 @@ end namespace it('ignore test', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @ignore @@ -760,7 +760,7 @@ end namespace it('two tests', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @ignore @@ -787,7 +787,7 @@ end namespace it('two tests and group', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @ignore @describe("group1") @@ -816,7 +816,7 @@ end namespace let ts = createTestSuite('test1.bs', `namespace Tests @ignore @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @ignore @describe("group1") @@ -846,7 +846,7 @@ end namespace let ts = createTestSuite('test1.bs', `namespace Tests @ignore @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @ignore @describe("group1") @@ -885,7 +885,7 @@ end namespace let ts = createTestSuite('test1.bs', `namespace Tests @ignore @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @ignore @describe("group1") @@ -923,7 +923,7 @@ end namespace it('ignore on param block', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @ignore @@ -956,7 +956,7 @@ end namespace it('ignoreParams', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -988,7 +988,7 @@ end namespace it('ignoreParams 2', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -1023,7 +1023,7 @@ end namespace it('simple params', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -1042,7 +1042,7 @@ end namespace it('2 params', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -1062,7 +1062,7 @@ end namespace it('2 with url and chars', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -1081,7 +1081,7 @@ end namespace it('param mismatch -no params', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -1095,7 +1095,7 @@ end namespace it('param mismatch -one', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -1113,7 +1113,7 @@ end namespace it('param mismatch -all', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") @@ -1131,7 +1131,7 @@ end namespace it('cannot parse', () => { let ts = createTestSuite('test1.bs', `namespace Tests @suite("Rooibos assertion tests") - class AssertionTests extends Rooibos.BaseTestSuite + class AssertionTests extends rooibos.BaseTestSuite @describe("group1") @it("one") diff --git a/bsc-plugin/src/plugin.spec.ts b/bsc-plugin/src/plugin.spec.ts index 881352aa..c3424b1d 100644 --- a/bsc-plugin/src/plugin.spec.ts +++ b/bsc-plugin/src/plugin.spec.ts @@ -11,7 +11,7 @@ let _rootDir = s`${tmpPath}/rootDir`; let _stagingFolderPath = s`${tmpPath}/staging`; const version = fsExtra.readJsonSync(__dirname + '/../package.json').version; -describe('RooibosPlugin', () => { +describe.only('RooibosPlugin', () => { let program: Program; let builder: ProgramBuilder; let plugin: RooibosPlugin; @@ -21,7 +21,10 @@ describe('RooibosPlugin', () => { options = { rootDir: _rootDir, stagingFolderPath: _stagingFolderPath, - stagingDir: _stagingFolderPath + stagingDir: _stagingFolderPath, + rooibos: { + isGlobalMethodMockingEnabled: true + } }; fsExtra.ensureDirSync(_stagingFolderPath); fsExtra.ensureDirSync(_rootDir); @@ -895,6 +898,146 @@ describe('RooibosPlugin', () => { if m.currentResult?.isFail = true then m.done() : return invalid `); }); + it('correctly transpiles global function calls', async () => { + + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + item = {id: "item"} + m.expectCalled(sayHello("arg1", "arg2"), "return") + m.expectCalled(sayHello()) + m.expectCalled(sayHello(), "return") + m.expectCalled(sayHello("arg1", "arg2")) + end function + end class + `); + program.setFile('source/code.bs', ` + function sayHello(firstName = "" as string, lastName = "" as string) + print firstName + " " + lastName + end function + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + const testText = getTestFunctionContents(true); + expect( + testText + ).to.eql(undent` + item = { + id: "item" + } + + m.currentAssertLineNumber = 7 + m._expectCalled(invalid, "sayHello", invalid, invalid, [ + "arg1" + "arg2" + ], "return") + if m.currentResult?.isFail = true then m.done() : return invalid + + + m.currentAssertLineNumber = 8 + m._expectCalled(invalid, "sayHello", invalid, invalid, []) + if m.currentResult?.isFail = true then m.done() : return invalid + + + m.currentAssertLineNumber = 9 + m._expectCalled(invalid, "sayHello", invalid, invalid, [], "return") + if m.currentResult?.isFail = true then m.done() : return invalid + + + m.currentAssertLineNumber = 10 + m._expectCalled(invalid, "sayHello", invalid, invalid, [ + "arg1" + "arg2" + ]) + if m.currentResult?.isFail = true then m.done() : return invalid +`); + + let codeText = getContents('code.brs'); + expect(codeText).to.equal(` + TODO +`); + }); + it.only('correctly transpiles namespaced function calls', async () => { + plugin.config.isGlobalMethodMockingEnabled = true; + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + item = {id: "item"} + m.expectCalled(utils.sayHello("arg1", "arg2"), "return") + m.expectCalled(utils.sayHello()) + m.expectCalled(utils.sayHello(), "return") + m.expectCalled(utils.sayHello("arg1", "arg2")) + end function + end class + `); + program.setFile('source/code.bs', ` + namespace utils + function sayHello(firstName = "" as string, lastName = "" as string) + print firstName + " " + lastName + end function + end namespace + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + const testText = getTestFunctionContents(true); + expect( + testText + ).to.eql(undent` + item = { + id: "item" + } + + m.currentAssertLineNumber = 7 + m._expectCalled(utils_sayhello, "utils_sayhello", invalid, invalid, [ + "arg1" + "arg2" + ]) + if m.currentResult?.isFail = true then m.done() : return invalid + + + m.currentAssertLineNumber = 8 + m._expectCalled(utils_sayhello, "utils_sayhello", invalid, invalid, []) + if m.currentResult?.isFail = true then m.done() : return invalid + + + m.currentAssertLineNumber = 9 + m._expectCalled(utils_sayhello, "utils_sayhello", invalid, invalid, []) + if m.currentResult?.isFail = true then m.done() : return invalid + + + m.currentAssertLineNumber = 10 + m._expectCalled(utils_sayhello, "utils_sayhello", invalid, invalid, [ + "arg1" + "arg2" + ]) + if m.currentResult?.isFail = true then m.done() : return invalid +`); + + let codeText = trimLeading(getContents('code.brs')); + expect(codeText).to.equal(trimLeading(`function utils_sayHello(firstName = "", lastName = "") + if RBS_CC_1_getMocksByFunctionName()["utils_sayHello"] <> invalid + return RBS_CC_1_getMocksByFunctionName()["utils_sayHello"](firstName,lastName) + end if + print firstName + " " + lastName + end function + + function RBS_CC_1_getMocksByFunctionName() + if m._rMocksByFunctionName = invalid + m._rMocksByFunctionName = {} + end if + return m._rMocksByFunctionName + end functiond`)); + }); }); describe('stubCall transpilation', () => { @@ -1578,3 +1721,8 @@ function getTestSubContents(trimEveryLine = false) { } return result; } + +function trimLeading(text: string) { + return text.split('\n').map((line) => line.trimStart()).join('\n'); +} + diff --git a/bsc-plugin/src/plugin.ts b/bsc-plugin/src/plugin.ts index 84c38d6e..25ca0c82 100644 --- a/bsc-plugin/src/plugin.ts +++ b/bsc-plugin/src/plugin.ts @@ -6,7 +6,12 @@ import type { TranspileObj, AstEditor, BeforeFileTranspileEvent, - PluginHandler + PluginHandler, + ClassStatement, + FunctionStatement, + Statement, + Scope, + BrsFile } from 'brighterscript'; import { isBrsFile @@ -16,12 +21,26 @@ import { CodeCoverageProcessor } from './lib/rooibos/CodeCoverageProcessor'; import { FileFactory } from './lib/rooibos/FileFactory'; import type { RooibosConfig } from './lib/rooibos/RooibosConfig'; import * as minimatch from 'minimatch'; +import { MockUtil } from './lib/rooibos/MockUtil'; + + +export interface NamespaceContainer { + file: BscFile; + fullName: string; + nameRange: Range; + lastPartName: string; + statements: Statement[]; + classStatements: Record; + functionStatements: Record; + namespaces: Record; +} export class RooibosPlugin implements CompilerPlugin { public name = 'rooibosPlugin'; public session: RooibosSession; public codeCoverageProcessor: CodeCoverageProcessor; + public mockUtil: MockUtil; public fileFactory: FileFactory; public _builder: ProgramBuilder; public config: RooibosConfig; @@ -35,6 +54,7 @@ export class RooibosPlugin implements CompilerPlugin { if (!this.session) { this.session = new RooibosSession(builder, this.fileFactory); this.codeCoverageProcessor = new CodeCoverageProcessor(builder, this.fileFactory); + this.mockUtil = new MockUtil(builder, this.fileFactory); } } private getConfig(options: any) { @@ -57,6 +77,9 @@ export class RooibosPlugin implements CompilerPlugin { if (config.isRecordingCodeCoverage === undefined) { config.isRecordingCodeCoverage = false; } + if (config.isGlobalMethodMockingEnabled === undefined) { + config.isGlobalMethodMockingEnabled = false; + } if (config.keepAppOpen === undefined) { config.keepAppOpen = true; } @@ -85,6 +108,18 @@ export class RooibosPlugin implements CompilerPlugin { config.coverageExcludedFiles.push(...defaultCoverageExcluded); } + const defaultGlobalMethodMockingExcluded = [ + '**/*.spec.bs', + '**/roku_modules/**/*', + '**/source/main.bs', + '**/source/rooibos/**/*' + ]; + if (config.globalMethodMockingExcludedFiles === undefined) { + config.globalMethodMockingExcludedFiles = defaultGlobalMethodMockingExcluded; + } else { + config.globalMethodMockingExcludedFiles.push(...defaultGlobalMethodMockingExcluded); + } + return config; } @@ -129,9 +164,10 @@ export class RooibosPlugin implements CompilerPlugin { } testSuite.addDataFunctions(event.editor as any); + const namespaceLookup = this.getNamespaces(testSuite.file); for (let group of [...testSuite.testGroups.values()].filter((tg) => tg.isIncluded)) { for (let testCase of [...group.testCases.values()].filter((tc) => tc.isIncluded)) { - group.modifyAssertions(testCase, noEarlyExit, event.editor as any); + group.modifyAssertions(testCase, noEarlyExit, event.editor as any, namespaceLookup); } } if (testSuite.isNodeTest) { @@ -139,8 +175,13 @@ export class RooibosPlugin implements CompilerPlugin { } } - if (isBrsFile(event.file) && this.shouldAddCodeCoverageToFile(event.file)) { - this.codeCoverageProcessor.addCodeCoverage(event.file, event.editor); + if (isBrsFile(event.file)) { + if (this.shouldAddCodeCoverageToFile(event.file)) { + this.codeCoverageProcessor.addCodeCoverage(event.file, event.editor); + } + if (this.shouldEnableGlobalMocksOnFile(event.file)) { + this.mockUtil.enableGlobalMethodMocks(event.file, event.editor); + } } } @@ -183,6 +224,35 @@ export class RooibosPlugin implements CompilerPlugin { } return true; } + + shouldEnableGlobalMocksOnFile(file: BscFile) { + if (!isBrsFile(file) || !this.config.isGlobalMethodMockingEnabled) { + return false; + } else if (!this.config.globalMethodMockingExcludedFiles) { + return true; + } else { + for (let filter of this.config.globalMethodMockingExcludedFiles) { + if (minimatch(file.pkgPath, filter)) { + return false; + } + } + } + return true; + } + + public getNamespaceLookup(scope: Scope): Map { + // eslint-disable-next-line @typescript-eslint/dot-notation + return scope['cache'].getOrAdd('namespaceLookup', () => scope.buildNamespaceLookup() as any); + } + + private getNamespaces(file: BrsFile) { + let scopeNamespaces = new Map(); + for (let scope of file.program.getScopesForFile(file)) { + let scopeMap = this.getNamespaceLookup(scope); + scopeNamespaces = new Map([...Array.from(scopeMap.entries())]); + } + return scopeNamespaces; + } } export default () => { diff --git a/docs/index.md b/docs/index.md index 1ebd54ae..3e0f0302 100644 --- a/docs/index.md +++ b/docs/index.md @@ -162,7 +162,7 @@ Rooibos has a hierarchy of tests as follows: Test suites are defined by: - declaring a class _inside_ a namespace - - which extends `Rooibos.BaseTestSuite` + - which extends `rooibos.BaseTestSuite` - and has a `@suite` annotation No special file naming is required. I recommend you call your files `thing.spec.bs` @@ -171,7 +171,7 @@ Please note that rooibos tests are _brighterscript_ only. You can test regular b ### Some advice -I find it really handy to have my own BaseTestSuite, that extends `Rooibos.BaseTestSuite` and I use that as the base of all my tests. In this way I can easily use common utilities and use common beforeEach/setup for setting things up. +I find it really handy to have my own BaseTestSuite, that extends `rooibos.BaseTestSuite` and I use that as the base of all my tests. In this way I can easily use common utilities and use common beforeEach/setup for setting things up. ### Simple example The following is a minimum working example of a Rooibos test suite, named `Simple.brs` @@ -181,7 +181,7 @@ The following is a minimum working example of a Rooibos test suite, named `Simpl namespace tests @suite("basic tests") - class BasicTests extends Rooibos.BaseTestSuite + class BasicTests extends rooibos.BaseTestSuite '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @describe("tests the node context is available for a Node scope function") @@ -206,7 +206,7 @@ Note, you can also use sub, if you wish namespace tests @suite("basic tests") - class BasicTests extends Rooibos.BaseTestSuite + class BasicTests extends rooibos.BaseTestSuite '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @describe("tests the node context is available for a Node scope function") @@ -408,7 +408,7 @@ In addition, we can also use beforeEach and afterEach to run before **each and e ``` namespace Tests - class SampleTest extends Rooibos.BaseTestSuite + class SampleTest extends rooibos.BaseTestSuite override function setup() m.values = [{index:1,name:"one"},{index:4, name:"four"},{index:12, name:"twelve"}] @@ -828,7 +828,7 @@ For example, using a function pointer (.brs): For example, using a function pointer (bs): ``` - m.expectCalled(m.myClass.doWork({"matcher": Rooibos.Matcher.anyArray}), returnValue) + m.expectCalled(m.myClass.doWork({"matcher": rooibos.Matcher.anyArray}), returnValue) ``` And inline: @@ -1044,7 +1044,7 @@ end function ### Global test setup -I find it really handy to have my own BaseTestSuite, that extends `Rooibos.BaseTestSuite` and I use that as the base of all my tests. In this way I can easily use common utilities and use common beforeEach/setup for setting things up. +I find it really handy to have my own BaseTestSuite, that extends `rooibos.BaseTestSuite` and I use that as the base of all my tests. In this way I can easily use common utilities and use common beforeEach/setup for setting things up. You can always call the super beforeEach/setup/teardown/etc from your other tests, making it trivial to do global setup functions. diff --git a/framework/src/source/BaseTestSuite.bs b/framework/src/source/BaseTestSuite.bs index 60c9f77a..4a04fea1 100644 --- a/framework/src/source/BaseTestSuite.bs +++ b/framework/src/source/BaseTestSuite.bs @@ -332,7 +332,7 @@ namespace rooibos return false end if try - if Rooibos.Common.isBoolean(expr) + if rooibos.common.isBoolean(expr) if expr return m.fail(msg) end if @@ -362,7 +362,7 @@ namespace rooibos return false end if try - if Rooibos.Common.isBoolean(expr) + if rooibos.common.isBoolean(expr) if not expr return m.fail(msg) end if @@ -394,10 +394,10 @@ namespace rooibos return false end if try - if not Rooibos.Common.eqValues(first, second) + if not rooibos.common.eqValues(first, second) if msg = "" - first_as_string = Rooibos.Common.asString(first, true) - second_as_string = Rooibos.Common.asString(second, true) + first_as_string = rooibos.common.asString(first, true) + second_as_string = rooibos.common.asString(second, true) msg = first_as_string + " != " + second_as_string end if m.currentResult.fail(msg, m.currentAssertLineNumber) @@ -428,10 +428,10 @@ namespace rooibos return false end if try - if not Rooibos.Common.eqValues(first, second, true) + if not rooibos.common.eqValues(first, second, true) if msg = "" - first_as_string = Rooibos.Common.asString(first) - second_as_string = Rooibos.Common.asString(second) + first_as_string = rooibos.common.asString(first) + second_as_string = rooibos.common.asString(second) msg = first_as_string + " != " + second_as_string end if m.currentResult.fail(msg, m.currentAssertLineNumber) @@ -462,10 +462,10 @@ namespace rooibos return false end if try - if Rooibos.Common.eqValues(first, second) + if rooibos.common.eqValues(first, second) if msg = "" - first_as_string = Rooibos.Common.asString(first, true) - second_as_string = Rooibos.Common.asString(second, true) + first_as_string = rooibos.common.asString(first, true) + second_as_string = rooibos.common.asString(second, true) msg = first_as_string + " == " + second_as_string end if m.currentResult.fail(msg, m.currentAssertLineNumber) @@ -498,7 +498,7 @@ namespace rooibos try if value <> invalid if msg = "" - expr_as_string = Rooibos.Common.asString(value, true) + expr_as_string = rooibos.common.asString(value, true) msg = expr_as_string + " <> Invalid" end if m.currentResult.fail(msg, m.currentAssertLineNumber) @@ -560,7 +560,7 @@ namespace rooibos return false end if try - if Rooibos.Common.isAssociativeArray(array) + if rooibos.common.isAssociativeArray(array) if not array.DoesExist(key) if msg = "" msg = "Array doesn't have the '" + key + "' key." @@ -599,7 +599,7 @@ namespace rooibos end if try - if Rooibos.Common.isAssociativeArray(array) + if rooibos.common.isAssociativeArray(array) if array.DoesExist(key) if msg = "" msg = "Array has the '" + key + "' key." @@ -638,7 +638,7 @@ namespace rooibos end if try - if Rooibos.Common.isAssociativeArray(array) and Rooibos.Common.isArray(keys) + if rooibos.common.isAssociativeArray(array) and rooibos.common.isArray(keys) for each key in keys if not array.DoesExist(key) if msg = "" @@ -678,7 +678,7 @@ namespace rooibos return false end if try - if Rooibos.Common.isAssociativeArray(array) and Rooibos.Common.isArray(keys) + if rooibos.common.isAssociativeArray(array) and rooibos.common.isArray(keys) for each key in keys if array.DoesExist(key) if msg = "" @@ -721,9 +721,9 @@ namespace rooibos return false end if try - if Rooibos.Common.isAssociativeArray(array) or Rooibos.Common.isArray(array) - if not Rooibos.Common.arrayContains(array, value, key) - msg = "Array doesn't have the '" + Rooibos.Common.asString(value, true) + "' value." + if rooibos.common.isAssociativeArray(array) or rooibos.common.isArray(array) + if not rooibos.common.arrayContains(array, value, key) + msg = "Array doesn't have the '" + rooibos.common.asString(value, true) + "' value." m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -757,27 +757,27 @@ namespace rooibos return false end if try - if not Rooibos.Common.isArray(values) + if not rooibos.common.isArray(values) msg = "values to search for are not an Array." m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if - if Rooibos.Common.isArray(array) + if rooibos.common.isArray(array) for each value in values isMatched = false - if not Rooibos.Common.isAssociativeArray(value) - msg = "Value to search for was not associativeArray " + Rooibos.Common.asString(value, true) + if not rooibos.common.isAssociativeArray(value) + msg = "Value to search for was not associativeArray " + rooibos.common.asString(value, true) m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if for each item in array - if Rooibos.Common.IsAssociativeArray(item) + if rooibos.common.IsAssociativeArray(item) isValueMatched = true for each key in value fieldValue = value[key] itemValue = item[key] - if not Rooibos.Common.eqValues(fieldValue, itemValue) + if not rooibos.common.eqValues(fieldValue, itemValue) isValueMatched = false exit for end if @@ -790,7 +790,7 @@ namespace rooibos end for ' items in array if not isMatched - msg = "array missing value: " + Rooibos.Common.asString(value, true) + msg = "array missing value: " + rooibos.common.asString(value, true) m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -828,9 +828,9 @@ namespace rooibos return false end if try - if Rooibos.Common.isAssociativeArray(array) or Rooibos.Common.isArray(array) - if Rooibos.Common.arrayContains(array, value, key) - msg = "Array has the '" + Rooibos.Common.asString(value, true) + "' value." + if rooibos.common.isAssociativeArray(array) or rooibos.common.isArray(array) + if rooibos.common.arrayContains(array, value, key) + msg = "Array has the '" + rooibos.common.asString(value, true) + "' value." m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -864,8 +864,8 @@ namespace rooibos return false end if try - if (Rooibos.Common.isAssociativeArray(array) and Rooibos.Common.isAssociativeArray(subset)) or (Rooibos.Common.isArray(array) and Rooibos.Common.isArray(subset)) - isAA = Rooibos.Common.isAssociativeArray(subset) + if (rooibos.common.isAssociativeArray(array) and rooibos.common.isAssociativeArray(subset)) or (rooibos.common.isArray(array) and rooibos.common.isArray(subset)) + isAA = rooibos.common.isAssociativeArray(subset) for each item in subset key = invalid value = item @@ -873,8 +873,8 @@ namespace rooibos key = item value = subset[key] end if - if not Rooibos.Common.arrayContains(array, value, key) - msg = "Array doesn't have the '" + Rooibos.Common.asString(value, true) + "' value." + if not rooibos.common.arrayContains(array, value, key) + msg = "Array doesn't have the '" + rooibos.common.asString(value, true) + "' value." m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -909,8 +909,8 @@ namespace rooibos return false end if try - if (Rooibos.Common.isAssociativeArray(array) and Rooibos.Common.isAssociativeArray(subset)) or (Rooibos.Common.isArray(array) and Rooibos.Common.isArray(subset)) - isAA = Rooibos.Common.isAssociativeArray(subset) + if (rooibos.common.isAssociativeArray(array) and rooibos.common.isAssociativeArray(subset)) or (rooibos.common.isArray(array) and rooibos.common.isArray(subset)) + isAA = rooibos.common.isAssociativeArray(subset) for each item in subset key = invalid value = item @@ -918,8 +918,8 @@ namespace rooibos key = item value = item[key] end if - if Rooibos.Common.arrayContains(array, value, key) - msg = "Array has the '" + Rooibos.Common.asString(value, true) + "' value." + if rooibos.common.arrayContains(array, value, key) + msg = "Array has the '" + rooibos.common.asString(value, true) + "' value." m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -954,9 +954,9 @@ namespace rooibos return false end if try - if Rooibos.Common.isAssociativeArray(array) or Rooibos.Common.isArray(array) + if rooibos.common.isAssociativeArray(array) or rooibos.common.isArray(array) if array.Count() <> count - msg = "Array items count " + Rooibos.Common.asString(array.Count()) + " <> " + Rooibos.Common.asString(count) + "." + msg = "Array items count " + rooibos.common.asString(array.Count()) + " <> " + rooibos.common.asString(count) + "." m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -990,9 +990,9 @@ namespace rooibos return false end if try - if Rooibos.Common.isAssociativeArray(array) or Rooibos.Common.isArray(array) + if rooibos.common.isAssociativeArray(array) or rooibos.common.isArray(array) if array.Count() = count - msg = "Array items count = " + Rooibos.Common.asString(count) + "." + msg = "Array items count = " + rooibos.common.asString(count) + "." m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -1025,15 +1025,15 @@ namespace rooibos return false end if try - if Rooibos.Common.isAssociativeArray(item) or Rooibos.Common.isArray(item) + if rooibos.common.isAssociativeArray(item) or rooibos.common.isArray(item) if item.count() > 0 msg = "Array is not empty." m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if - else if Rooibos.Common.isString(item) - if Rooibos.Common.asString(item) <> "" - msg = "String is not empty, contains: " + Rooibos.Common.asString(item, true) + else if rooibos.common.isString(item) + if rooibos.common.asString(item) <> "" + msg = "String is not empty, contains: " + rooibos.common.asString(item, true) m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -1066,13 +1066,13 @@ namespace rooibos return false end if try - if Rooibos.Common.isAssociativeArray(item) or Rooibos.Common.isArray(item) + if rooibos.common.isAssociativeArray(item) or rooibos.common.isArray(item) if item.count() = 0 msg = "Array is empty." m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if - else if Rooibos.Common.isString(item) + else if rooibos.common.isString(item) if item = "" msg = "Input value is empty." m.currentResult.fail(msg, m.currentAssertLineNumber) @@ -1115,13 +1115,13 @@ namespace rooibos return false end if - if Rooibos.Common.isAssociativeArray(array) or Rooibos.Common.isArray(array) + if rooibos.common.isAssociativeArray(array) or rooibos.common.isArray(array) methodName = "Rooibos_Common_Is" + typeStr typeCheckFunction = m.getIsTypeFunction(methodName) if typeCheckFunction <> invalid for each item in array if not typeCheckFunction(item) - msg = Rooibos.Common.asString(item, true) + " is not a '" + typeStr + "' type." + msg = rooibos.common.asString(item, true) + " is not a '" + typeStr + "' type." m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -1147,35 +1147,35 @@ namespace rooibos function getIsTypeFunction(name) if name = "Rooibos_Common_IsFunction" - return Rooibos.Common.isFunction + return rooibos.common.isFunction else if name = "Rooibos_Common_IsXmlElement" - return Rooibos.Common.isXmlElement + return rooibos.common.isXmlElement else if name = "Rooibos_Common_IsInteger" - return Rooibos.Common.isInteger + return rooibos.common.isInteger else if name = "Rooibos_Common_IsBoolean" - return Rooibos.Common.isBoolean + return rooibos.common.isBoolean else if name = "Rooibos_Common_IsFloat" - return Rooibos.Common.isFloat + return rooibos.common.isFloat else if name = "Rooibos_Common_IsDouble" - return Rooibos.Common.isDouble + return rooibos.common.isDouble else if name = "Rooibos_Common_IsLongInteger" - return Rooibos.Common.isLongInteger + return rooibos.common.isLongInteger else if name = "Rooibos_Common_IsNumber" - return Rooibos.Common.isNumber + return rooibos.common.isNumber else if name = "Rooibos_Common_IsList" - return Rooibos.Common.isList + return rooibos.common.isList else if name = "Rooibos_Common_IsArray" - return Rooibos.Common.isArray + return rooibos.common.isArray else if name = "Rooibos_Common_IsAssociativeArray" - return Rooibos.Common.isAssociativeArray + return rooibos.common.isAssociativeArray else if name = "Rooibos_Common_IsSGNode" - return Rooibos.Common.isSGNode + return rooibos.common.isSGNode else if name = "Rooibos_Common_IsString" - return Rooibos.Common.isString + return rooibos.common.isString else if name = "Rooibos_Common_IsDateTime" - return Rooibos.Common.isDateTime + return rooibos.common.isDateTime else if name = "Rooibos_Common_IsUndefined" - return Rooibos.Common.isUndefined + return rooibos.common.isUndefined else return invalid end if @@ -1199,7 +1199,7 @@ namespace rooibos try if type(value) <> typeStr if msg = "" - expr_as_string = Rooibos.Common.asString(value, true) + expr_as_string = rooibos.common.asString(value, true) msg = expr_as_string + " was not expected type " + typeStr end if m.currentResult.fail(msg, m.currentAssertLineNumber) @@ -1232,14 +1232,14 @@ namespace rooibos try if type(value) <> "roSGNode" if msg = "" - expr_as_string = Rooibos.Common.asString(value, true) + expr_as_string = rooibos.common.asString(value, true) msg = expr_as_string + " was not a node, so could not match subtype " + typeStr end if m.currentResult.fail(msg, m.currentAssertLineNumber) return false else if value.subType() <> typeStr if msg = "" - expr_as_string = Rooibos.Common.asString(value, true) + expr_as_string = rooibos.common.asString(value, true) msg = expr_as_string + "( type : " + value.subType() + ") was not of subType " + typeStr end if m.currentResult.fail(msg, m.currentAssertLineNumber) @@ -1258,13 +1258,13 @@ namespace rooibos if m.currentResult.isFail return false end if - if rooibos.Common.isFunction(func) + if rooibos.common.isFunction(func) func = func.toStr().mid(10).replace("_", ".") end if try - if not Rooibos.Common.isAssociativeArray(value) + if not rooibos.common.isAssociativeArray(value) if msg = "" - expr_as_string = Rooibos.Common.asString(value) + expr_as_string = rooibos.common.asString(value) msg = expr_as_string + " was not an aa, so could not match Class " + func end if m.currentResult.fail(msg, m.currentAssertLineNumber) @@ -1316,7 +1316,7 @@ namespace rooibos childCount = node.getChildCount() end if if childCount <> count - msg = "node items count <> " + Rooibos.Common.asString(count) + ". Received " + Rooibos.Common.asString(childCount) + msg = "node items count <> " + rooibos.common.asString(count) + ". Received " + rooibos.common.asString(childCount) m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -1358,7 +1358,7 @@ namespace rooibos childCount = node.getChildCount() end if if childCount = count - msg = "node items count = " + Rooibos.Common.asString(count) + "." + msg = "node items count = " + rooibos.common.asString(count) + "." m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -1460,8 +1460,8 @@ namespace rooibos end if try if type(node) = "roSGNode" - if not Rooibos.Common.nodeContains(node, value) - msg = "Node doesn't have the '" + Rooibos.Common.asString(value, true) + "' value." + if not rooibos.common.nodeContains(node, value) + msg = "Node doesn't have the '" + rooibos.common.asString(value, true) + "' value." m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -1496,8 +1496,8 @@ namespace rooibos end if try if type(node) = "roSGNode" - if not Rooibos.Common.nodeContains(node, value) - msg = "Node doesn't have the '" + Rooibos.Common.asString(value, true) + "' value." + if not rooibos.common.nodeContains(node, value) + msg = "Node doesn't have the '" + rooibos.common.asString(value, true) + "' value." m.currentResult.fail(msg, m.currentAssertLineNumber) return false else @@ -1544,8 +1544,8 @@ namespace rooibos end if try if type(node) = "roSGNode" - if Rooibos.Common.nodeContains(node, value) - msg = "Node has the '" + Rooibos.Common.asString(value, true) + "' value." + if rooibos.common.nodeContains(node, value) + msg = "Node has the '" + rooibos.common.asString(value, true) + "' value." m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -1579,15 +1579,15 @@ namespace rooibos return false end if try - if (type(node) = "roSGNode" and Rooibos.Common.isAssociativeArray(subset)) or (type(node) = "roSGNode" and Rooibos.Common.isArray(subset)) - isIgnoredFields = Rooibos.Common.isArray(ignoredFields) + if (type(node) = "roSGNode" and rooibos.common.isAssociativeArray(subset)) or (type(node) = "roSGNode" and rooibos.common.isArray(subset)) + isIgnoredFields = rooibos.common.isArray(ignoredFields) for each key in subset if key <> "" - if not isIgnoredFields or not Rooibos.Common.arrayContains(ignoredFields, key) + if not isIgnoredFields or not rooibos.common.arrayContains(ignoredFields, key) subsetValue = subset[key] nodeValue = node[key] - if not Rooibos.Common.eqValues(nodeValue, subsetValue) - msg = key + ": Expected '" + Rooibos.Common.asString(subsetValue, true) + "', got '" + Rooibos.Common.asString(nodeValue, true) + "'" + if not rooibos.common.eqValues(nodeValue, subsetValue) + msg = key + ": Expected '" + rooibos.common.asString(subsetValue, true) + "', got '" + rooibos.common.asString(nodeValue, true) + "'" m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -1626,8 +1626,8 @@ namespace rooibos return false end if try - if (type(node) = "roSGNode" and Rooibos.Common.isAssociativeArray(subset)) or (type(node) = "roSGNode" and Rooibos.Common.isArray(subset)) - isAA = Rooibos.Common.isAssociativeArray(subset) + if (type(node) = "roSGNode" and rooibos.common.isAssociativeArray(subset)) or (type(node) = "roSGNode" and rooibos.common.isArray(subset)) + isAA = rooibos.common.isAssociativeArray(subset) for each item in subset key = invalid value = item @@ -1635,8 +1635,8 @@ namespace rooibos key = item value = item[key] end if - if Rooibos.Common.nodeContains(node, value) - msg = "Node has the '" + Rooibos.Common.asString(value, true) + "' value." + if rooibos.common.nodeContains(node, value) + msg = "Node has the '" + rooibos.common.asString(value, true) + "' value." m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -1676,15 +1676,15 @@ namespace rooibos return false end if try - if Rooibos.Common.isAssociativeArray(array) and Rooibos.Common.isAssociativeArray(subset) - isIgnoredFields = Rooibos.Common.isArray(ignoredFields) + if rooibos.common.isAssociativeArray(array) and rooibos.common.isAssociativeArray(subset) + isIgnoredFields = rooibos.common.isArray(ignoredFields) for each key in subset if key <> "" - if not isIgnoredFields or not Rooibos.Common.arrayContains(ignoredFields, key) + if not isIgnoredFields or not rooibos.common.arrayContains(ignoredFields, key) subsetValue = subset[key] arrayValue = array[key] - if not Rooibos.Common.eqValues(arrayValue, subsetValue) - msg = key + ": Expected '" + Rooibos.Common.asString(subsetValue, true) + "', got '" + Rooibos.Common.asString(arrayValue, true) + "'" + if not rooibos.common.eqValues(arrayValue, subsetValue) + msg = key + ": Expected '" + rooibos.common.asString(subsetValue, true) + "', got '" + rooibos.common.asString(arrayValue, true) + "'" m.currentResult.fail(msg, m.currentAssertLineNumber) return false end if @@ -1725,7 +1725,10 @@ namespace rooibos ' * @returns {Object} - stub that was wired into the real method ' */ function stub(target, methodName, returnValue = invalid, allowNonExistingMethods = false) as object - if type(target) <> "roAssociativeArray" + if target = invalid and not rooibos.common.isFunction(methodName) + m.fail("could not create Stub. Global function", methodName, ", is invalid") + return {} + else if type(target) <> "roAssociativeArray" m.fail("could not create Stub provided target was null") return {} end if @@ -1780,7 +1783,7 @@ namespace rooibos function _expectCalled(target, methodName, rootObject = invalid as dynamic, fullPath = invalid as dynamic, expectedArgs = invalid, returnValue = invalid as dynamic) as object try if type(target) <> "roAssociativeArray" and fullPath <> invalid - target = rooibos.Common.makePathStubbable(rootObject, fullPath) + target = rooibos.common.makePathStubbable(rootObject, fullPath) end if return m.mock(target, methodName, 1, expectedArgs, returnValue, true) catch error @@ -1798,7 +1801,7 @@ namespace rooibos function _stubCall(target, methodName, rootObject = invalid as dynamic, fullPath = invalid as dynamic, returnValue = invalid as dynamic) as object try if type(target) <> "roAssociativeArray" and fullPath <> invalid - target = rooibos.Common.makePathStubbable(rootObject, fullPath) + target = rooibos.common.makePathStubbable(rootObject, fullPath) end if return m.stub(target, methodName, returnValue, true) catch error @@ -1817,7 +1820,7 @@ namespace rooibos function _expectNotCalled(target, methodName, rootObject = invalid as dynamic, fullPath = invalid as dynamic) as object try if type(target) <> "roAssociativeArray" and fullPath <> invalid - target = rooibos.Common.makePathStubbable(rootObject, fullPath) + target = rooibos.common.makePathStubbable(rootObject, fullPath) end if return m.mock(target, methodName, 0, invalid, invalid, true) catch error @@ -1943,19 +1946,20 @@ namespace rooibos function mock(target, methodName, expectedInvocations = 1, expectedArgs = invalid, returnValue = invalid, allowNonExistingMethods = false) as object lineNumber = m.currentAssertLineNumber 'check params - if not Rooibos.Common.isAssociativeArray(target) + + if target <> invalid and not rooibos.common.isFunction(target) and not rooibos.common.isAssociativeArray(target) methodName = "" - m.mockFail(lineNumber, "", "mock args: target was not an AA") - else if not Rooibos.Common.isString(methodName) + m.mockFail(lineNumber, "", "mock args: target should be an AA or in-scope Global function", methodName) + else if not rooibos.common.isString(methodName) methodName = "" m.mockFail(lineNumber, "", "mock args: methodName was not a string") - else if not Rooibos.Common.isNumber(expectedInvocations) + else if not rooibos.common.isNumber(expectedInvocations) m.mockFail(lineNumber, methodName, "mock args: expectedInvocations was not an int") - else if not Rooibos.Common.isArray(expectedArgs) and Rooibos.Common.isValid(expectedArgs) + else if not rooibos.common.isArray(expectedArgs) and rooibos.common.isValid(expectedArgs) m.mockFail(lineNumber, methodName, "mock args: expectedArgs was not invalid or an array of args") - else if Rooibos.Common.isUndefined(expectedArgs) + else if rooibos.common.isUndefined(expectedArgs) m.mockFail(lineNumber, methodName, "mock args: expectedArgs undefined") - else if Rooibos.Common.isUndefined(returnValue) + else if rooibos.common.isUndefined(returnValue) m.mockFail(lineNumber, methodName, "mock args: returnValue undefined") end if @@ -1968,9 +1972,15 @@ namespace rooibos m.__mockId = -1 m.__mockTargetId = -1 m.mocks = {} + rooibos.resetMocksByFunctionName() end if fake = invalid + if rooibos.common.isFunction(target) + target = { + isGlobalCall: true + } + end if if not target.doesExist("__rooibosTargetId") m.__mockTargetId++ target["__rooibosTargetId"] = m.__mockTargetId @@ -1979,7 +1989,7 @@ namespace rooibos for i = 0 to m.__mockId id = stri(i).trim() mock = m.mocks[id] - if mock <> invalid and mock.methodName = methodName and mock.target.__rooibosTargetId = target.__rooibosTargetId + if mock <> invalid and mock.methodName = methodName and (mock.target.__rooibosTargetId = target.__rooibosTargetId or (mock.target.isGlobalCall and target.isGlobalCall)) fake = mock fake.lineNumbers.push(lineNumber) exit for @@ -1996,21 +2006,26 @@ namespace rooibos fake = m.createFake(id, target, methodName, expectedInvocations, expectedArgs, returnValue) m.mocks[id] = fake 'this will bind it to m - allowNonExisting = m.allowNonExistingMethodsOnMocks = true or allowNonExistingMethods - isMethodPresent = type(target[methodName]) = "Function" or type(target[methodName]) = "roFunction" - if isMethodPresent or allowNonExisting - target[methodName] = m["MockCallback" + id] - target.__mocks = m.mocks - - if not isMethodPresent - ' ? "WARNING - mocking call " ; methodName; " which did not exist on target object" - end if + if target.isGlobalCall + rooibos.getMocksByFunctionName()[methodName] = fake else - ? "ERROR - could not create Mock : method not found "; target ; "." ; methodName + allowNonExisting = m.allowNonExistingMethodsOnMocks = true or allowNonExistingMethods + isMethodPresent = type(target[methodName]) = "Function" or type(target[methodName]) = "roFunction" + if isMethodPresent or allowNonExisting + target[methodName] = m["MockCallback" + id] + target.__mocks = m.mocks + + if not isMethodPresent + ' ? "WARNING - mocking call " ; methodName; " which did not exist on target object" + end if + else + ? "ERROR - could not create Mock : method not found "; target ; "." ; methodName + end if end if else m.combineFakes(fake, m.createFake(id, target, methodName, expectedInvocations, expectedArgs, returnValue)) end if + return fake end function @@ -2030,22 +2045,23 @@ namespace rooibos function createFake(id, target, methodName, expectedInvocations = 1, expectedArgs = invalid, returnValue = invalid) as object expectedArgsValues = [] lineNumber = m.currentAssertLineNumber - hasArgs = Rooibos.Common.isArray(expectedArgs) + hasArgs = rooibos.common.isArray(expectedArgs) defaultValue = m.ignoreValue if hasArgs defaultValue = m.invalidValue else expectedArgs = [] end if + lineNumbers = [lineNumber] for i = 0 to 9 if hasArgs and expectedArgs.count() > i 'guard against bad values value = expectedArgs[i] - if not Rooibos.Common.isUndefined(value) - if Rooibos.Common.isAssociativeArray(value) and Rooibos.Common.isValid(value.matcher) - if not Rooibos.Common.isFunction(value.matcher) + if not rooibos.common.isUndefined(value) + if rooibos.common.isAssociativeArray(value) and rooibos.common.isValid(value.matcher) + if not rooibos.common.isFunction(value.matcher) ? "[ERROR] you have specified a matching function; but it is not in scope!" expectedArgsValues.push("#ERR-OUT_OF_SCOPE_MATCHER!") else @@ -2158,7 +2174,7 @@ namespace rooibos ' * @description Will check all mocks that have been created to ensure they were invoked the expected amount of times, with the expected args. ' */ function assertMocks() as void - if m.__mockId = invalid or not Rooibos.Common.isAssociativeArray(m.mocks) + if m.__mockId = invalid or not rooibos.common.isAssociativeArray(m.mocks) return end if @@ -2169,8 +2185,8 @@ namespace rooibos m.mockFail(mock.lineNumbers[0], methodName, "Wrong number of calls. (" + stri(mock.invocations).trim() + " / " + stri(mock.expectedInvocations).trim() + ")") m.cleanMocks() return - else if mock.expectedInvocations > 0 and (Rooibos.Common.isArray(mock.expectedArgs) or (type(mock.expectedArgs) = "roAssociativeArray" and Rooibos.Common.isArray(mock.expectedArgs.multiInvoke))) - isMultiArgsSupported = type(mock.expectedArgs) = "roAssociativeArray" and Rooibos.Common.isArray(mock.expectedArgs.multiInvoke) + else if mock.expectedInvocations > 0 and (rooibos.common.isArray(mock.expectedArgs) or (type(mock.expectedArgs) = "roAssociativeArray" and rooibos.common.isArray(mock.expectedArgs.multiInvoke))) + isMultiArgsSupported = type(mock.expectedArgs) = "roAssociativeArray" and rooibos.common.isArray(mock.expectedArgs.multiInvoke) for invocationIndex = 0 to mock.invocations - 1 invokedArgs = mock.allInvokedArgs[invocationIndex] @@ -2182,25 +2198,25 @@ namespace rooibos for i = 0 to expectedArgs.count() - 1 value = invokedArgs[i] expected = expectedArgs[i] - didNotExpectArg = Rooibos.Common.isString(expected) and expected = m.invalidValue + didNotExpectArg = rooibos.common.isString(expected) and expected = m.invalidValue if didNotExpectArg expected = invalid end if - isUsingMatcher = Rooibos.Common.isAssociativeArray(expected) and Rooibos.Common.isFunction(expected.matcher) + isUsingMatcher = rooibos.common.isAssociativeArray(expected) and rooibos.common.isFunction(expected.matcher) if isUsingMatcher if not expected.matcher(value) - m.mockFail(mock.lineNumbers[invocationIndex], methodName, "on Invocation #" + stri(invocationIndex).trim() + ", expected arg #" + stri(i).trim() + " to match matching function '" + Rooibos.Common.asString(expected.matcher) + "' got '" + Rooibos.Common.asString(value, true) + "')") + m.mockFail(mock.lineNumbers[invocationIndex], methodName, "on Invocation #" + stri(invocationIndex).trim() + ", expected arg #" + stri(i).trim() + " to match matching function '" + rooibos.common.asString(expected.matcher) + "' got '" + rooibos.common.asString(value, true) + "')") m.cleanMocks() end if else - if not (Rooibos.Common.isString(expected) and expected = m.ignoreValue) and not Rooibos.Common.eqValues(value, expected) + if not (rooibos.common.isString(expected) and expected = m.ignoreValue) and not rooibos.common.eqValues(value, expected) if expected = invalid expected = "[INVALID]" end if - m.mockFail(mock.lineNumbers[invocationIndex], methodName, "on Invocation #" + stri(invocationIndex).trim() + ", expected arg #" + stri(i).trim() + " to be '" + Rooibos.Common.asString(expected, true) + "' got '" + Rooibos.Common.asString(value, true) + "')") + m.mockFail(mock.lineNumbers[invocationIndex], methodName, "on Invocation #" + stri(invocationIndex).trim() + ", expected arg #" + stri(i).trim() + " to be '" + rooibos.common.asString(expected, true) + "' got '" + rooibos.common.asString(value, true) + "')") m.cleanMocks() return end if @@ -2229,6 +2245,7 @@ namespace rooibos mock.target.__mocks = invalid end for m.mocks = invalid + rooibos.resetMocksByFunctionName() end function ' /** @@ -2247,6 +2264,7 @@ namespace rooibos stub.target.__stubs = invalid end for m.stubs = invalid + rooibos.resetMocksByFunctionName() end function @@ -2699,4 +2717,23 @@ namespace rooibos ' ? "++++++++ TEST TIMED OUT" m.testRunner.currentTestSuite.failBecauseOfTimeOut() end function + + function getMocksByFunctionName() + if m._rMocksByFunctionName = invalid + m._rMocksByFunctionName = {} + end if + return m._rMocksByFunctionName + end function + + function resetMocksByFunctionName() + m._rMocksByFunctionName = invalid + end function + + function getMockForFunction(functionName as string) + return rooibos.getMocksByFunctionName()[functionName] + end function + + function isFunctionMocked(functionName as string) + return rooibos.getMockForFunction(functionName) <> invalid + end function end namespace \ No newline at end of file diff --git a/framework/src/source/CommonUtils.bs b/framework/src/source/CommonUtils.bs index dd25db8d..9b9a6f51 100755 --- a/framework/src/source/CommonUtils.bs +++ b/framework/src/source/CommonUtils.bs @@ -1,4 +1,4 @@ -namespace rooibos.Common +namespace rooibos.common ' /** ' * @module CommonUtils ' */ @@ -15,7 +15,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value contains XMLElement interface, else return false ' */ function isXmlElement(value) as boolean - return Rooibos.Common.isValid(value) and GetInterface(value, "ifXMLElement") <> invalid + return rooibos.common.isValid(value) and GetInterface(value, "ifXMLElement") <> invalid end function ' /** @@ -27,12 +27,12 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value contains Function interface, else return false ' */ function isFunction(value) as boolean - return Rooibos.Common.isValid(value) and GetInterface(value, "ifFunction") <> invalid + return rooibos.common.isValid(value) and GetInterface(value, "ifFunction") <> invalid end function ' /** - ' * @name Rooibos.Common.getFunction + ' * @name rooibos.common.getFunction ' * @function ' * @description looks up the function by name, for the function map ' * @memberof module:CommonUtils @@ -41,10 +41,10 @@ namespace rooibos.Common ' * @returns {Function} - function pointer or invalid ' */ function getFunction(filename, functionName) as object - if not Rooibos.Common.isNotEmptyString(functionName) + if not rooibos.common.isNotEmptyString(functionName) return invalid end if - if not Rooibos.Common.isNotEmptyString(filename) + if not rooibos.common.isNotEmptyString(filename) return invalid end if 'bs:disable-next-line @@ -68,7 +68,7 @@ namespace rooibos.Common end function ' /** - ' * @name Rooibos.Common.getFunctionBruteforce + ' * @name rooibos.common.getFunctionBruteforce ' * @function ' * @description looks up the function by name, from any function map ' * in future @@ -78,7 +78,7 @@ namespace rooibos.Common ' * @returns {Function} - function pointer or invalid ' */ function getFunctionBruteForce(functionName) as object - if not Rooibos.Common.isNotEmptyString(functionName) + if not rooibos.common.isNotEmptyString(functionName) return invalid end if 'bs:disable-next-line @@ -116,7 +116,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value contains Boolean interface, else return false ' */ function isBoolean(value) as boolean - return Rooibos.Common.isValid(value) and GetInterface(value, "ifBoolean") <> invalid + return rooibos.common.isValid(value) and GetInterface(value, "ifBoolean") <> invalid end function ' /** @@ -128,7 +128,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value type equals Integer, else return false ' */ function isInteger(value) as boolean - return Rooibos.Common.isValid(value) and GetInterface(value, "ifInt") <> invalid and (Type(value) = "roInt" or Type(value) = "roInteger" or Type(value) = "Integer") + return rooibos.common.isValid(value) and GetInterface(value, "ifInt") <> invalid and (Type(value) = "roInt" or Type(value) = "roInteger" or Type(value) = "Integer") end function ' /** @@ -140,7 +140,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value contains Float interface, else return false ' */ function isFloat(value) as boolean - return Rooibos.Common.isValid(value) and GetInterface(value, "ifFloat") <> invalid + return rooibos.common.isValid(value) and GetInterface(value, "ifFloat") <> invalid end function ' /** @@ -152,7 +152,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value contains Double interface, else return false ' */ function isDouble(value) as boolean - return Rooibos.Common.isValid(value) and GetInterface(value, "ifDouble") <> invalid + return rooibos.common.isValid(value) and GetInterface(value, "ifDouble") <> invalid end function ' /** @@ -164,7 +164,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value contains LongInteger interface, else return false ' */ function isLongInteger(value) as boolean - return Rooibos.Common.isValid(value) and GetInterface(value, "ifLongInt") <> invalid + return rooibos.common.isValid(value) and GetInterface(value, "ifLongInt") <> invalid end function ' /** @@ -176,7 +176,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value is number, else return false ' */ function isNumber(value) as boolean - return Rooibos.Common.isLongInteger(value) or Rooibos.Common.isDouble(value) or Rooibos.Common.isInteger(value) or Rooibos.Common.isFloat(value) + return rooibos.common.isLongInteger(value) or rooibos.common.isDouble(value) or rooibos.common.isInteger(value) or rooibos.common.isFloat(value) end function ' /** @@ -188,7 +188,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value contains List interface, else return false ' */ function isList(value) as boolean - return Rooibos.Common.isValid(value) and GetInterface(value, "ifList") <> invalid + return rooibos.common.isValid(value) and GetInterface(value, "ifList") <> invalid end function ' /** @@ -200,7 +200,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value contains Array interface, else return false ' */ function isArray(value) as boolean - return Rooibos.Common.isValid(value) and GetInterface(value, "ifArray") <> invalid + return rooibos.common.isValid(value) and GetInterface(value, "ifArray") <> invalid end function ' /** @@ -212,7 +212,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value contains AssociativeArray interface, else return false ' */ function isAssociativeArray(value) as boolean - return Rooibos.Common.isValid(value) and GetInterface(value, "ifAssociativeArray") <> invalid + return rooibos.common.isValid(value) and GetInterface(value, "ifAssociativeArray") <> invalid end function ' /** @@ -224,7 +224,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value contains SGNodeChildren interface, else return false ' */ function isSGNode(value) as boolean - return Rooibos.Common.isValid(value) and GetInterface(value, "ifSGNodeChildren") <> invalid + return rooibos.common.isValid(value) and GetInterface(value, "ifSGNodeChildren") <> invalid end function ' /** @@ -236,7 +236,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value contains String interface, else return false ' */ function isString(value) as boolean - return Rooibos.Common.isValid(value) and GetInterface(value, "ifString") <> invalid + return rooibos.common.isValid(value) and GetInterface(value, "ifString") <> invalid end function ' /** @@ -248,7 +248,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value contains String interface and length more 0, else return false ' */ function isNotEmptyString(value) as boolean - return Rooibos.Common.isString(value) and len(value) > 0 + return rooibos.common.isString(value) and len(value) > 0 end function ' /** @@ -260,7 +260,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value contains DateTime interface, else return false ' */ function isDateTime(value) as boolean - return Rooibos.Common.isValid(value) and (GetInterface(value, "ifDateTime") <> invalid or Type(value) = "roDateTime") + return rooibos.common.isValid(value) and (GetInterface(value, "ifDateTime") <> invalid or Type(value) = "roDateTime") end function ' /** @@ -272,7 +272,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value initialized and not equal invalid, else return false ' */ function isValid(value) as boolean - return not Rooibos.Common.isUndefined(value) and value <> invalid + return not rooibos.common.isUndefined(value) and value <> invalid end function function isUndefined(value) as boolean @@ -304,23 +304,23 @@ namespace rooibos.Common ' * @returns {String} - converted string ' */ function asString(input, includeType = false) as string - if Rooibos.Common.isValid(input) = false + if rooibos.common.isValid(input) = false return "INVALID" - else if Rooibos.Common.isString(input) + else if rooibos.common.isString(input) if includeType return """" + input + """" else return input end if - else if Rooibos.Common.isInteger(input) or Rooibos.Common.isLongInteger(input) or Rooibos.Common.isBoolean(input) + else if rooibos.common.isInteger(input) or rooibos.common.isLongInteger(input) or rooibos.common.isBoolean(input) if includeType - return input.ToStr() + " (" + Rooibos.Common.getSafeType(input) + ")" + return input.ToStr() + " (" + rooibos.common.getSafeType(input) + ")" else return input.ToStr() end if - else if Rooibos.Common.isFloat(input) or Rooibos.Common.isDouble(input) + else if rooibos.common.isFloat(input) or rooibos.common.isDouble(input) if includeType - return Str(input).Trim() + " (" + Rooibos.Common.getSafeType(input) + ")" + return Str(input).Trim() + " (" + rooibos.common.getSafeType(input) + ")" else return Str(input).Trim() end if @@ -335,19 +335,19 @@ namespace rooibos.Common isFirst = false end if for each key in input - if rooibos.Common.canSafelyIterateAAKey(input, key) - text = text + key + ":" + Rooibos.Common.asString(input[key], includeType) + if rooibos.common.canSafelyIterateAAKey(input, key) + text = text + key + ":" + rooibos.common.asString(input[key], includeType) end if end for text = text + "}" return text - else if Rooibos.Common.isArray(input) + else if rooibos.common.isArray(input) text = "[" join = "" maxLen = 500 for each v in input if len(text) < maxLen - text += join + rooibos.Common.asString(v, includeType) + text += join + rooibos.common.asString(v, includeType) join = ", " end if end for @@ -356,7 +356,7 @@ namespace rooibos.Common end if text = text + "]" return text - else if Rooibos.Common.isFunction(input) + else if rooibos.common.isFunction(input) return input.toStr() + "(function)" else return "" @@ -372,13 +372,13 @@ namespace rooibos.Common ' * @returns {Integer} - converted Integer ' */ function asInteger(input) as integer - if Rooibos.Common.isValid(input) = false + if rooibos.common.isValid(input) = false return 0 - else if Rooibos.Common.isString(input) + else if rooibos.common.isString(input) return input.ToInt() - else if Rooibos.Common.isInteger(input) + else if rooibos.common.isInteger(input) return input - else if Rooibos.Common.isFloat(input) or Rooibos.Common.isDouble(input) or Rooibos.Common.isLongInteger(input) + else if rooibos.common.isFloat(input) or rooibos.common.isDouble(input) or rooibos.common.isLongInteger(input) return Int(input) else return 0 @@ -394,11 +394,11 @@ namespace rooibos.Common ' * @returns {Integer} - converted LongInteger ' */ function asLongInteger(input) as longinteger - if Rooibos.Common.isValid(input) = false + if rooibos.common.isValid(input) = false return 0 - else if Rooibos.Common.isString(input) - return Rooibos.Common.asInteger(input) - else if Rooibos.Common.isLongInteger(input) or Rooibos.Common.isFloat(input) or Rooibos.Common.isDouble(input) or Rooibos.Common.isInteger(input) + else if rooibos.common.isString(input) + return rooibos.common.asInteger(input) + else if rooibos.common.isLongInteger(input) or rooibos.common.isFloat(input) or rooibos.common.isDouble(input) or rooibos.common.isInteger(input) return input else return 0 @@ -414,13 +414,13 @@ namespace rooibos.Common ' * @returns {Float} - converted Float ' */ function asFloat(input) as float - if Rooibos.Common.isValid(input) = false + if rooibos.common.isValid(input) = false return 0.0 - else if Rooibos.Common.isString(input) + else if rooibos.common.isString(input) return input.ToFloat() - else if Rooibos.Common.isInteger(input) + else if rooibos.common.isInteger(input) return (input / 1) - else if Rooibos.Common.isFloat(input) or Rooibos.Common.isDouble(input) or Rooibos.Common.isLongInteger(input) + else if rooibos.common.isFloat(input) or rooibos.common.isDouble(input) or rooibos.common.isLongInteger(input) return input else return 0.0 @@ -436,11 +436,11 @@ namespace rooibos.Common ' * @returns {Float} - converted Double ' */ function asDouble(input) as double - if Rooibos.Common.isValid(input) = false + if rooibos.common.isValid(input) = false return 0.0 - else if Rooibos.Common.isString(input) - return Rooibos.Common.asFloat(input) - else if Rooibos.Common.isInteger(input) or Rooibos.Common.isLongInteger(input) or Rooibos.Common.isFloat(input) or Rooibos.Common.isDouble(input) + else if rooibos.common.isString(input) + return rooibos.common.asFloat(input) + else if rooibos.common.isInteger(input) or rooibos.common.isLongInteger(input) or rooibos.common.isFloat(input) or rooibos.common.isDouble(input) return input else return 0.0 @@ -456,13 +456,13 @@ namespace rooibos.Common ' * @returns {Boolean} - converted boolean ' */ function asBoolean(input) as boolean - if Rooibos.Common.isValid(input) = false + if rooibos.common.isValid(input) = false return false - else if Rooibos.Common.isString(input) + else if rooibos.common.isString(input) return LCase(input) = "true" - else if Rooibos.Common.isInteger(input) or Rooibos.Common.isFloat(input) + else if rooibos.common.isInteger(input) or rooibos.common.isFloat(input) return input <> 0 - else if Rooibos.Common.isBoolean(input) + else if rooibos.common.isBoolean(input) return input else return false @@ -478,8 +478,8 @@ namespace rooibos.Common ' * @returns {Array} - converted array ' */ function asArray(value) as object - if Rooibos.Common.isValid(value) - if not Rooibos.Common.isArray(value) + if rooibos.common.isValid(value) + if not rooibos.common.isArray(value) return [value] else return value @@ -501,10 +501,10 @@ namespace rooibos.Common ' * @returns {Boolean} - true if value is null or empty string, else return false ' */ function isNullOrEmpty(value) as boolean - if Rooibos.Common.isString(value) + if rooibos.common.isString(value) return Len(value) = 0 else - return not Rooibos.Common.isValid(value) + return not rooibos.common.isValid(value) end if end function @@ -524,19 +524,19 @@ namespace rooibos.Common ' * @returns {Integer} - element index if array contains a value, else return -1 ' */ function findElementIndexInArray(array, value, compareAttribute = invalid, caseSensitive = false, callCount = 0) as integer - if callCount = 0 and not Rooibos.Common.isArray(array) - array = Rooibos.Common.asArray(array) + if callCount = 0 and not rooibos.common.isArray(array) + array = rooibos.common.asArray(array) end if - if Rooibos.Common.isArray(array) - for i = 0 to Rooibos.Common.asArray(array).Count() - 1 + if rooibos.common.isArray(array) + for i = 0 to rooibos.common.asArray(array).Count() - 1 compareValue = array[i] - if compareAttribute <> invalid and Rooibos.Common.isAssociativeArray(compareValue) + if compareAttribute <> invalid and rooibos.common.isAssociativeArray(compareValue) compareValue = compareValue.lookupCI(compareAttribute) end if - if Rooibos.Common.eqValues(compareValue, value, callCount + 1) + if rooibos.common.eqValues(compareValue, value, callCount + 1) return i end if next @@ -555,7 +555,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if array contains a value, else return false ' */ function arrayContains(array, value, compareAttribute = invalid) as boolean - return (Rooibos.Common.findElementIndexInArray(array, value, compareAttribute) > -1) + return (rooibos.common.findElementIndexInArray(array, value, compareAttribute) > -1) end function @@ -602,7 +602,7 @@ namespace rooibos.Common ' * @returns {Boolean} - true if node contains a value, else return false ' */ function nodeContains(node, value) as boolean - return (Rooibos.Common.findElementIndexInNode(node, value) > -1) + return (rooibos.common.findElementIndexInNode(node, value) > -1) end function @@ -649,8 +649,8 @@ namespace rooibos.Common end if ' Workaraund for bug with string boxing, and box everything else - val1Type = Rooibos.Common.getSafeType(Value1) - val2Type = Rooibos.Common.getSafeType(Value2) + val1Type = rooibos.common.getSafeType(Value1) + val2Type = rooibos.common.getSafeType(Value2) if val1Type = invalid or val2Type = invalid ? "ERROR!!!! - undefined value passed" return false @@ -669,11 +669,11 @@ namespace rooibos.Common valtype = val1Type if val1Type = "List" - return Rooibos.Common.eqArray(Value1, Value2, fuzzy, callCount + 1) + return rooibos.common.eqArray(Value1, Value2, fuzzy, callCount + 1) else if valtype = "roAssociativeArray" - return Rooibos.Common.eqAssocArray(Value1, Value2, fuzzy, callCount + 1) + return rooibos.common.eqAssocArray(Value1, Value2, fuzzy, callCount + 1) else if valtype = "roArray" - return Rooibos.Common.eqArray(Value1, Value2, fuzzy, callCount + 1) + return rooibos.common.eqArray(Value1, Value2, fuzzy, callCount + 1) else if valtype = "roSGNode" if val2Type <> "roSGNode" return false @@ -682,7 +682,7 @@ namespace rooibos.Common end if else if fuzzy = true - return Rooibos.Common.asString(Value1) = Rooibos.Common.asString(Value2) + return rooibos.common.asString(Value1) = rooibos.common.asString(Value2) else 'If you crashed on this line, then you're trying to compare '2 things which can't be compared - check what value1 and value2 @@ -694,8 +694,8 @@ namespace rooibos.Common end function function eqTypes(Value1, Value2) as dynamic - val1Type = Rooibos.Common.getSafeType(Value1) - val2Type = Rooibos.Common.getSafeType(Value2) + val1Type = rooibos.common.getSafeType(Value1) + val2Type = rooibos.common.getSafeType(Value2) if val1Type = invalid or val2Type = invalid ? "ERROR!!!! - undefined value passed" return false @@ -736,7 +736,7 @@ namespace rooibos.Common if rooibos.common.canSafelyIterateAAKey(Value1, k) and rooibos.common.canSafelyIterateAAKey(Value2, k) v1 = Value1[k] v2 = Value2[k] - if not Rooibos.Common.eqValues(v1, v2, fuzzy, callCount + 1) + if not rooibos.common.eqValues(v1, v2, fuzzy, callCount + 1) return false end if end if @@ -771,7 +771,7 @@ namespace rooibos.Common ? "REACHED MAX ITERATIONS DOING COMPARISON" return true end if - if not (Rooibos.Common.isArray(Value1)) or not Rooibos.Common.isArray(Value2) + if not (rooibos.common.isArray(Value1)) or not rooibos.common.isArray(Value2) return false end if @@ -784,7 +784,7 @@ namespace rooibos.Common for i = 0 to l1 - 1 v1 = Value1[i] v2 = Value2[i] - if not Rooibos.Common.eqValues(v1, v2, fuzzy, callCount + 1) + if not rooibos.common.eqValues(v1, v2, fuzzy, callCount + 1) return false end if end for @@ -838,14 +838,14 @@ namespace rooibos.Common end if nextPart = invalid - if rooibos.Common.isArray(part) and isIndexNumber + if rooibos.common.isArray(part) and isIndexNumber nextPart = part[index] else if type(part) = "roAssociativeArray" and not isIndexNumber nextPart = part[index] end if if nextPart = invalid or type(nextPart) <> "roAssociativeArray" - if (not isIndexNumber and type(part) = "roAssociativeArray") or (isIndexNumber and (rooibos.Common.isArray(part))) + if (not isIndexNumber and type(part) = "roAssociativeArray") or (isIndexNumber and (rooibos.common.isArray(part))) nextPart = { id: index } part[index] = nextPart else diff --git a/framework/src/source/ConsoleTestReporter.bs b/framework/src/source/ConsoleTestReporter.bs index 285d48de..d0e609f4 100644 --- a/framework/src/source/ConsoleTestReporter.bs +++ b/framework/src/source/ConsoleTestReporter.bs @@ -30,13 +30,13 @@ namespace rooibos 'bs:disable-next-line ignoredInfo = m.testRunner.runtimeConfig.getIgnoredTestInfo() - m.printLine(0, "Total: " + Rooibos.Common.AsString(m.allStats.ranCount)) - m.printLine(0, " Passed: " + Rooibos.Common.AsString(m.allStats.passedCount)) - m.printLine(0, " Crashed: " + Rooibos.Common.AsString(m.allStats.crashedCount)) - m.printLine(0, " Failed: " + Rooibos.Common.AsString(m.allStats.failedCount)) + m.printLine(0, "Total: " + rooibos.common.AsString(m.allStats.ranCount)) + m.printLine(0, " Passed: " + rooibos.common.AsString(m.allStats.passedCount)) + m.printLine(0, " Crashed: " + rooibos.common.AsString(m.allStats.crashedCount)) + m.printLine(0, " Failed: " + rooibos.common.AsString(m.allStats.failedCount)) 'bs:disable-next-line - m.printLine(0, " Ignored: " + Rooibos.Common.AsString(ignoredInfo.count)) - m.printLine(0, " Time: " + Rooibos.Common.AsString(m.allStats.time) + "ms") + m.printLine(0, " Ignored: " + rooibos.common.AsString(ignoredInfo.count)) + m.printLine(0, " Time: " + rooibos.common.AsString(m.allStats.time) + "ms") m.printLine() m.printLine() @@ -103,7 +103,7 @@ namespace rooibos insetText = "" if test.isParamTest <> true - messageLine = Rooibos.Common.fillText(" " + testChar + " |--" + test.name + " : ", ".", m.lineWidth) + messageLine = rooibos.common.fillText(" " + testChar + " |--" + test.name + " : ", ".", m.lineWidth) m.printLine(0, messageLine + test.result.getStatusText() + timeText) m.printLine(0, " | " + insetText + " |--Test : " + testLocationText) else if test.paramTestIndex = 0 @@ -130,7 +130,7 @@ namespace rooibos else rawParams = test.rawParams end if - messageLine = Rooibos.Common.fillText(" " + testChar + insetText + " |--" + formatJson(rawParams) + " : ", ".", m.lineWidth) + messageLine = rooibos.common.fillText(" " + testChar + insetText + " |--" + formatJson(rawParams) + " : ", ".", m.lineWidth) m.printLine(0, messageLine + test.result.getStatusText() + timeText) end if diff --git a/framework/src/source/Matchers.bs b/framework/src/source/Matchers.bs index 193056a5..2445b869 100644 --- a/framework/src/source/Matchers.bs +++ b/framework/src/source/Matchers.bs @@ -1,27 +1,27 @@ namespace rooibos.Matcher function anyString(value) - return Rooibos.Common.isString(value) + return rooibos.common.isString(value) end function function anyBool(value) - return Rooibos.Common.isBoolean(value) + return rooibos.common.isBoolean(value) end function function anyNumber(value) - return Rooibos.Common.isNumber(value) + return rooibos.common.isNumber(value) end function function anyAA(value) - return Rooibos.Common.isAssociativeArray(value) + return rooibos.common.isAssociativeArray(value) end function function anyArray(value) - return Rooibos.Common.isArray(value) + return rooibos.common.isArray(value) end function function anyNode(value) - return Rooibos.Common.isSGNode(value) + return rooibos.common.isSGNode(value) end function diff --git a/framework/src/source/RooibosScene.xml b/framework/src/source/RooibosScene.xml index 0dfd684b..5937a1ff 100644 --- a/framework/src/source/RooibosScene.xml +++ b/framework/src/source/RooibosScene.xml @@ -19,7 +19,7 @@ uri='source/rooibos/Matchers.bs' />