Skip to content

Commit

Permalink
WIP: adds support for expecting on global functions and namespace fun…
Browse files Browse the repository at this point in the history
…ctions (#241)

* adds support for expecting on global functions and namespace functions

* fixes

* wip

* fixes error in utils

* adds docs

* reinstates erroneously disabled try catch
  • Loading branch information
georgejecook authored Oct 25, 2023
1 parent 4e69b1e commit 10f6305
Show file tree
Hide file tree
Showing 24 changed files with 1,499 additions and 427 deletions.
387 changes: 387 additions & 0 deletions bsc-plugin/src/lib/rooibos/MockUtil.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,387 @@
/* 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'
],
isGlobalMethodMockingEfficientMode: false
},
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_SM_1_getMocksByFunctionName()["sayhello"] <> invalid
result = RBS_SM_1_getMocksByFunctionName()["sayhello"].callback(a1,a2)
return result
end if
print "hello"
end function
function RBS_SM_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_SM_1_getMocksByFunctionName()["sayhello"] <> invalid
result = RBS_SM_1_getMocksByFunctionName()["sayhello"].callback(a1,a2)
return result
end if
print "hello"
end function
function RBS_SM_1_getMocksByFunctionName()
if m._rMocksByFunctionName = invalid
m._rMocksByFunctionName = {}
end if
return m._rMocksByFunctionName
end function
`);
expect(a).to.equal(b);

});
it('weird raletracker task issue I saw', async () => {
program.setFile('source/code.bs', `
Sub RedLines_SetRulerLines(rulerLines)
For Each line In rulerLines.Items()
RedLines_AddLine(line.key, line.value.position, line.value.coords, m.node, m.childMap)
End For
end Sub
Sub RedLines_AddLine(id, position, coords, node, childMap) as Object
line = CreateObject("roSGNode", "Rectangle")
line.setField("id", id)
end sub
`);
program.validate();
expect(program.getDiagnostics()).to.be.empty;
await builder.transpile();
let a = getContents('source/code.brs');
let b = trimLeading(`Sub RedLines_SetRulerLines(rulerLines)
if RBS_SM_1_getMocksByFunctionName()["redlines_setrulerlines"] <> invalid
result = RBS_SM_1_getMocksByFunctionName()["redlines_setrulerlines"].callback(rulerLines)
return
end if
For Each line In rulerLines.Items()
RedLines_AddLine(line.key, line.value.position, line.value.coords, m.node, m.childMap)
End For
end Sub
Sub RedLines_AddLine(id, position, coords, node, childMap) as Object
if RBS_SM_1_getMocksByFunctionName()["redlines_addline"] <> invalid
result = RBS_SM_1_getMocksByFunctionName()["redlines_addline"].callback(id,position,coords,node,childMap)
return result
end if
line = CreateObject("roSGNode", "Rectangle")
line.setField("id", id)
end sub
function RBS_SM_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_SM_1_getMocksByFunctionName()["sayhello"] <> invalid
result = RBS_SM_1_getMocksByFunctionName()["sayhello"].callback(a1,a2)
return
end if
print "hello"
end sub
function RBS_SM_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_SM_1_getMocksByFunctionName()["person_utils_sayhello"] <> invalid
result = RBS_SM_1_getMocksByFunctionName()["person_utils_sayhello"].callback(a1,a2)
return result
end if
print "hello"
end function
function RBS_SM_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_SM_1_getMocksByFunctionName()["person_utils_sayhello"] <> invalid
result = RBS_SM_1_getMocksByFunctionName()["person_utils_sayhello"].callback(a1,a2)
return
end if
print "hello"
end sub
function RBS_SM_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_SM_1_getMocksByFunctionName()["beings_sayhello"] <> invalid
result = RBS_SM_1_getMocksByFunctionName()["beings_sayhello"].callback()
return result
end if
print "hello2"
end function
function sayHello()
if RBS_SM_1_getMocksByFunctionName()["sayhello"] <> invalid
result = RBS_SM_1_getMocksByFunctionName()["sayhello"].callback()
return result
end if
print "hello3"
end function
function RBS_SM_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);
});
});
});
Loading

0 comments on commit 10f6305

Please sign in to comment.