Major refactoring using ESLint with rules from AirBnb and Vue. Enable most of the ESLint rules and do necessary linting in the code. Also add more information for rules that are disabled to describe what they are and why they are disabled. Allow logging (`console.log`) in test files, and in development mode (e.g. when working with `npm run serve`), but disable it when environment is production (as pre-configured by Vue). Also add flag (`--mode production`) in `lint:eslint` command so production linting is executed earlier in lifecycle. Disable rules that requires a separate work. Such as ESLint rules that are broken in TypeScript: no-useless-constructor (eslint/eslint#14118) and no-shadow (eslint/eslint#13014).
261 lines
8.3 KiB
TypeScript
261 lines
8.3 KiB
TypeScript
import 'mocha';
|
|
import { expect } from 'chai';
|
|
import { IReadOnlyFunctionParameterCollection } from '@/application/Parser/Script/Compiler/Function/Parameter/IFunctionParameterCollection';
|
|
import { FunctionParameterCollectionStub } from '@tests/unit/stubs/FunctionParameterCollectionStub';
|
|
import { createCallerFunction, createFunctionWithInlineCode } from '@/application/Parser/Script/Compiler/Function/SharedFunction';
|
|
import { IFunctionCall } from '@/application/Parser/Script/Compiler/Function/Call/IFunctionCall';
|
|
import { FunctionCallStub } from '@tests/unit/stubs/FunctionCallStub';
|
|
import { FunctionBodyType, ISharedFunction } from '@/application/Parser/Script/Compiler/Function/ISharedFunction';
|
|
|
|
describe('SharedFunction', () => {
|
|
describe('name', () => {
|
|
runForEachFactoryMethod((build) => {
|
|
it('sets as expected', () => {
|
|
// arrange
|
|
const expected = 'expected-function-name';
|
|
const builder = new SharedFunctionBuilder()
|
|
.withName(expected);
|
|
// act
|
|
const sut = build(builder);
|
|
// assert
|
|
expect(sut.name).equal(expected);
|
|
});
|
|
it('throws if empty or undefined', () => {
|
|
// arrange
|
|
const expectedError = 'undefined function name';
|
|
const invalidValues = [undefined, ''];
|
|
for (const invalidValue of invalidValues) {
|
|
const builder = new SharedFunctionBuilder()
|
|
.withName(invalidValue);
|
|
// act
|
|
const act = () => build(builder);
|
|
// assert
|
|
expect(act).to.throw(expectedError);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
describe('parameters', () => {
|
|
runForEachFactoryMethod((build) => {
|
|
it('sets as expected', () => {
|
|
// arrange
|
|
const expected = new FunctionParameterCollectionStub()
|
|
.withParameterName('test-parameter');
|
|
const builder = new SharedFunctionBuilder()
|
|
.withParameters(expected);
|
|
// act
|
|
const sut = build(builder);
|
|
// assert
|
|
expect(sut.parameters).equal(expected);
|
|
});
|
|
it('throws if undefined', () => {
|
|
// arrange
|
|
const expectedError = 'undefined parameters';
|
|
const parameters = undefined;
|
|
const builder = new SharedFunctionBuilder()
|
|
.withParameters(parameters);
|
|
// act
|
|
const act = () => build(builder);
|
|
// assert
|
|
expect(act).to.throw(expectedError);
|
|
});
|
|
});
|
|
});
|
|
describe('body', () => {
|
|
describe('createFunctionWithInlineCode', () => {
|
|
describe('code', () => {
|
|
it('sets as expected', () => {
|
|
// arrange
|
|
const expected = 'expected-code';
|
|
// act
|
|
const sut = new SharedFunctionBuilder()
|
|
.withCode(expected)
|
|
.createFunctionWithInlineCode();
|
|
// assert
|
|
expect(sut.body.code.do).equal(expected);
|
|
});
|
|
it('throws if empty or undefined', () => {
|
|
// arrange
|
|
const functionName = 'expected-function-name';
|
|
const expectedError = `undefined code in function "${functionName}"`;
|
|
const invalidValues = [undefined, ''];
|
|
for (const invalidValue of invalidValues) {
|
|
// act
|
|
const act = () => new SharedFunctionBuilder()
|
|
.withName(functionName)
|
|
.withCode(invalidValue)
|
|
.createFunctionWithInlineCode();
|
|
// assert
|
|
expect(act).to.throw(expectedError);
|
|
}
|
|
});
|
|
});
|
|
describe('revertCode', () => {
|
|
it('sets as expected', () => {
|
|
// arrange
|
|
const testData = ['expected-revert-code', undefined, ''];
|
|
for (const data of testData) {
|
|
// act
|
|
const sut = new SharedFunctionBuilder()
|
|
.withRevertCode(data)
|
|
.createFunctionWithInlineCode();
|
|
// assert
|
|
expect(sut.body.code.revert).equal(data);
|
|
}
|
|
});
|
|
});
|
|
it('sets type as expected', () => {
|
|
// arrange
|
|
const expectedType = FunctionBodyType.Code;
|
|
// act
|
|
const sut = new SharedFunctionBuilder()
|
|
.createFunctionWithInlineCode();
|
|
// assert
|
|
expect(sut.body.type).equal(expectedType);
|
|
});
|
|
it('calls are undefined', () => {
|
|
// arrange
|
|
const expectedCalls = undefined;
|
|
// act
|
|
const sut = new SharedFunctionBuilder()
|
|
.createFunctionWithInlineCode();
|
|
// assert
|
|
expect(sut.body.calls).equal(expectedCalls);
|
|
});
|
|
});
|
|
describe('createCallerFunction', () => {
|
|
describe('callSequence', () => {
|
|
it('sets as expected', () => {
|
|
// arrange
|
|
const expected = [
|
|
new FunctionCallStub().withFunctionName('firstFunction'),
|
|
new FunctionCallStub().withFunctionName('secondFunction'),
|
|
];
|
|
// act
|
|
const sut = new SharedFunctionBuilder()
|
|
.withCallSequence(expected)
|
|
.createCallerFunction();
|
|
// assert
|
|
expect(sut.body.calls).equal(expected);
|
|
});
|
|
it('throws if undefined', () => {
|
|
// arrange
|
|
const functionName = 'invalidFunction';
|
|
const callSequence = undefined;
|
|
const expectedError = `undefined call sequence in function "${functionName}"`;
|
|
// act
|
|
const act = () => new SharedFunctionBuilder()
|
|
.withName(functionName)
|
|
.withCallSequence(callSequence)
|
|
.createCallerFunction();
|
|
// assert
|
|
expect(act).to.throw(expectedError);
|
|
});
|
|
it('throws if empty', () => {
|
|
// arrange
|
|
const functionName = 'invalidFunction';
|
|
const callSequence = [];
|
|
const expectedError = `empty call sequence in function "${functionName}"`;
|
|
// act
|
|
const act = () => new SharedFunctionBuilder()
|
|
.withName(functionName)
|
|
.withCallSequence(callSequence)
|
|
.createCallerFunction();
|
|
// assert
|
|
expect(act).to.throw(expectedError);
|
|
});
|
|
});
|
|
it('sets type as expected', () => {
|
|
// arrange
|
|
const expectedType = FunctionBodyType.Calls;
|
|
// act
|
|
const sut = new SharedFunctionBuilder()
|
|
.createCallerFunction();
|
|
// assert
|
|
expect(sut.body.type).equal(expectedType);
|
|
});
|
|
it('code is undefined', () => {
|
|
// arrange
|
|
const expectedCode = undefined;
|
|
// act
|
|
const sut = new SharedFunctionBuilder()
|
|
.createCallerFunction();
|
|
// assert
|
|
expect(sut.body.code).equal(expectedCode);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
function runForEachFactoryMethod(
|
|
act: (action: (sut: SharedFunctionBuilder) => ISharedFunction) => void,
|
|
): void {
|
|
describe('createCallerFunction', () => {
|
|
const action = (builder: SharedFunctionBuilder) => builder.createCallerFunction();
|
|
act(action);
|
|
});
|
|
describe('createFunctionWithInlineCode', () => {
|
|
const action = (builder: SharedFunctionBuilder) => builder.createFunctionWithInlineCode();
|
|
act(action);
|
|
});
|
|
}
|
|
|
|
/*
|
|
Using an abstraction here allows for easy refactorings in
|
|
parameters or moving between functional and object-oriented
|
|
solutions without refactorings all tests.
|
|
*/
|
|
class SharedFunctionBuilder {
|
|
private name = 'name';
|
|
|
|
private parameters: IReadOnlyFunctionParameterCollection = new FunctionParameterCollectionStub();
|
|
|
|
private callSequence: readonly IFunctionCall[] = [new FunctionCallStub()];
|
|
|
|
private code = 'code';
|
|
|
|
private revertCode = 'revert-code';
|
|
|
|
public createCallerFunction(): ISharedFunction {
|
|
return createCallerFunction(
|
|
this.name,
|
|
this.parameters,
|
|
this.callSequence,
|
|
);
|
|
}
|
|
|
|
public createFunctionWithInlineCode(): ISharedFunction {
|
|
return createFunctionWithInlineCode(
|
|
this.name,
|
|
this.parameters,
|
|
this.code,
|
|
this.revertCode,
|
|
);
|
|
}
|
|
|
|
public withName(name: string) {
|
|
this.name = name;
|
|
return this;
|
|
}
|
|
|
|
public withParameters(parameters: IReadOnlyFunctionParameterCollection) {
|
|
this.parameters = parameters;
|
|
return this;
|
|
}
|
|
|
|
public withCode(code: string) {
|
|
this.code = code;
|
|
return this;
|
|
}
|
|
|
|
public withRevertCode(revertCode: string) {
|
|
this.revertCode = revertCode;
|
|
return this;
|
|
}
|
|
|
|
public withCallSequence(callSequence: readonly IFunctionCall[]) {
|
|
this.callSequence = callSequence;
|
|
return this;
|
|
}
|
|
}
|