Files
privacy.sexy/tests/unit/application/Context/State/Code/Generation/UserScriptGenerator.spec.ts
undergroundwires 803ef2bb3e Move stubs from ./stubs to ./shared/Stubs
Gathers all shared test code in single place.
2022-01-25 08:37:03 +01:00

279 lines
11 KiB
TypeScript

import 'mocha';
import { expect } from 'chai';
import { UserScriptGenerator } from '@/application/Context/State/Code/Generation/UserScriptGenerator';
import { SelectedScript } from '@/application/Context/State/Selection/SelectedScript';
import { ICodeBuilderFactory } from '@/application/Context/State/Code/Generation/ICodeBuilderFactory';
import { ICodeBuilder } from '@/application/Context/State/Code/Generation/ICodeBuilder';
import { ScriptStub } from '@tests/unit/shared/Stubs/ScriptStub';
import { ScriptingDefinitionStub } from '@tests/unit/shared/Stubs/ScriptingDefinitionStub';
import { itEachAbsentObjectValue, itEachAbsentStringValue } from '@tests/unit/shared/TestCases/AbsentTests';
import { SelectedScriptStub } from '@tests/unit/shared/Stubs/SelectedScriptStub';
describe('UserScriptGenerator', () => {
describe('scriptingDefinition', () => {
describe('startCode', () => {
it('is prepended if not empty', () => {
// arrange
const sut = new UserScriptGenerator();
const startCode = 'Start\nCode';
const script = new ScriptStub('id')
.withCode('code\nmulti-lined')
.toSelectedScript();
const definition = new ScriptingDefinitionStub()
.withStartCode(startCode);
const expectedStart = `${startCode}\n`;
// act
const code = sut.buildCode([script], definition);
// assert
const actual = code.code;
expect(actual.startsWith(expectedStart));
});
describe('is not prepended if empty', () => {
itEachAbsentStringValue((absentValue) => {
// arrange
const codeBuilderStub = new CodeBuilderStub();
const sut = new UserScriptGenerator(mockCodeBuilderFactory(codeBuilderStub));
const script = new ScriptStub('id')
.withCode('code\nmulti-lined')
.toSelectedScript();
const definition = new ScriptingDefinitionStub()
.withStartCode(absentValue);
const expectedStart = codeBuilderStub
.appendFunction(script.script.name, script.script.code.execute)
.toString();
// act
const code = sut.buildCode([script], definition);
// assert
const actual = code.code;
expect(actual.startsWith(expectedStart));
});
});
});
describe('endCode', () => {
it('is appended if not empty', () => {
// arrange
const sut = new UserScriptGenerator();
const endCode = 'End\nCode';
const script = new ScriptStub('id')
.withCode('code\nmulti-lined')
.toSelectedScript();
const definition = new ScriptingDefinitionStub()
.withEndCode(endCode);
const expectedEnd = `${endCode}\n`;
// act
const code = sut.buildCode([script], definition);
// assert
const actual = code.code;
expect(actual.endsWith(expectedEnd));
});
describe('is not appended if empty', () => {
itEachAbsentStringValue((absentValue) => {
// arrange
const codeBuilderStub = new CodeBuilderStub();
const sut = new UserScriptGenerator(mockCodeBuilderFactory(codeBuilderStub));
const script = new ScriptStub('id')
.withCode('code\nmulti-lined')
.toSelectedScript();
const expectedEnd = codeBuilderStub
.appendFunction(script.script.name, script.script.code.execute)
.toString();
const definition = new ScriptingDefinitionStub()
.withEndCode(absentValue);
// act
const code = sut.buildCode([script], definition);
// assert
const actual = code.code;
expect(actual.endsWith(expectedEnd));
});
});
});
describe('throws when absent', () => {
itEachAbsentObjectValue((absentValue) => {
// arrange
const expectedError = 'missing definition';
const sut = new UserScriptGenerator();
const scriptingDefinition = absentValue;
const selectedScripts = [new SelectedScriptStub('a')];
// act
const act = () => sut.buildCode(selectedScripts, scriptingDefinition);
// assert
expect(act).to.throw(expectedError);
});
});
});
it('appends revert script', () => {
// arrange
const sut = new UserScriptGenerator();
const scriptName = 'test non-revert script';
const scriptCode = 'REM nop';
const script = new ScriptStub('id')
.withName(scriptName)
.withRevertCode(scriptCode)
.toSelectedScript(true);
const definition = new ScriptingDefinitionStub();
// act
const actual = sut.buildCode([script], definition);
// assert
expect(actual.code).to.include(`${scriptName} (revert)`);
expect(actual.code).to.include(scriptCode);
});
it('appends non-revert script', () => {
const sut = new UserScriptGenerator();
// arrange
const scriptName = 'test non-revert script';
const scriptCode = 'REM nop';
const script = new ScriptStub('id').withName(scriptName).withCode(scriptCode);
const selectedScripts = [new SelectedScript(script, false)];
const definition = new ScriptingDefinitionStub();
// act
const actual = sut.buildCode(selectedScripts, definition);
// assert
expect(actual.code).to.include(scriptName);
expect(actual.code).to.not.include(`${scriptName} (revert)`);
expect(actual.code).to.include(scriptCode);
});
describe('scriptPositions', () => {
it('without script; returns empty', () => {
// arrange
const sut = new UserScriptGenerator();
const selectedScripts = [];
const definition = new ScriptingDefinitionStub();
// act
const actual = sut.buildCode(selectedScripts, definition);
// assert
expect(actual.scriptPositions.size).to.equal(0);
});
describe('with scripts', () => {
// arrange
const totalStartCodeLines = 2;
const totalFunctionNameLines = 4;
const definition = new ScriptingDefinitionStub()
.withStartCode('First line\nSecond line');
describe('single script', () => {
const testCases = [
{
name: 'single-lined',
scriptCode: 'only line',
codeLines: 1,
},
{
name: 'multi-lined',
scriptCode: 'first line\nsecond line',
codeLines: 2,
},
];
const sut = new UserScriptGenerator();
for (const testCase of testCases) {
it(testCase.name, () => {
const expectedStartLine = totalStartCodeLines
+ 1 // empty line code begin
+ 1; // code begin
const expectedEndLine = expectedStartLine
+ totalFunctionNameLines
+ testCase.codeLines;
const selectedScript = new ScriptStub('script-id')
.withName('script')
.withCode(testCase.scriptCode)
.toSelectedScript(false);
// act
const actual = sut.buildCode([selectedScript], definition);
// expect
expect(1).to.equal(actual.scriptPositions.size);
const position = actual.scriptPositions.get(selectedScript);
expect(expectedStartLine).to.equal(position.startLine, 'Unexpected start line position');
expect(expectedEndLine).to.equal(position.endLine, 'Unexpected end line position');
});
}
});
it('multiple scripts', () => {
const sut = new UserScriptGenerator();
const selectedScripts = [
new ScriptStub('1').withCode('only line'),
new ScriptStub('2').withCode('first line\nsecond line'),
].map((s) => s.toSelectedScript());
const expectedFirstScriptStart = totalStartCodeLines
+ 1 // empty line code begin
+ 1; // code begin
const expectedFirstScriptEnd = expectedFirstScriptStart
+ totalFunctionNameLines
+ 1; // total code lines
const expectedSecondScriptStart = expectedFirstScriptEnd
+ 1 // code end hyphens
+ 1 // new line
+ 1; // code begin
const expectedSecondScriptEnd = expectedSecondScriptStart
+ totalFunctionNameLines
+ 2; // total lines of second script
// act
const actual = sut.buildCode(selectedScripts, definition);
// assert
const firstPosition = actual.scriptPositions.get(selectedScripts[0]);
const secondPosition = actual.scriptPositions.get(selectedScripts[1]);
expect(actual.scriptPositions.size).to.equal(2);
expect(expectedFirstScriptStart).to.equal(firstPosition.startLine, 'Unexpected start line position (first script)');
expect(expectedFirstScriptEnd).to.equal(firstPosition.endLine, 'Unexpected end line position (first script)');
expect(expectedSecondScriptStart).to.equal(secondPosition.startLine, 'Unexpected start line position (second script)');
expect(expectedSecondScriptEnd).to.equal(secondPosition.endLine, 'Unexpected end line position (second script)');
});
});
});
describe('selectedScripts', () => {
describe('throws when absent', () => {
itEachAbsentObjectValue((absentValue) => {
// arrange
const expectedError = 'missing scripts';
const sut = new UserScriptGenerator();
const scriptingDefinition = new ScriptingDefinitionStub();
const selectedScripts = absentValue;
// act
const act = () => sut.buildCode(selectedScripts, scriptingDefinition);
// assert
expect(act).to.throw(expectedError);
});
});
});
});
function mockCodeBuilderFactory(mock: ICodeBuilder): ICodeBuilderFactory {
return {
create: () => mock,
};
}
class CodeBuilderStub implements ICodeBuilder {
public currentLine = 0;
private text = '';
public appendLine(code?: string): ICodeBuilder {
this.text += this.text ? `${code}\n` : code;
this.currentLine++;
return this;
}
public appendTrailingHyphensCommentLine(totalRepeatHyphens: number): ICodeBuilder {
return this.appendLine(`trailing-hyphens-${totalRepeatHyphens}`);
}
public appendCommentLine(commentLine?: string): ICodeBuilder {
return this.appendLine(`Comment | ${commentLine}`);
}
public appendCommentLineWithHyphensAround(
sectionName: string,
totalRepeatHyphens: number,
): ICodeBuilder {
return this.appendLine(`hyphens-around-${totalRepeatHyphens} | Section name: ${sectionName} | hyphens-around-${totalRepeatHyphens}`);
}
public appendFunction(name: string, code: string): ICodeBuilder {
return this
.appendLine(`Function | Name: ${name}`)
.appendLine(`Function | Code: ${code}`);
}
public toString(): string {
return this.text;
}
}