diff --git a/src/application/Parser/Script/Compiler/Expressions/ExpressionsCompiler.ts b/src/application/Parser/Script/Compiler/Expressions/ExpressionsCompiler.ts index a4898f47..8f8503cc 100644 --- a/src/application/Parser/Script/Compiler/Expressions/ExpressionsCompiler.ts +++ b/src/application/Parser/Script/Compiler/Expressions/ExpressionsCompiler.ts @@ -10,11 +10,14 @@ export class ExpressionsCompiler implements IExpressionsCompiler { public constructor( private readonly extractor: IExpressionParser = new CompositeExpressionParser()) { } public compileExpressions( - code: string, + code: string | undefined, args: IReadOnlyFunctionCallArgumentCollection): string { if (!args) { throw new Error('undefined args, send empty collection instead'); } + if (!code) { + return code; + } const expressions = this.extractor.findExpressions(code); ensureParamsUsedInCodeHasArgsProvided(expressions, args); const context = new ExpressionEvaluationContext(args); diff --git a/src/application/Parser/Script/Compiler/Expressions/IExpressionsCompiler.ts b/src/application/Parser/Script/Compiler/Expressions/IExpressionsCompiler.ts index f73e8471..0703c20f 100644 --- a/src/application/Parser/Script/Compiler/Expressions/IExpressionsCompiler.ts +++ b/src/application/Parser/Script/Compiler/Expressions/IExpressionsCompiler.ts @@ -2,6 +2,6 @@ import { IReadOnlyFunctionCallArgumentCollection } from '../Function/Call/Argume export interface IExpressionsCompiler { compileExpressions( - code: string, + code: string | undefined, args: IReadOnlyFunctionCallArgumentCollection): string; } diff --git a/src/application/Parser/Script/Compiler/Expressions/Parser/Regex/RegexParser.ts b/src/application/Parser/Script/Compiler/Expressions/Parser/Regex/RegexParser.ts index 7e3eb178..3754bf20 100644 --- a/src/application/Parser/Script/Compiler/Expressions/Parser/Regex/RegexParser.ts +++ b/src/application/Parser/Script/Compiler/Expressions/Parser/Regex/RegexParser.ts @@ -15,6 +15,9 @@ export abstract class RegexParser implements IExpressionParser { protected abstract buildExpression(match: RegExpMatchArray): IPrimitiveExpression; private* findRegexExpressions(code: string): Iterable { + if (!code) { + throw new Error('undefined code'); + } const matches = Array.from(code.matchAll(this.regex)); for (const match of matches) { const startPos = match.index; diff --git a/tests/unit/application/Parser/Script/Compiler/Expressions/ExpressionsCompiler.spec.ts b/tests/unit/application/Parser/Script/Compiler/Expressions/ExpressionsCompiler.spec.ts index d89bcc77..1f893960 100644 --- a/tests/unit/application/Parser/Script/Compiler/Expressions/ExpressionsCompiler.spec.ts +++ b/tests/unit/application/Parser/Script/Compiler/Expressions/ExpressionsCompiler.spec.ts @@ -8,6 +8,28 @@ import { FunctionCallArgumentCollectionStub } from '@tests/unit/stubs/FunctionCa describe('ExpressionsCompiler', () => { describe('compileExpressions', () => { + describe('returns code when it is empty or undefined', () => { + // arrange + const testCases = [{ + name: 'empty', + value: '', + }, { + name: 'undefined', + value: undefined, + }, + ]; + for (const test of testCases) { + it(`given ${test.name}`, () => { + const expected = test.value; + const sut = new SystemUnderTest(); + const args = new FunctionCallArgumentCollectionStub(); + // act + const value = sut.compileExpressions(test.value, args); + // assert + expect(value).to.equal(expected); + }); + } + }); describe('combines expressions as expected', () => { // arrange const code = 'part1 {{ a }} part2 {{ b }} part3'; @@ -49,7 +71,7 @@ describe('ExpressionsCompiler', () => { const expressionParserMock = new ExpressionParserStub() .withResult(testCase.expressions); const args = new FunctionCallArgumentCollectionStub(); - const sut = new MockableExpressionsCompiler(expressionParserMock); + const sut = new SystemUnderTest(expressionParserMock); // act const actual = sut.compileExpressions(code, args); // assert @@ -69,7 +91,7 @@ describe('ExpressionsCompiler', () => { ]; const expressionParserMock = new ExpressionParserStub() .withResult(expressions); - const sut = new MockableExpressionsCompiler(expressionParserMock); + const sut = new SystemUnderTest(expressionParserMock); // act sut.compileExpressions(code, expected); // assert @@ -83,7 +105,7 @@ describe('ExpressionsCompiler', () => { const expectedError = 'undefined args, send empty collection instead'; const args = undefined; const expressionParserMock = new ExpressionParserStub(); - const sut = new MockableExpressionsCompiler(expressionParserMock); + const sut = new SystemUnderTest(expressionParserMock); // act const act = () => sut.compileExpressions('code', args); // assert @@ -135,7 +157,7 @@ describe('ExpressionsCompiler', () => { const code = 'non-important-code'; const expressionParserMock = new ExpressionParserStub() .withResult(testCase.expressions); - const sut = new MockableExpressionsCompiler(expressionParserMock); + const sut = new SystemUnderTest(expressionParserMock); // act const act = () => sut.compileExpressions(code, testCase.args); // assert @@ -147,7 +169,7 @@ describe('ExpressionsCompiler', () => { // arrange const expected = 'expected-code'; const expressionParserMock = new ExpressionParserStub(); - const sut = new MockableExpressionsCompiler(expressionParserMock); + const sut = new SystemUnderTest(expressionParserMock); const args = new FunctionCallArgumentCollectionStub(); // act sut.compileExpressions(expected, args); @@ -158,8 +180,8 @@ describe('ExpressionsCompiler', () => { }); }); -class MockableExpressionsCompiler extends ExpressionsCompiler { - constructor(extractor: IExpressionParser) { +class SystemUnderTest extends ExpressionsCompiler { + constructor(extractor: IExpressionParser = new ExpressionParserStub()) { super(extractor); } } diff --git a/tests/unit/application/Parser/Script/Compiler/Expressions/Parser/Regex/RegexParser.spec.ts b/tests/unit/application/Parser/Script/Compiler/Expressions/Parser/Regex/RegexParser.spec.ts index e7f47a84..ac94bebb 100644 --- a/tests/unit/application/Parser/Script/Compiler/Expressions/Parser/Regex/RegexParser.spec.ts +++ b/tests/unit/application/Parser/Script/Compiler/Expressions/Parser/Regex/RegexParser.spec.ts @@ -7,6 +7,30 @@ import { FunctionParameterStub } from '@tests/unit/stubs/FunctionParameterStub'; describe('RegexParser', () => { describe('findExpressions', () => { + describe('throws when code is unexpected', () => { + // arrange + const testCases = [ + { + name: 'undefined', + value: undefined, + expectedError: 'undefined code', + }, + { + name: 'empty', + value: '', + expectedError: 'undefined code', + }, + ]; + for (const testCase of testCases) { + it(`given ${testCase.name}`, () => { + const sut = new RegexParserConcrete(/unimportant/); + // act + const act = () => sut.findExpressions(testCase.value); + // assert + expect(act).to.throw(testCase.expectedError); + }); + } + }); describe('matches regex as expected', () => { // arrange const testCases = [