- Unify test data for nonexistence of an object/string and collection. - Introduce more test through adding missing test data to existing tests. - Improve logic for checking absence of values to match tests. - Add missing tests for absent value validation. - Update documentation to include shared test functionality.
189 lines
7.7 KiB
TypeScript
189 lines
7.7 KiB
TypeScript
import 'mocha';
|
|
import { expect } from 'chai';
|
|
import { ExpressionsCompiler } from '@/application/Parser/Script/Compiler/Expressions/ExpressionsCompiler';
|
|
import { IExpressionParser } from '@/application/Parser/Script/Compiler/Expressions/Parser/IExpressionParser';
|
|
import { ExpressionStub } from '@tests/unit/stubs/ExpressionStub';
|
|
import { ExpressionParserStub } from '@tests/unit/stubs/ExpressionParserStub';
|
|
import { FunctionCallArgumentCollectionStub } from '@tests/unit/stubs/FunctionCallArgumentCollectionStub';
|
|
import { itEachAbsentObjectValue, itEachAbsentStringValue } from '@tests/unit/shared/TestCases/AbsentTests';
|
|
|
|
describe('ExpressionsCompiler', () => {
|
|
describe('compileExpressions', () => {
|
|
describe('returns code when it is absent', () => {
|
|
itEachAbsentStringValue((absentValue) => {
|
|
// arrange
|
|
const expected = absentValue;
|
|
const sut = new SystemUnderTest();
|
|
const args = new FunctionCallArgumentCollectionStub();
|
|
// act
|
|
const value = sut.compileExpressions(absentValue, args);
|
|
// assert
|
|
expect(value).to.equal(expected);
|
|
});
|
|
});
|
|
describe('combines expressions as expected', () => {
|
|
// arrange
|
|
const code = 'part1 {{ a }} part2 {{ b }} part3';
|
|
const testCases = [
|
|
{
|
|
name: 'with ordered expressions',
|
|
expressions: [
|
|
new ExpressionStub().withPosition(6, 13).withEvaluatedResult('a'),
|
|
new ExpressionStub().withPosition(20, 27).withEvaluatedResult('b'),
|
|
],
|
|
expected: 'part1 a part2 b part3',
|
|
},
|
|
{
|
|
name: 'unordered expressions',
|
|
expressions: [
|
|
new ExpressionStub().withPosition(20, 27).withEvaluatedResult('b'),
|
|
new ExpressionStub().withPosition(6, 13).withEvaluatedResult('a'),
|
|
],
|
|
expected: 'part1 a part2 b part3',
|
|
},
|
|
{
|
|
name: 'with an optional expected argument that is not provided',
|
|
expressions: [
|
|
new ExpressionStub().withPosition(6, 13).withEvaluatedResult('a')
|
|
.withParameterNames(['optionalParameter'], true),
|
|
new ExpressionStub().withPosition(20, 27).withEvaluatedResult('b')
|
|
.withParameterNames(['optionalParameterTwo'], true),
|
|
],
|
|
expected: 'part1 a part2 b part3',
|
|
},
|
|
{
|
|
name: 'with no expressions',
|
|
expressions: [],
|
|
expected: code,
|
|
},
|
|
];
|
|
for (const testCase of testCases) {
|
|
it(testCase.name, () => {
|
|
const expressionParserMock = new ExpressionParserStub()
|
|
.withResult(testCase.expressions);
|
|
const args = new FunctionCallArgumentCollectionStub();
|
|
const sut = new SystemUnderTest(expressionParserMock);
|
|
// act
|
|
const actual = sut.compileExpressions(code, args);
|
|
// assert
|
|
expect(actual).to.equal(testCase.expected);
|
|
});
|
|
}
|
|
});
|
|
describe('arguments', () => {
|
|
it('passes arguments to expressions as expected', () => {
|
|
// arrange
|
|
const expected = new FunctionCallArgumentCollectionStub()
|
|
.withArgument('test-arg', 'test-value');
|
|
const code = 'non-important';
|
|
const expressions = [
|
|
new ExpressionStub(),
|
|
new ExpressionStub(),
|
|
];
|
|
const expressionParserMock = new ExpressionParserStub()
|
|
.withResult(expressions);
|
|
const sut = new SystemUnderTest(expressionParserMock);
|
|
// act
|
|
sut.compileExpressions(code, expected);
|
|
// assert
|
|
expect(expressions[0].callHistory).to.have.lengthOf(1);
|
|
expect(expressions[0].callHistory[0].args).to.equal(expected);
|
|
expect(expressions[1].callHistory).to.have.lengthOf(1);
|
|
expect(expressions[1].callHistory[0].args).to.equal(expected);
|
|
});
|
|
describe('throws if arguments is missing', () => {
|
|
itEachAbsentObjectValue((absentValue) => {
|
|
// arrange
|
|
const expectedError = 'missing args, send empty collection instead.';
|
|
const args = absentValue;
|
|
const expressionParserMock = new ExpressionParserStub();
|
|
const sut = new SystemUnderTest(expressionParserMock);
|
|
// act
|
|
const act = () => sut.compileExpressions('code', args);
|
|
// assert
|
|
expect(act).to.throw(expectedError);
|
|
});
|
|
});
|
|
});
|
|
describe('throws when expected argument is not provided but used in code', () => {
|
|
// arrange
|
|
const testCases = [
|
|
{
|
|
name: 'empty parameters',
|
|
expressions: [
|
|
new ExpressionStub().withParameterNames(['parameter'], false),
|
|
],
|
|
args: new FunctionCallArgumentCollectionStub(),
|
|
expectedError: 'parameter value(s) not provided for: "parameter" but used in code',
|
|
},
|
|
{
|
|
name: 'unnecessary parameter is provided',
|
|
expressions: [
|
|
new ExpressionStub().withParameterNames(['parameter'], false),
|
|
],
|
|
args: new FunctionCallArgumentCollectionStub()
|
|
.withArgument('unnecessaryParameter', 'unnecessaryValue'),
|
|
expectedError: 'parameter value(s) not provided for: "parameter" but used in code',
|
|
},
|
|
{
|
|
name: 'multiple values are not provided',
|
|
expressions: [
|
|
new ExpressionStub().withParameterNames(['parameter1'], false),
|
|
new ExpressionStub().withParameterNames(['parameter2', 'parameter3'], false),
|
|
],
|
|
args: new FunctionCallArgumentCollectionStub(),
|
|
expectedError: 'parameter value(s) not provided for: "parameter1", "parameter2", "parameter3" but used in code',
|
|
},
|
|
{
|
|
name: 'some values are provided',
|
|
expressions: [
|
|
new ExpressionStub().withParameterNames(['parameter1'], false),
|
|
new ExpressionStub().withParameterNames(['parameter2', 'parameter3'], false),
|
|
],
|
|
args: new FunctionCallArgumentCollectionStub()
|
|
.withArgument('parameter2', 'value'),
|
|
expectedError: 'parameter value(s) not provided for: "parameter1", "parameter3" but used in code',
|
|
},
|
|
{
|
|
name: 'parameter names are not repeated in error message',
|
|
expressions: [
|
|
new ExpressionStub().withParameterNames(['parameter1', 'parameter1', 'parameter2', 'parameter2'], false),
|
|
],
|
|
args: new FunctionCallArgumentCollectionStub(),
|
|
expectedError: 'parameter value(s) not provided for: "parameter1", "parameter2" but used in code',
|
|
},
|
|
];
|
|
for (const testCase of testCases) {
|
|
it(testCase.name, () => {
|
|
const code = 'non-important-code';
|
|
const expressionParserMock = new ExpressionParserStub()
|
|
.withResult(testCase.expressions);
|
|
const sut = new SystemUnderTest(expressionParserMock);
|
|
// act
|
|
const act = () => sut.compileExpressions(code, testCase.args);
|
|
// assert
|
|
expect(act).to.throw(testCase.expectedError);
|
|
});
|
|
}
|
|
});
|
|
it('calls parser with expected code', () => {
|
|
// arrange
|
|
const expected = 'expected-code';
|
|
const expressionParserMock = new ExpressionParserStub();
|
|
const sut = new SystemUnderTest(expressionParserMock);
|
|
const args = new FunctionCallArgumentCollectionStub();
|
|
// act
|
|
sut.compileExpressions(expected, args);
|
|
// assert
|
|
expect(expressionParserMock.callHistory).to.have.lengthOf(1);
|
|
expect(expressionParserMock.callHistory[0]).to.equal(expected);
|
|
});
|
|
});
|
|
});
|
|
|
|
class SystemUnderTest extends ExpressionsCompiler {
|
|
constructor(extractor: IExpressionParser = new ExpressionParserStub()) {
|
|
super(extractor);
|
|
}
|
|
}
|