Fix failing of functions without revert code
Add missing empty/undefined handling to fix a bug where defining new functions without `revertCode:` fails.
This commit is contained in:
@@ -10,11 +10,14 @@ export class ExpressionsCompiler implements IExpressionsCompiler {
|
|||||||
public constructor(
|
public constructor(
|
||||||
private readonly extractor: IExpressionParser = new CompositeExpressionParser()) { }
|
private readonly extractor: IExpressionParser = new CompositeExpressionParser()) { }
|
||||||
public compileExpressions(
|
public compileExpressions(
|
||||||
code: string,
|
code: string | undefined,
|
||||||
args: IReadOnlyFunctionCallArgumentCollection): string {
|
args: IReadOnlyFunctionCallArgumentCollection): string {
|
||||||
if (!args) {
|
if (!args) {
|
||||||
throw new Error('undefined args, send empty collection instead');
|
throw new Error('undefined args, send empty collection instead');
|
||||||
}
|
}
|
||||||
|
if (!code) {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
const expressions = this.extractor.findExpressions(code);
|
const expressions = this.extractor.findExpressions(code);
|
||||||
ensureParamsUsedInCodeHasArgsProvided(expressions, args);
|
ensureParamsUsedInCodeHasArgsProvided(expressions, args);
|
||||||
const context = new ExpressionEvaluationContext(args);
|
const context = new ExpressionEvaluationContext(args);
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ import { IReadOnlyFunctionCallArgumentCollection } from '../Function/Call/Argume
|
|||||||
|
|
||||||
export interface IExpressionsCompiler {
|
export interface IExpressionsCompiler {
|
||||||
compileExpressions(
|
compileExpressions(
|
||||||
code: string,
|
code: string | undefined,
|
||||||
args: IReadOnlyFunctionCallArgumentCollection): string;
|
args: IReadOnlyFunctionCallArgumentCollection): string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ export abstract class RegexParser implements IExpressionParser {
|
|||||||
protected abstract buildExpression(match: RegExpMatchArray): IPrimitiveExpression;
|
protected abstract buildExpression(match: RegExpMatchArray): IPrimitiveExpression;
|
||||||
|
|
||||||
private* findRegexExpressions(code: string): Iterable<IExpression> {
|
private* findRegexExpressions(code: string): Iterable<IExpression> {
|
||||||
|
if (!code) {
|
||||||
|
throw new Error('undefined code');
|
||||||
|
}
|
||||||
const matches = Array.from(code.matchAll(this.regex));
|
const matches = Array.from(code.matchAll(this.regex));
|
||||||
for (const match of matches) {
|
for (const match of matches) {
|
||||||
const startPos = match.index;
|
const startPos = match.index;
|
||||||
|
|||||||
@@ -8,6 +8,28 @@ import { FunctionCallArgumentCollectionStub } from '@tests/unit/stubs/FunctionCa
|
|||||||
|
|
||||||
describe('ExpressionsCompiler', () => {
|
describe('ExpressionsCompiler', () => {
|
||||||
describe('compileExpressions', () => {
|
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', () => {
|
describe('combines expressions as expected', () => {
|
||||||
// arrange
|
// arrange
|
||||||
const code = 'part1 {{ a }} part2 {{ b }} part3';
|
const code = 'part1 {{ a }} part2 {{ b }} part3';
|
||||||
@@ -49,7 +71,7 @@ describe('ExpressionsCompiler', () => {
|
|||||||
const expressionParserMock = new ExpressionParserStub()
|
const expressionParserMock = new ExpressionParserStub()
|
||||||
.withResult(testCase.expressions);
|
.withResult(testCase.expressions);
|
||||||
const args = new FunctionCallArgumentCollectionStub();
|
const args = new FunctionCallArgumentCollectionStub();
|
||||||
const sut = new MockableExpressionsCompiler(expressionParserMock);
|
const sut = new SystemUnderTest(expressionParserMock);
|
||||||
// act
|
// act
|
||||||
const actual = sut.compileExpressions(code, args);
|
const actual = sut.compileExpressions(code, args);
|
||||||
// assert
|
// assert
|
||||||
@@ -69,7 +91,7 @@ describe('ExpressionsCompiler', () => {
|
|||||||
];
|
];
|
||||||
const expressionParserMock = new ExpressionParserStub()
|
const expressionParserMock = new ExpressionParserStub()
|
||||||
.withResult(expressions);
|
.withResult(expressions);
|
||||||
const sut = new MockableExpressionsCompiler(expressionParserMock);
|
const sut = new SystemUnderTest(expressionParserMock);
|
||||||
// act
|
// act
|
||||||
sut.compileExpressions(code, expected);
|
sut.compileExpressions(code, expected);
|
||||||
// assert
|
// assert
|
||||||
@@ -83,7 +105,7 @@ describe('ExpressionsCompiler', () => {
|
|||||||
const expectedError = 'undefined args, send empty collection instead';
|
const expectedError = 'undefined args, send empty collection instead';
|
||||||
const args = undefined;
|
const args = undefined;
|
||||||
const expressionParserMock = new ExpressionParserStub();
|
const expressionParserMock = new ExpressionParserStub();
|
||||||
const sut = new MockableExpressionsCompiler(expressionParserMock);
|
const sut = new SystemUnderTest(expressionParserMock);
|
||||||
// act
|
// act
|
||||||
const act = () => sut.compileExpressions('code', args);
|
const act = () => sut.compileExpressions('code', args);
|
||||||
// assert
|
// assert
|
||||||
@@ -135,7 +157,7 @@ describe('ExpressionsCompiler', () => {
|
|||||||
const code = 'non-important-code';
|
const code = 'non-important-code';
|
||||||
const expressionParserMock = new ExpressionParserStub()
|
const expressionParserMock = new ExpressionParserStub()
|
||||||
.withResult(testCase.expressions);
|
.withResult(testCase.expressions);
|
||||||
const sut = new MockableExpressionsCompiler(expressionParserMock);
|
const sut = new SystemUnderTest(expressionParserMock);
|
||||||
// act
|
// act
|
||||||
const act = () => sut.compileExpressions(code, testCase.args);
|
const act = () => sut.compileExpressions(code, testCase.args);
|
||||||
// assert
|
// assert
|
||||||
@@ -147,7 +169,7 @@ describe('ExpressionsCompiler', () => {
|
|||||||
// arrange
|
// arrange
|
||||||
const expected = 'expected-code';
|
const expected = 'expected-code';
|
||||||
const expressionParserMock = new ExpressionParserStub();
|
const expressionParserMock = new ExpressionParserStub();
|
||||||
const sut = new MockableExpressionsCompiler(expressionParserMock);
|
const sut = new SystemUnderTest(expressionParserMock);
|
||||||
const args = new FunctionCallArgumentCollectionStub();
|
const args = new FunctionCallArgumentCollectionStub();
|
||||||
// act
|
// act
|
||||||
sut.compileExpressions(expected, args);
|
sut.compileExpressions(expected, args);
|
||||||
@@ -158,8 +180,8 @@ describe('ExpressionsCompiler', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
class MockableExpressionsCompiler extends ExpressionsCompiler {
|
class SystemUnderTest extends ExpressionsCompiler {
|
||||||
constructor(extractor: IExpressionParser) {
|
constructor(extractor: IExpressionParser = new ExpressionParserStub()) {
|
||||||
super(extractor);
|
super(extractor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,30 @@ import { FunctionParameterStub } from '@tests/unit/stubs/FunctionParameterStub';
|
|||||||
|
|
||||||
describe('RegexParser', () => {
|
describe('RegexParser', () => {
|
||||||
describe('findExpressions', () => {
|
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', () => {
|
describe('matches regex as expected', () => {
|
||||||
// arrange
|
// arrange
|
||||||
const testCases = [
|
const testCases = [
|
||||||
|
|||||||
Reference in New Issue
Block a user