Add type validation for parameters and fix types

This commit introduces type validation for parameter values within the
parser/compiler, aligning with the YAML schema. It aims to eliminate
dependencies on side effects in the collection files.

This update changes the treatment of data types in the Windows
collection, moving away from unintended type casting by the compiler.
Previously, numeric and boolean values were used even though only
string types were supported. This behavior was unstable and untested,
and has now been adjusted to use strings exclusively.

Changes ensure that parameter values are correctly validated
as strings, enhancing stability and maintainability.
This commit is contained in:
undergroundwires
2024-06-19 17:01:27 +02:00
parent 48761f62a2
commit fac26a6ca0
43 changed files with 873 additions and 466 deletions

View File

@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest';
import { createTypeValidator } from '@/application/Parser/Common/TypeValidator';
import { itEachAbsentObjectValue } from '@tests/unit/shared/TestCases/AbsentTests';
import { createTypeValidator, type NonEmptyStringAssertion, type RegexValidationRule } from '@/application/Parser/Common/TypeValidator';
import { itEachAbsentObjectValue, itEachAbsentStringValue } from '@tests/unit/shared/TestCases/AbsentTests';
describe('createTypeValidator', () => {
describe('assertObject', () => {
@@ -146,6 +146,108 @@ describe('createTypeValidator', () => {
});
});
});
describe('assertNonEmptyString', () => {
describe('with valid string', () => {
it('accepts non-empty string without regex rule', () => {
// arrange
const nonEmptyString = 'hello';
const { assertNonEmptyString } = createTypeValidator();
// act
const act = () => assertNonEmptyString({ value: nonEmptyString, valueName: 'unimportant name' });
// assert
expect(act).to.not.throw();
});
it('accepts if the string matches the regex', () => {
// arrange
const regex: RegExp = /goodbye/;
const stringMatchingRegex = 'Valid string containing "goodbye"';
const rule: RegexValidationRule = {
expectedMatch: regex,
errorMessage: 'String contain "goodbye"',
};
const { assertNonEmptyString } = createTypeValidator();
// act
const act = () => assertNonEmptyString({
value: stringMatchingRegex,
valueName: 'unimportant name',
rule,
});
// assert
expect(act).to.not.throw();
});
});
describe('with invalid string', () => {
describe('throws error for missing string', () => {
itEachAbsentStringValue((absentValue) => {
// arrange
const valueName = 'absent string value';
const expectedMessage = `'${valueName}' is missing.`;
const { assertNonEmptyString } = createTypeValidator();
// act
const act = () => assertNonEmptyString({ value: absentValue, valueName });
// assert
expect(act).to.throw(expectedMessage);
});
});
describe('throws error for non string values', () => {
// arrange
const testScenarios: readonly {
readonly description: string;
readonly invalidValue: unknown;
}[] = [
{
description: 'number',
invalidValue: 42,
},
{
description: 'boolean',
invalidValue: true,
},
{
description: 'object',
invalidValue: { property: 'value' },
},
{
description: 'array',
invalidValue: ['a', 'r', 'r', 'a', 'y'],
},
];
testScenarios.forEach(({
description, invalidValue,
}) => {
it(description, () => {
const valueName = 'invalidValue';
const expectedMessage = `'${valueName}' should be of type 'string', but is of type '${typeof invalidValue}'.`;
const { assertNonEmptyString } = createTypeValidator();
// act
const act = () => assertNonEmptyString({ value: invalidValue, valueName });
// assert
expect(act).to.throw(expectedMessage);
});
});
});
it('throws an error if the string does not match the regex', () => {
// arrange
const regex: RegExp = /goodbye/;
const stringNotMatchingRegex = 'Hello';
const expectedMessage = 'String should contain "goodbye"';
const rule: RegexValidationRule = {
expectedMatch: regex,
errorMessage: expectedMessage,
};
const assertion: NonEmptyStringAssertion = {
value: stringNotMatchingRegex,
valueName: 'non-important-value-name',
rule,
};
const { assertNonEmptyString } = createTypeValidator();
// act
const act = () => assertNonEmptyString(assertion);
// assert
expect(act).to.throw(expectedMessage);
});
});
});
});
function createObjectWithProperties(properties: readonly string[]): object {