From 6c80fdd7593ff0f9077d61c1fc1b221d604b2131 Mon Sep 17 00:00:00 2001 From: George Cook Date: Sat, 2 Apr 2022 01:18:56 +0200 Subject: [PATCH] Feature/accept expect once with function param (#157) * adds support for function pointers in expectCalled functions * adds expectCalled and expectNotCalled * Fixes for stubbing - still is borked in some way though * Fixes callfunc issues with new expect syntax --- bsc-plugin/src/lib/rooibos/TestGroup.ts | 83 ++- bsc-plugin/src/plugin.spec.ts | 845 ++++++++++++++++++----- framework/src/source/BaseTestSuite.bs | 190 ++++- tests/src/source/Basic.spec.bs | 20 - tests/src/source/Expect.spec.bs | 24 + tests/src/source/NewExpectSyntax.spec.bs | 287 ++++++++ 6 files changed, 1227 insertions(+), 222 deletions(-) create mode 100644 tests/src/source/NewExpectSyntax.spec.bs diff --git a/bsc-plugin/src/lib/rooibos/TestGroup.ts b/bsc-plugin/src/lib/rooibos/TestGroup.ts index a636e553..57361c36 100644 --- a/bsc-plugin/src/lib/rooibos/TestGroup.ts +++ b/bsc-plugin/src/lib/rooibos/TestGroup.ts @@ -1,5 +1,6 @@ -import type { CallExpression } from 'brighterscript'; -import { createVisitor, WalkMode, isDottedGetExpression, isCallExpression } from 'brighterscript'; +import type { CallExpression, DottedGetExpression } from 'brighterscript'; +import { ArrayLiteralExpression, createInvalidLiteral, createStringLiteral, createToken, isDottedGetExpression, TokenKind } from 'brighterscript'; +import * as brighterscript from 'brighterscript'; import { BrsTranspileState } from 'brighterscript/dist/parser/BrsTranspileState'; import { TranspileState } from 'brighterscript/dist/parser/TranspileState'; import { diagnosticErrorProcessingFile } from '../utils/Diagnostics'; @@ -51,23 +52,33 @@ export class TestGroup extends TestBlock { const transpileState = new BrsTranspileState(this.file); try { let func = this.testSuite.classStatement.methods.find((m) => m.name.text.toLowerCase() === testCase.funcName.toLowerCase()); - func.walk(createVisitor({ - ExpressionStatement: (es) => { - let ce = es.expression as CallExpression; - if (isCallExpression(ce) && isDottedGetExpression(ce.callee)) { - let dge = ce.callee; - let assertRegex = /(?:fail|assert(?:[a-z0-9]*)|expect(?:[a-z0-9]*))/i; + func.walk(brighterscript.createVisitor({ + ExpressionStatement: (expressionStatement) => { + let callExpression = expressionStatement.expression as CallExpression; + if (brighterscript.isCallExpression(callExpression) && brighterscript.isDottedGetExpression(callExpression.callee)) { + let dge = callExpression.callee; + let assertRegex = /(?:fail|assert(?:[a-z0-9]*)|expect(?:[a-z0-9]*)|stubCall)/i; if (dge && assertRegex.test(dge.name.text)) { - return new RawCodeStatement(` - m.currentAssertLineNumber = ${ce.range.start.line} - ${ce.transpile(transpileState).join('')} - ${noEarlyExit ? '' : 'if m.currentResult.isFail then return invalid'} - `, this.file, ce.range); + if (dge.name.text === 'stubCall') { + this.modifyModernRooibosExpectCallExpression(callExpression); + return expressionStatement; + + } else { + + if (dge.name.text === 'expectCalled' || dge.name.text === 'expectNotCalled') { + this.modifyModernRooibosExpectCallExpression(callExpression); + } + return new RawCodeStatement(` + m.currentAssertLineNumber = ${callExpression.range.start.line} + ${callExpression.transpile(transpileState).join('')} + ${noEarlyExit ? '' : 'if m.currentResult.isFail then return invalid'} + `, this.file, callExpression.range); + } } } } }), { - walkMode: WalkMode.visitStatementsRecursive + walkMode: brighterscript.WalkMode.visitStatementsRecursive }); } catch (e) { // console.log(e); @@ -75,6 +86,50 @@ export class TestGroup extends TestBlock { } } + private modifyModernRooibosExpectCallExpression(callExpression: CallExpression) { + let isNotCalled = false; + let isStubCall = false; + if (isDottedGetExpression(callExpression.callee)) { + const nameText = callExpression.callee.name.text; + callExpression.callee.name.text = `_${nameText}`; + isNotCalled = nameText === 'expectNotCalled'; + isStubCall = nameText === 'stubCall'; + } + //modify args + let arg0 = callExpression.args[0]; + if (brighterscript.isCallExpression(arg0) && isDottedGetExpression(arg0.callee)) { + let functionName = arg0.callee.name.text; + callExpression.args.shift(); + if (!isNotCalled && !isStubCall) { + const expectedArgs = new ArrayLiteralExpression(arg0.args, createToken(TokenKind.LeftSquareBracket), createToken(TokenKind.RightSquareBracket)); + callExpression.args.unshift(expectedArgs); + } + callExpression.args.unshift(createStringLiteral(functionName)); + callExpression.args.unshift(arg0.callee.obj); + } else if (brighterscript.isDottedGetExpression(arg0)) { + let functionName = arg0.name.text; + arg0 = callExpression.args.shift() as DottedGetExpression; + if (!isNotCalled && !isStubCall) { + callExpression.args.unshift(createInvalidLiteral()); + } + callExpression.args.unshift(createStringLiteral(functionName)); + callExpression.args.unshift((arg0 as DottedGetExpression).obj); + } else if (brighterscript.isCallfuncExpression(arg0)) { + let functionName = arg0.methodName.text; + callExpression.args.shift(); + if (isNotCalled || isStubCall) { + //TODO in future we can improve is notCalled to know which callFunc function it is + // const expectedArgs = new ArrayLiteralExpression([createStringLiteral(functionName)], createToken(TokenKind.LeftSquareBracket), createToken(TokenKind.RightSquareBracket)); + // callExpression.args.unshift(expectedArgs); + } else { + const expectedArgs = new ArrayLiteralExpression([createStringLiteral(functionName), ...arg0.args], createToken(TokenKind.LeftSquareBracket), createToken(TokenKind.RightSquareBracket)); + callExpression.args.unshift(expectedArgs); + } + callExpression.args.unshift(createStringLiteral('callFunc')); + callExpression.args.unshift(arg0.callee); + } + } + public asText(): string { let testCaseText = [...this.testCases.values()].filter((tc) => tc.isIncluded).map((tc) => tc.asText()); diff --git a/bsc-plugin/src/plugin.spec.ts b/bsc-plugin/src/plugin.spec.ts index 6604e50e..2a6e2fd6 100644 --- a/bsc-plugin/src/plugin.spec.ts +++ b/bsc-plugin/src/plugin.spec.ts @@ -49,7 +49,7 @@ describe('RooibosPlugin', () => { describe('basic tests', () => { it('does not find tests with no annotations', () => { - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` class notATest end class `); @@ -58,7 +58,7 @@ describe('RooibosPlugin', () => { expect(plugin.session.sessionInfo.testSuitesToRun).to.be.empty; }); it('finds a basic suite', () => { - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @suite class ATest @describe("groupA") @@ -74,7 +74,7 @@ describe('RooibosPlugin', () => { expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; }); it('finds a suite name, only', () => { - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @only @suite("named") class ATest @@ -94,7 +94,7 @@ describe('RooibosPlugin', () => { expect(suite.isSolo).to.be.true; }); it('ignores a suite', () => { - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @ignore @suite class ATest @@ -111,7 +111,7 @@ describe('RooibosPlugin', () => { expect(plugin.session.sessionInfo.testSuitesToRun).to.be.empty; }); it('ignores a group', () => { - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @suite class ATest @ignore @@ -129,7 +129,7 @@ describe('RooibosPlugin', () => { expect(plugin.session.sessionInfo.testsCount).to.equal(0); }); it('ignores a test', () => { - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @suite class ATest @describe("groupA") @@ -147,7 +147,7 @@ describe('RooibosPlugin', () => { expect(plugin.session.sessionInfo.testsCount).to.equal(0); }); it('multiple groups', () => { - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @suite class ATest @describe("groupA") @@ -175,7 +175,7 @@ describe('RooibosPlugin', () => { expect(suite.getTestGroups()[0].testCases).to.have.length(1); }); it('duplicate test name', () => { - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @suite class ATest @describe("groupA") @@ -201,7 +201,7 @@ describe('RooibosPlugin', () => { expect(plugin.session.sessionInfo.testSuitesToRun).to.be.empty; }); it('empty test group', () => { - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @suite class ATest @describe("groupA") @@ -212,7 +212,7 @@ describe('RooibosPlugin', () => { expect(plugin.session.sessionInfo.testSuitesToRun).to.be.empty; }); it('multiple test group annotations - same name', () => { - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @suite class ATest @describe("groupA") @@ -227,7 +227,7 @@ describe('RooibosPlugin', () => { expect(plugin.session.sessionInfo.testSuitesToRun).to.be.empty; }); it('params test with negative numbers', () => { - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @suite class ATest @describe("groupA") @@ -245,7 +245,7 @@ describe('RooibosPlugin', () => { expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; }); it('updates test name to match name of annotation', () => { - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @suite class ATest @describe("groupA") @@ -262,7 +262,7 @@ describe('RooibosPlugin', () => { expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; }); it('updates test name to match name of annotation - with params', () => { - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @suite class ATest @describe("groupA") @@ -281,7 +281,7 @@ describe('RooibosPlugin', () => { expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; }); it('multiple test group annotations - different name', () => { - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @suite class ATest @describe("groupA") @@ -299,7 +299,7 @@ describe('RooibosPlugin', () => { it('test full transpile', async () => { plugin.afterProgramCreate(program); // program.validate(); - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @suite class ATest extends rooibos.BaseTestSuite @describe("groupA") @@ -397,7 +397,7 @@ end function`)); it('test full transpile with complex params', async () => { plugin.afterProgramCreate(program); // program.validate(); - program.addOrReplaceFile('source/test.spec.bs', ` + program.setFile('source/test.spec.bs', ` @suite class ATest extends rooibos.BaseTestSuite @describe("groupA") @@ -421,10 +421,517 @@ end function`)); Rooibos_init() end function`)); }); - }); - describe('honours tags - simple tests', () => { - let testSource = ` + describe('expectCalled transpilation', () => { + it('correctly transpiles call funcs', async () => { + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + m.expectCalled(m.thing@.getFunction()) + m.expectCalled(m.thing@.getFunction(), "return") + m.expectCalled(m.thing@.getFunction("a", "b")) + m.expectCalled(m.thing@.getFunction("a", "b"), "return") + end function + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + let contents = getTestFunctionContents(); + expect(contents).to.eql(trim(`= function() + + m.currentAssertLineNumber = 6 + m._expectCalled(m.thing, "callFunc", [ + "getFunction" + ]) + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 7 + m._expectCalled(m.thing, "callFunc", [ + "getFunction" + ], "return") + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 8 + m._expectCalled(m.thing, "callFunc", [ + "getFunction", + "a", + "b" + ]) + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 9 + m._expectCalled(m.thing, "callFunc", [ + "getFunction", + "a", + "b" + ], "return") + if m.currentResult.isFail then return invalid + + `)); + + }); + it('correctly transpiles func pointers', async () => { + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + m.expectCalled(m.thing.getFunctionField) + m.expectCalled(m.thing.getFunctionField, "return") + end function + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + let contents = getTestFunctionContents(); + expect(contents).to.eql(trim(`= function() + + m.currentAssertLineNumber = 6 + m._expectCalled(m.thing, "getFunctionField", invalid) + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 7 + m._expectCalled(m.thing, "getFunctionField", invalid, "return") + if m.currentResult.isFail then return invalid + + `)); + + }); + it('correctly transpiles function invocations', async () => { + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + m.expectCalled(m.thing.getFunction()) + m.expectCalled(m.thing.getFunction(), "return") + m.expectCalled(m.thing.getFunction("arg1", "arg2")) + m.expectCalled(m.thing.getFunction("arg1", "arg2"), "return") + end function + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + let contents = getTestFunctionContents(); + expect(contents).to.eql(trim(`= function() + + m.currentAssertLineNumber = 6 + m._expectCalled(m.thing, "getFunction", []) + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 7 + m._expectCalled(m.thing, "getFunction", [], "return") + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 8 + m._expectCalled(m.thing, "getFunction", [ + "arg1", + "arg2" + ]) + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 9 + m._expectCalled(m.thing, "getFunction", [ + "arg1", + "arg2" + ], "return") + if m.currentResult.isFail then return invalid + + `)); + }); + + it('correctly transpiles function invocations - simple object', async () => { + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + item = {id: "item"} + m.expectCalled(item.getFunction()) + m.expectCalled(item.getFunction(), "return") + m.expectCalled(item.getFunction("arg1", "arg2")) + m.expectCalled(item.getFunction("arg1", "arg2"), "return") + end function + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + let contents = getTestFunctionContents(); + expect(contents).to.eql(trim(`= function() + item = { + id: "item" + } + + m.currentAssertLineNumber = 7 + m._expectCalled(item, "getFunction", []) + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 8 + m._expectCalled(item, "getFunction", [], "return") + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 9 + m._expectCalled(item, "getFunction", [ + "arg1", + "arg2" + ]) + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 10 + m._expectCalled(item, "getFunction", [ + "arg1", + "arg2" + ], "return") + if m.currentResult.isFail then return invalid + + `)); + }); + }); + + + describe('stubCall transpilation', () => { + it('correctly transpiles call funcs', async () => { + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + m.stubCall(m.thing@.getFunction()) + m.stubCall(m.thing@.getFunction(), "return") + m.stubCall(m.thing@.getFunction("a", "b")) + m.stubCall(m.thing@.getFunction("a", "b"), "return") + end function + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + let contents = getTestFunctionContents(); + expect(contents).to.eql(trim(`= function() + m._stubCall(m.thing, "callFunc") + m._stubCall(m.thing, "callFunc", "return") + m._stubCall(m.thing, "callFunc") + m._stubCall(m.thing, "callFunc", "return") + `)); + + }); + it('correctly transpiles func pointers', async () => { + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + m.stubCall(m.thing.getFunctionField) + m.stubCall(m.thing.getFunctionField, "return") + end function + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + let contents = getTestFunctionContents(); + expect(contents).to.eql(trim(`= function() + m._stubCall(m.thing, "getFunctionField") + m._stubCall(m.thing, "getFunctionField", "return") + `)); + + }); + it('correctly transpiles func pointers - simple', async () => { + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + item = {id:"item"} + m.stubCall(item.getFunctionField) + m.stubCall(item.getFunctionField, "return") + end function + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + let contents = getTestFunctionContents(); + expect(contents).to.eql(trim(`= function() + item = { + id: "item" + } + m._stubCall(item, "getFunctionField") + m._stubCall(item, "getFunctionField", "return") + `)); + + }); + it('correctly transpiles function invocations', async () => { + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + m.stubCall(m.thing.getFunction()) + m.stubCall(m.thing.getFunction(), "return") + m.stubCall(m.thing.getFunction("arg1", "arg2")) + m.stubCall(m.thing.getFunction("arg1", "arg2"), "return") + end function + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + let contents = getTestFunctionContents(); + expect(contents).to.eql(trim(`= function() + m._stubCall(m.thing, "getFunction") + m._stubCall(m.thing, "getFunction", "return") + m._stubCall(m.thing, "getFunction") + m._stubCall(m.thing, "getFunction", "return") + `)); + }); + + it('correctly transpiles function invocations - simple object', async () => { + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + item = {id: "item"} + m.stubCall(item.getFunction()) + m.stubCall(item.getFunction(), "return") + m.stubCall(item.getFunction("arg1", "arg2")) + m.stubCall(item.getFunction("arg1", "arg2"), "return") + end function + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + let contents = getTestFunctionContents(); + expect(contents).to.eql(trim(`= function() + item = { + id: "item" + } + m._stubCall(item, "getFunction") + m._stubCall(item, "getFunction", "return") + m._stubCall(item, "getFunction") + m._stubCall(item, "getFunction", "return") + `)); + }); + }); + + describe('expectNotCalled transpilation', () => { + + it('correctly transpiles call funcs', async () => { + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + m.expectNotCalled(m.thing@.getFunction()) + m.expectNotCalled(m.thing@.getFunction(), "return") + m.expectNotCalled(m.thing@.getFunction()) + m.expectNotCalled(m.thing@.getFunction(), "return") + end function + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + let contents = getTestFunctionContents(); + expect(contents).to.eql(trim(`= function() + + m.currentAssertLineNumber = 6 + m._expectNotCalled(m.thing, "callFunc") + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 7 + m._expectNotCalled(m.thing, "callFunc", "return") + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 8 + m._expectNotCalled(m.thing, "callFunc") + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 9 + m._expectNotCalled(m.thing, "callFunc", "return") + if m.currentResult.isFail then return invalid + + `)); + + }); + it.only('correctly transpiles call funcs on simple objects', async () => { + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + m.expectNotCalled(thing@.getFunction()) + m.expectNotCalled(thing@.getFunction("arg1", "arg2")) + end function + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + let contents = getTestFunctionContents(); + expect(contents).to.eql(trim(`= function() + + m.currentAssertLineNumber = 6 + m._expectNotCalled(thing, "callFunc") + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 7 + m._expectNotCalled(thing, "callFunc") + if m.currentResult.isFail then return invalid + + `)); + + }); + it('correctly transpiles func pointers', async () => { + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + m.expectNotCalled(m.thing.getFunctionField) + end function + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + let contents = getTestFunctionContents(); + expect(contents).to.eql(trim(`= function() + + m.currentAssertLineNumber = 6 + m._expectNotCalled(m.thing, "getFunctionField") + if m.currentResult.isFail then return invalid + + `)); + + }); + it('correctly transpiles function invocations', async () => { + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + m.expectNotCalled(m.thing.getFunction()) + m.expectNotCalled(m.thing.getFunction(), "return") + m.expectNotCalled(m.thing.getFunction()) + m.expectNotCalled(m.thing.getFunction(), "return") + end function + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + let contents = getTestFunctionContents(); + expect(contents).to.eql(trim(`= function() + + m.currentAssertLineNumber = 6 + m._expectNotCalled(m.thing, "getFunction") + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 7 + m._expectNotCalled(m.thing, "getFunction", "return") + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 8 + m._expectNotCalled(m.thing, "getFunction") + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 9 + m._expectNotCalled(m.thing, "getFunction", "return") + if m.currentResult.isFail then return invalid + + `)); + }); + + it('correctly transpiles function invocations - simple object', async () => { + program.setFile('source/test.spec.bs', ` + @suite + class ATest + @describe("groupA") + @it("test1") + function _() + item = {id: "item"} + m.expectNotCalled(item.getFunction()) + m.expectNotCalled(item.getFunction()) + end function + end class + `); + program.validate(); + expect(program.getDiagnostics()).to.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + await builder.transpile(); + let contents = getTestFunctionContents(); + expect(contents).to.eql(trim(`= function() + item = { + id: "item" + } + + m.currentAssertLineNumber = 7 + m._expectNotCalled(item, "getFunction") + if m.currentResult.isFail then return invalid + + + m.currentAssertLineNumber = 8 + m._expectNotCalled(item, "getFunction") + if m.currentResult.isFail then return invalid + + `)); + }); + }); + + describe('honours tags - simple tests', () => { + let testSource = ` @tags("one", "two", "exclude") @suite("a") class ATest extends rooibos.BaseTestSuite @@ -443,163 +950,169 @@ end function`)); end class `; - beforeEach(() => { - plugin = new RooibosPlugin(); - options = { - rootDir: _rootDir, - stagingFolderPath: _stagingFolderPath - }; - fsExtra.ensureDirSync(_stagingFolderPath); - fsExtra.ensureDirSync(_rootDir); - fsExtra.ensureDirSync(tmpPath); - - builder = new ProgramBuilder(); - builder.options = util.normalizeAndResolveConfig(options); - builder.program = new Program(builder.options); - program = builder.program; - builder.plugins = new PluginInterface([plugin], builder.logger); - program.plugins = new PluginInterface([plugin], builder.logger); - program.createSourceScope(); //ensure source scope is created - plugin.beforeProgramCreate(builder); - plugin.fileFactory.sourcePath = path.resolve(path.join('../framework/src/source')); - plugin.afterProgramCreate(program); - // program.validate(); - }); - afterEach(() => { - fsExtra.ensureDirSync(tmpPath); - fsExtra.emptyDirSync(tmpPath); - builder.dispose(); - program.dispose(); - }); - it('tag one', async () => { - plugin.session.sessionInfo.includeTags = ['one']; - program.addOrReplaceFile('source/test.spec.bs', testSource); - program.validate(); - await builder.transpile(); - console.log(builder.getDiagnostics()); - expect(builder.getDiagnostics()).to.have.length(1); - expect(builder.getDiagnostics()[0].severity).to.equal(DiagnosticSeverity.Warning); - expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; - expect(plugin.session.sessionInfo.testSuitesToRun[0].name).to.equal('a'); - expect(plugin.session.sessionInfo.testSuitesToRun[1].name).to.equal('b'); - }); - it('tag two', async () => { - plugin.session.sessionInfo.includeTags = ['two']; - program.addOrReplaceFile('source/test.spec.bs', testSource); - program.validate(); - await builder.transpile(); - console.log(builder.getDiagnostics()); - expect(builder.getDiagnostics()).to.have.length(1); - expect(builder.getDiagnostics()[0].severity).to.equal(DiagnosticSeverity.Warning); - expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; - expect(plugin.session.sessionInfo.testSuitesToRun[0].name).to.equal('a'); - }); - it('tag three', async () => { - plugin.session.sessionInfo.includeTags = ['three']; - program.addOrReplaceFile('source/test.spec.bs', testSource); - program.validate(); - await builder.transpile(); - console.log(builder.getDiagnostics()); - expect(builder.getDiagnostics()).to.have.length(1); - expect(builder.getDiagnostics()[0].severity).to.equal(DiagnosticSeverity.Warning); - expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; - expect(plugin.session.sessionInfo.testSuitesToRun[0].name).to.equal('b'); - }); - it('tag exclude', async () => { - plugin.session.sessionInfo.excludeTags = ['exclude']; - program.addOrReplaceFile('source/test.spec.bs', testSource); - program.validate(); - await builder.transpile(); - console.log(builder.getDiagnostics()); - expect(builder.getDiagnostics()).to.have.length(1); - expect(builder.getDiagnostics()[0].severity).to.equal(DiagnosticSeverity.Warning); - expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; - expect(plugin.session.sessionInfo.testSuitesToRun[0].name).to.equal('b'); - }); - it('inlcude and exclude tags', async () => { - plugin.session.sessionInfo.includeTags = ['one', 'two']; - plugin.session.sessionInfo.excludeTags = ['exclude']; - program.addOrReplaceFile('source/test.spec.bs', testSource); - program.validate(); - await builder.transpile(); - console.log(builder.getDiagnostics()); - expect(builder.getDiagnostics()).to.have.length(1); - expect(builder.getDiagnostics()[0].severity).to.equal(DiagnosticSeverity.Warning); - expect(plugin.session.sessionInfo.testSuitesToRun).to.be.empty; - }); - it('Need all tags', async () => { - plugin.session.sessionInfo.includeTags = ['one', 'two']; - program.addOrReplaceFile('source/test.spec.bs', testSource); - program.validate(); - await builder.transpile(); - console.log(builder.getDiagnostics()); - expect(builder.getDiagnostics()).to.have.length(1); - expect(builder.getDiagnostics()[0].severity).to.equal(DiagnosticSeverity.Warning); - expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; - expect(plugin.session.sessionInfo.testSuitesToRun[0].name).to.equal('a'); + beforeEach(() => { + plugin = new RooibosPlugin(); + options = { + rootDir: _rootDir, + stagingFolderPath: _stagingFolderPath + }; + fsExtra.ensureDirSync(_stagingFolderPath); + fsExtra.ensureDirSync(_rootDir); + fsExtra.ensureDirSync(tmpPath); + + builder = new ProgramBuilder(); + builder.options = util.normalizeAndResolveConfig(options); + builder.program = new Program(builder.options); + program = builder.program; + builder.plugins = new PluginInterface([plugin], builder.logger); + program.plugins = new PluginInterface([plugin], builder.logger); + program.createSourceScope(); //ensure source scope is created + plugin.beforeProgramCreate(builder); + plugin.fileFactory.sourcePath = path.resolve(path.join('../framework/src/source')); + plugin.afterProgramCreate(program); + // program.validate(); + }); + afterEach(() => { + fsExtra.ensureDirSync(tmpPath); + fsExtra.emptyDirSync(tmpPath); + builder.dispose(); + program.dispose(); + }); + it('tag one', async () => { + plugin.session.sessionInfo.includeTags = ['one']; + program.setFile('source/test.spec.bs', testSource); + program.validate(); + await builder.transpile(); + console.log(builder.getDiagnostics()); + expect(builder.getDiagnostics()).to.have.length(1); + expect(builder.getDiagnostics()[0].severity).to.equal(DiagnosticSeverity.Warning); + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun[0].name).to.equal('a'); + expect(plugin.session.sessionInfo.testSuitesToRun[1].name).to.equal('b'); + }); + it('tag two', async () => { + plugin.session.sessionInfo.includeTags = ['two']; + program.setFile('source/test.spec.bs', testSource); + program.validate(); + await builder.transpile(); + console.log(builder.getDiagnostics()); + expect(builder.getDiagnostics()).to.have.length(1); + expect(builder.getDiagnostics()[0].severity).to.equal(DiagnosticSeverity.Warning); + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun[0].name).to.equal('a'); + }); + it('tag three', async () => { + plugin.session.sessionInfo.includeTags = ['three']; + program.setFile('source/test.spec.bs', testSource); + program.validate(); + await builder.transpile(); + console.log(builder.getDiagnostics()); + expect(builder.getDiagnostics()).to.have.length(1); + expect(builder.getDiagnostics()[0].severity).to.equal(DiagnosticSeverity.Warning); + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun[0].name).to.equal('b'); + }); + it('tag exclude', async () => { + plugin.session.sessionInfo.excludeTags = ['exclude']; + program.setFile('source/test.spec.bs', testSource); + program.validate(); + await builder.transpile(); + console.log(builder.getDiagnostics()); + expect(builder.getDiagnostics()).to.have.length(1); + expect(builder.getDiagnostics()[0].severity).to.equal(DiagnosticSeverity.Warning); + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun[0].name).to.equal('b'); + }); + it('include and exclude tags', async () => { + plugin.session.sessionInfo.includeTags = ['one', 'two']; + plugin.session.sessionInfo.excludeTags = ['exclude']; + program.setFile('source/test.spec.bs', testSource); + program.validate(); + await builder.transpile(); + console.log(builder.getDiagnostics()); + expect(builder.getDiagnostics()).to.have.length(1); + expect(builder.getDiagnostics()[0].severity).to.equal(DiagnosticSeverity.Warning); + expect(plugin.session.sessionInfo.testSuitesToRun).to.be.empty; + }); + it('Need all tags', async () => { + plugin.session.sessionInfo.includeTags = ['one', 'two']; + program.setFile('source/test.spec.bs', testSource); + program.validate(); + await builder.transpile(); + console.log(builder.getDiagnostics()); + expect(builder.getDiagnostics()).to.have.length(1); + expect(builder.getDiagnostics()[0].severity).to.equal(DiagnosticSeverity.Warning); + expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty; + expect(plugin.session.sessionInfo.testSuitesToRun[0].name).to.equal('a'); + }); }); - }); -}); + }); -describe.only('run a local project', () => { - it('sanity checks on parsing - only run this outside of ci', () => { - let programBuilder = new ProgramBuilder(); - let swv = { - 'stagingFolderPath': 'build', - 'rootDir': '/home/george/hope/open-source/rooibos/tests', - 'files': ['manifest', 'source/**/*.*', 'components/**/*.*'], - 'autoImportComponentScript': true, - 'createPackage': false, - 'diagnosticFilters': [ - { - 'src': '**/roku_modules/**/*.*', - 'codes': [1107, 1009] + describe.skip('run a local project', () => { + it('sanity checks on parsing - only run this outside of ci', () => { + let programBuilder = new ProgramBuilder(); + let swv = { + 'stagingFolderPath': 'build', + 'rootDir': '/home/george/hope/open-source/rooibos/tests', + 'files': ['manifest', 'source/**/*.*', 'components/**/*.*'], + 'autoImportComponentScript': true, + 'createPackage': false, + 'diagnosticFilters': [ + { + 'src': '**/roku_modules/**/*.*', + 'codes': [1107, 1009] + } + ], + 'rooibos': { + 'showOnlyFailures': true, + 'catchCrashes': true, + 'lineWidth': 70, + 'failFast': false, + 'sendHomeOnFinish': false + }, + 'maestro': { + 'nodeFileDelay': 0, + 'excludeFilters': [ + '**/roku_modules/**/*', + '**/*BaseTestSuite*.bs' + ] + }, + 'sourceMap': true, + 'extends': 'bsconfig.json', + 'plugins': [ + '/home/george/hope/open-source/maestro/maestro-roku-bsc-plugin/dist/plugin.js', + '/home/george/hope/open-source/rooibos/bsc-plugin/dist/plugin.js' + ], + 'exclude': { + 'id': '/home/george/hope/open-source/maestro/roku-log-bsc-plugin/dist/plugin.js' + }, + 'rokuLog': { + 'strip': false, + 'insertPkgPath': true } - ], - 'rooibos': { - 'showOnlyFailures': true, - 'catchCrashes': true, - 'lineWidth': 70, - 'failFast': false, - 'sendHomeOnFinish': false - }, - 'maestro': { - 'nodeFileDelay': 0, - 'excludeFilters': [ - '**/roku_modules/**/*', - '**/*BaseTestSuite*.bs' - ] - }, - 'sourceMap': true, - 'extends': 'bsconfig.json', - 'plugins': [ - '/home/george/hope/open-source/maestro/maestro-roku-bsc-plugin/dist/plugin.js', - '/home/george/hope/open-source/rooibos/bsc-plugin/dist/plugin.js' - ], - 'exclude': { - 'id': '/home/george/hope/open-source/maestro/roku-log-bsc-plugin/dist/plugin.js' - }, - 'rokuLog': { - 'strip': false, - 'insertPkgPath': true - } - }; + }; - programBuilder.run( - // swv - { - project: '/home/george/hope/open-source/rooibos/tests/bsconfig.json' - // project: '/home/george/hope/open-source/maestro/swerve-app/bsconfig-test.json' - } - ).catch(e => { - console.error(e); + programBuilder.run( + // swv + { + project: '/home/george/hope/open-source/rooibos/tests/bsconfig.json' + // project: '/home/george/hope/open-source/maestro/swerve-app/bsconfig-test.json' + } + ).catch(e => { + console.error(e); + }); + console.log('done'); }); - console.log('done'); }); }); function getContents(filename: string) { return trim(fsExtra.readFileSync(s`${_stagingFolderPath}/source/${filename}`).toString()); } + +function getTestFunctionContents() { + let contentsRegex = /\= function\(\)([\S\s]*|.*)(?=end function)/gim; + return trim(getContents('test.spec.brs').match(contentsRegex)[0].split('end function')[0]); +} diff --git a/framework/src/source/BaseTestSuite.bs b/framework/src/source/BaseTestSuite.bs index e762e5ce..a9d17cca 100644 --- a/framework/src/source/BaseTestSuite.bs +++ b/framework/src/source/BaseTestSuite.bs @@ -1576,8 +1576,9 @@ namespace rooibos end if m.__stubId++ - if m.__stubId > 5 - ? "ERROR ONLY 6 STUBS PER TEST ARE SUPPORTED!!" + if m.__stubId > 25 + ? "ERROR ONLY 25 MOCKS PER TEST ARE SUPPORTED!! you're on # " ; m.__mockId + ? " Method was " ; methodName return invalid end if @@ -1591,9 +1592,10 @@ namespace rooibos target[methodName] = m["StubCallback" + id] target.__stubs = m.stubs - if not isMethodPresent - ? "WARNING - stubbing call " ; methodName; " which did not exist on target object" - end if + ' FIXME: add a log setting for this - and add better detection so that stubs know that they are colliding/don't exist/have correct sigs + ' if not isMethodPresent + ' ? "WARNING - stubbing call " ; methodName; " which did not exist on target object" + ' end if else ? "ERROR - could not create Stub : method not found "; target ; "." ; methodName end if @@ -1601,24 +1603,46 @@ namespace rooibos return fake end function - ' /** - ' * @memberof module:BaseTestSuite - ' * @name expectOnce - ' * @function - ' * @instance - ' * @description Creates a stub to replace a real method with, which the framework will track. If it was invoked the wrong number of times, or with wrong arguments, it will result in test failure - ' * @param {Dynamic} target - object on which the method to be stubbed is found - ' * @param {Dynamic} methodName - name of method to stub - ' * @param {Dynamic} [expectedArgs=invalid] - array containing the arguments we expect the method to be invoked with - ' * @param {Dynamic} [returnValue=invalid] - value that the stub method will return when invoked - ' * @param {boolean} [allowNonExistingMethods=false] - if true, then rooibos will only warn if the method did not exist prior to faking - ' * @returns {Object} - mock that was wired into the real method - ' */ - function expectCallFuncOnce(target, methodName, expectedArgs = invalid, returnValue = invalid, allowNonExistingMethods = false) as object + function expectCalled(invocation as dynamic, returnValue = invalid as dynamic) as object + 'mock function body - the plugin replaces this + return invalid + end function + + function _expectCalled(target, methodName, expectedArgs = invalid, returnValue = invalid as dynamic) as object + try + return m.mock(target, methodName, 1, expectedArgs, returnValue, true) + catch error + 'bs:disable-next-line + m.currentResult.fail("Setting up mock failed: " + error.message, m.currentAssertLineNumber) + return false + end try + return false + end function + + function stubCall(invocation as dynamic, returnValue = invalid as dynamic) as object + 'mock function body - the plugin replaces this + return invalid + end function + + function _stubCall(target, methodName, returnValue = invalid as dynamic) as object + try + return m.stub(target, methodName, returnValue, true) + catch error + 'bs:disable-next-line + m.currentResult.fail("Setting up mock failed: " + error.message, m.currentAssertLineNumber) + return false + end try + return false + end function + + function expectNotCalled(invocation as dynamic) as object + 'mock function body - the plugin replaces this + return invalid + end function + + function _expectNotCalled(target, methodName) as object try - args = [methodName] - args.append(expectedArgs) - return m.mock(target, "callFunc", 1, expectedArgs, returnValue, allowNonExistingMethods) + return m.mock(target, methodName, 0, invalid, invalid, true) catch error 'bs:disable-next-line m.currentResult.fail("Setting up mock failed: " + error.message, m.currentAssertLineNumber) @@ -1627,6 +1651,7 @@ namespace rooibos return false end function + ' /** ' * @memberof module:BaseTestSuite ' * @name expectOnce @@ -2088,6 +2113,127 @@ namespace rooibos return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) end function + function stubCallback6(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["6"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback7(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["7"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback8(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["8"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback9(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["9"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback10(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["10"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback11(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["11"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback12(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["12"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback13(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["13"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback14(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["14"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback15(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["15"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback16(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["16"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback17(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["17"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback18(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["18"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback19(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["19"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback20(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["20"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback21(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["21"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback22(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["22"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback23(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["23"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback24(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["24"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + function stubCallback25(arg1 = invalid, arg2 = invalid, arg3 = invalid, arg4 = invalid, arg5 = invalid, arg6 = invalid, arg7 = invalid, arg8 = invalid, arg9 = invalid, arg10 = invalid, arg11 = invalid, arg12 = invalid, arg13 = invalid, arg14 = invalid, arg15 = invalid) as dynamic + 'bs:disable-next-line + fake = m.__Stubs["25"] + return fake.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) + end function + + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ '++ Fake Mock callback functions - this is required to get scope '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/tests/src/source/Basic.spec.bs b/tests/src/source/Basic.spec.bs index d8c3d83d..14fb7ec7 100644 --- a/tests/src/source/Basic.spec.bs +++ b/tests/src/source/Basic.spec.bs @@ -180,25 +180,5 @@ namespace tests m.assertEqual(msg, "[one, two, three] != [2one, 2two, 2three]") end function - '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - @describe("expectCallFunc") - '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - @it("supports expectCallFunc syntax") - function _() - node = { "id" : "node" } - - a = 1 - b = 2 - value = { "id" : "value" } - - m.expectCallFuncOnce(node, "getValue", [a, b], value) - - result = node@.getValue(a, b) - - m.assertEqual(result, value) - end function - - end class end namespace \ No newline at end of file diff --git a/tests/src/source/Expect.spec.bs b/tests/src/source/Expect.spec.bs index 94e28529..3bf3bc0f 100644 --- a/tests/src/source/Expect.spec.bs +++ b/tests/src/source/Expect.spec.bs @@ -5,6 +5,30 @@ namespace tests @suite class ExpectTests extends rooibos.BaseTestSuite + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + '+ Helper + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + private function assertRunningTestIsFailed() + m.isAutoAssertingMocks = false + m.assertMocks() + + isFail = m.currentResult.isFail + m.currentResult.Reset() + m.cleanMocks() + m.assertTrue(isFail) + end function + + private function assertRunningTestIsPassed() + m.isAutoAssertingMocks = false + m.assertMocks() + + isFail = m.currentResult.isFail + m.currentResult.Reset() + m.cleanMocks() + m.assertFalse(isFail) + end function + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @describe("expectonce bug") '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/tests/src/source/NewExpectSyntax.spec.bs b/tests/src/source/NewExpectSyntax.spec.bs new file mode 100644 index 00000000..7148c7b3 --- /dev/null +++ b/tests/src/source/NewExpectSyntax.spec.bs @@ -0,0 +1,287 @@ + +namespace tests + @suite + class NewExpectSyntaxTests extends rooibos.BaseTestSuite + + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + '+ Helper + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + private function assertRunningTestIsFailed() + m.isAutoAssertingMocks = false + m.assertMocks() + + isFail = m.currentResult.isFail + m.currentResult.Reset() + m.cleanMocks() + m.cleanSTubs() + m.assertTrue(isFail) + end function + + private function assertRunningTestIsPassed() + m.isAutoAssertingMocks = false + m.assertMocks() + + isFail = m.currentResult.isFail + m.currentResult.Reset() + m.cleanMocks() + m.cleanSTubs() + m.assertFalse(isFail) + end function + + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @describe("expectCalled regular functions") + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + @it("simple") + function _() + item = { "id": "node" } + m.expectCalled(item.getText(), "test") + m.assertEqual(item.getText(), "test") + end function + + @it("expected param") + function _() + item = { "id": "node" } + m.expectCalled(item.getText("expected"), "test") + m.assertEqual(item.getText("expected"), "test") + + m.assertRunningTestIsPassed() + end function + + @it("not matching on param") + function _() + item = { "id": "node" } + m.expectCalled(item.getText("expected"), "test") + + m.assertEqual(item.getText("not expected"), "test") + + m.assertRunningTestIsFailed() + end function + + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @describe("expectCalled function pointers") + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + @it("supports function pointer - therefore ignoring the params") + function _() + item = { "id": "node" } + m.expectCalled(item.getText, "test") + + m.assertEqual(item.getText("any text"), "test") + + m.assertRunningTestIsPassed() + end function + + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @describe("expectCalled callFunc functions") + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + @it("simple") + function _() + item = { "id": "node" } + m.expectCalled(item@.getText(), "test") + m.assertEqual(item@.getText(), "test") + end function + + @it("expected param") + function _() + item = { "id": "node" } + m.expectCalled(item@.getText("expected"), "test") + m.assertEqual(item@.getText("expected"), "test") + + m.assertRunningTestIsPassed() + end function + + @it("not matching on param") + function _() + item = { "id": "node" } + m.expectCalled(item@.getText("expected"), "test") + + m.assertEqual(item@.getText("not expected"), "test") + + m.assertRunningTestIsFailed() + end function + + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @describe("stubCall regular functions") + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + @it("simple") + function _() + item = { "id": "node" } + m.stubCall(item.getText(), "test") + m.assertEqual(item.getText(), "test") + end function + + @it("expected param") + function _() + item = { "id": "node" } + m.stubCall(item.getText("expected"), "test") + m.assertEqual(item.getText("expected"), "test") + + m.assertRunningTestIsPassed() + end function + + @it("not matching on param") + function _() + item = { "id": "node" } + m.stubCall(item.getText("expected"), "test") + + m.assertEqual(item.getText("not expected"), "test") + + m.assertRunningTestIsPassed() + end function + + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @describe("stubCall function pointers") + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + @it("supports function pointer - therefore ignoring the params") + function _() + item = { "id": "node" } + m.stubCall(item.getText, "test") + + m.assertEqual(item.getText("any text"), "test") + + m.assertRunningTestIsPassed() + end function + + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @describe("stubCall callFunc functions") + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + @it("not matching on param") + function _() + item = { "id": "node" } + m.stubCall(item@.getText("expected"), "test") + + m.assertEqual(item@.getText("not expected"), "test") + + m.assertRunningTestIsPassed() + end function + + @it("simple") + function _() + item = { "id": "node" } + m.stubCall(item@.getText(), "test") + m.assertEqual(item@.getText(), "test") + end function + + @it("expected param") + function _() + item = { "id": "node" } + m.stubCall(item@.getText("expected"), "test") + m.assertEqual(item@.getText("expected"), "test") + + m.assertRunningTestIsPassed() + end function + + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @describe("expectNotCalled") + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + @it("passes when not called") + function _() + item = { "id": "node" } + m.expectNotCalled(item.getText()) + m.assertRunningTestIsPassed() + end function + + @it("fails when called") + function _() + item = { "id": "node" } + m.expectNotCalled(item.getText()) + item.getText() + + m.assertRunningTestIsFailed() + end function + + @it("fails when called, with params") + function _() + item = { "id": "node" } + m.expectNotCalled(item.getText()) + item.getText("expected") + + m.assertRunningTestIsFailed() + end function + + @it("fails when called, with params on expect too") + function _() + item = { "id": "node" } + m.expectNotCalled(item.getText("expected")) + item.getText("not expected") + + m.assertRunningTestIsFailed() + end function + + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @describe("expectNotCalled - with callfunc") + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + @it("passes when not called") + function _() + item = { "id": "node" } + m.expectNotCalled(item@.getText()) + m.assertRunningTestIsPassed() + end function + + @it("fails when called") + function _() + item = { "id": "node" } + m.expectNotCalled(item@.getText()) + item@.getText() + + m.assertRunningTestIsFailed() + end function + + @it("fails when called, with params") + function _() + item = { "id": "node" } + m.expectNotCalled(item@.getText()) + item@.getText("expected") + + m.assertRunningTestIsFailed() + end function + + @it("fails when called, with params on expect too") + function _() + item = { "id": "node" } + m.expectNotCalled(item@.getText("expected")) + item@.getText("not expected") + + m.assertRunningTestIsFailed() + end function + + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @describe("expectNotCalled - function pointers") + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + @it("passes when not called") + function _() + item = { "id": "node" } + m.expectNotCalled(item.getText) + m.assertRunningTestIsPassed() + end function + + @it("fails when called") + function _() + item = { "id": "node" } + m.expectNotCalled(item.getText) + item.getText() + + m.assertRunningTestIsFailed() + end function + + @it("fails when called, with params") + function _() + item = { "id": "node" } + m.expectNotCalled(item.getText) + item.getText("expected") + + m.assertRunningTestIsFailed() + end function + + end class + +end namespace \ No newline at end of file