Add validation for max line length in compiler
This commit adds validation logic in compiler to check for max allowed characters per line for scripts. This allows preventing bugs caused by limitation of terminal emulators. Other supporting changes: - Rename/refactor related code for clarity and better maintainability. - Drop `I` prefix from interfaces to align with latest convention. - Refactor CodeValidator to be functional rather than object-oriented for simplicity. - Refactor syntax definition construction to be functional and be part of rule for better separation of concerns. - Refactored validation logic to use an enum-based factory pattern for improved maintainability and scalability.
This commit is contained in:
@@ -1,34 +1,86 @@
|
||||
import { expect } from 'vitest';
|
||||
import type { Constructible } from '@/TypeHelpers';
|
||||
import type { ICodeValidationRule } from '@/application/Parser/Executable/Script/Validation/ICodeValidationRule';
|
||||
import type { ICodeValidator } from '@/application/Parser/Executable/Script/Validation/ICodeValidator';
|
||||
import type { CodeValidator } from '@/application/Parser/Executable/Script/Validation/CodeValidator';
|
||||
import { ScriptingLanguage } from '@/domain/ScriptingLanguage';
|
||||
import type { CodeValidationRule } from '@/application/Parser/Executable/Script/Validation/CodeValidationRule';
|
||||
import { formatAssertionMessage } from '@tests/shared/FormatAssertionMessage';
|
||||
|
||||
export class CodeValidatorStub implements ICodeValidator {
|
||||
public callHistory = new Array<{
|
||||
code: string,
|
||||
rules: readonly ICodeValidationRule[],
|
||||
}>();
|
||||
export class CodeValidatorStub {
|
||||
public callHistory = new Array<Parameters<CodeValidator>>();
|
||||
|
||||
public throwIfInvalid(
|
||||
code: string,
|
||||
rules: readonly ICodeValidationRule[],
|
||||
): void {
|
||||
this.callHistory.push({
|
||||
code,
|
||||
rules: Array.from(rules),
|
||||
});
|
||||
public get(): CodeValidator {
|
||||
return (...args) => {
|
||||
this.callHistory.push(args);
|
||||
};
|
||||
}
|
||||
|
||||
public assertHistory(expectation: {
|
||||
validatedCodes: readonly (string | undefined)[],
|
||||
rules: readonly Constructible<ICodeValidationRule>[],
|
||||
}) {
|
||||
expect(this.callHistory).to.have.lengthOf(expectation.validatedCodes.length);
|
||||
const actualValidatedCodes = this.callHistory.map((args) => args.code);
|
||||
expect(actualValidatedCodes.sort()).deep.equal([...expectation.validatedCodes].sort());
|
||||
for (const call of this.callHistory) {
|
||||
const actualRules = call.rules.map((rule) => rule.constructor);
|
||||
expect(actualRules.sort()).to.deep.equal([...expectation.rules].sort());
|
||||
}
|
||||
public assertValidatedCodes(
|
||||
validatedCodes: readonly string[],
|
||||
) {
|
||||
expectExpectedCodes(this, validatedCodes);
|
||||
}
|
||||
|
||||
public assertValidatedRules(
|
||||
rules: readonly CodeValidationRule[],
|
||||
) {
|
||||
expectExpectedRules(this, rules);
|
||||
}
|
||||
|
||||
public assertValidatedLanguage(
|
||||
language: ScriptingLanguage,
|
||||
) {
|
||||
expectExpectedLanguage(this, language);
|
||||
}
|
||||
}
|
||||
|
||||
function expectExpectedCodes(
|
||||
validator: CodeValidatorStub,
|
||||
expectedCodes: readonly string[],
|
||||
): void {
|
||||
expect(validator.callHistory).to.have.lengthOf(expectedCodes.length, formatAssertionMessage([
|
||||
'Mismatch in number of validated codes',
|
||||
`Expected: ${expectedCodes.length}`,
|
||||
`Actual: ${validator.callHistory.length}`,
|
||||
]));
|
||||
const actualValidatedCodes = validator.callHistory.map((args) => {
|
||||
const [code] = args;
|
||||
return code;
|
||||
});
|
||||
expect(actualValidatedCodes).to.have.members(expectedCodes, formatAssertionMessage([
|
||||
'Mismatch in validated codes',
|
||||
`Expected: ${JSON.stringify(expectedCodes)}`,
|
||||
`Actual: ${JSON.stringify(actualValidatedCodes)}`,
|
||||
]));
|
||||
}
|
||||
|
||||
function expectExpectedRules(
|
||||
validator: CodeValidatorStub,
|
||||
expectedRules: readonly CodeValidationRule[],
|
||||
): void {
|
||||
for (const call of validator.callHistory) {
|
||||
const [,,actualRules] = call;
|
||||
expect(actualRules).to.have.lengthOf(expectedRules.length, formatAssertionMessage([
|
||||
'Mismatch in number of validation rules for a call.',
|
||||
`Expected: ${expectedRules.length}`,
|
||||
`Actual: ${actualRules.length}`,
|
||||
]));
|
||||
expect(actualRules).to.have.members(expectedRules, formatAssertionMessage([
|
||||
'Mismatch in validation rules for for a call.',
|
||||
`Expected: ${JSON.stringify(expectedRules)}`,
|
||||
`Actual: ${JSON.stringify(actualRules)}`,
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
function expectExpectedLanguage(
|
||||
validator: CodeValidatorStub,
|
||||
expectedLanguage: ScriptingLanguage,
|
||||
): void {
|
||||
for (const call of validator.callHistory) {
|
||||
const [,language] = call;
|
||||
expect(language).to.equal(expectedLanguage, formatAssertionMessage([
|
||||
'Mismatch in scripting language',
|
||||
`Expected: ${ScriptingLanguage[expectedLanguage]}`,
|
||||
`Actual: ${ScriptingLanguage[language]}`,
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user