win: fix incomplete VSCEIP, location scripts
This commit improves the validation logic in parser, corrects Windows collection files to adhere to expected structure. This validation helps catch errors that previously led to incomplete generated code in scripts for disabling VSCEIP and location settings. Changes: - Add type validation for function call structures in the parser/compiler. This helps prevent runtime errors by ensuring that only correctly structured data is processed. - Fix scripts in the Windows collection that previoulsy had incomplete `code` or `revertCode` values. These corrections ensure that the scripts function as intended. - Refactor related logic within the compiler/parser to improve testability and maintainability.
This commit is contained in:
@@ -1,84 +0,0 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { parseFunctionCalls } from '@/application/Parser/Executable/Script/Compiler/Function/Call/FunctionCallParser';
|
||||
import { FunctionCallDataStub } from '@tests/unit/shared/Stubs/FunctionCallDataStub';
|
||||
import { itEachAbsentStringValue } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
|
||||
describe('FunctionCallParser', () => {
|
||||
describe('parseFunctionCalls', () => {
|
||||
it('throws if call is not an object', () => {
|
||||
// arrange
|
||||
const expectedError = 'called function(s) must be an object';
|
||||
const invalidCalls = ['string', 33, false];
|
||||
invalidCalls.forEach((invalidCall) => {
|
||||
// act
|
||||
const act = () => parseFunctionCalls(invalidCall as never);
|
||||
// assert
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
});
|
||||
describe('throws if call sequence has undefined function name', () => {
|
||||
itEachAbsentStringValue((absentValue) => {
|
||||
// arrange
|
||||
const expectedError = 'missing function name in function call';
|
||||
const data = [
|
||||
new FunctionCallDataStub().withName('function-name'),
|
||||
new FunctionCallDataStub().withName(absentValue),
|
||||
];
|
||||
// act
|
||||
const act = () => parseFunctionCalls(data);
|
||||
// assert
|
||||
expect(act).to.throw(expectedError);
|
||||
}, { excludeNull: true, excludeUndefined: true });
|
||||
});
|
||||
it('parses single call as expected', () => {
|
||||
// arrange
|
||||
const expectedFunctionName = 'functionName';
|
||||
const expectedParameterName = 'parameterName';
|
||||
const expectedArgumentValue = 'argumentValue';
|
||||
const data = new FunctionCallDataStub()
|
||||
.withName(expectedFunctionName)
|
||||
.withParameters({ [expectedParameterName]: expectedArgumentValue });
|
||||
// act
|
||||
const actual = parseFunctionCalls(data);
|
||||
// assert
|
||||
expect(actual).to.have.lengthOf(1);
|
||||
const call = actual[0];
|
||||
expect(call.functionName).to.equal(expectedFunctionName);
|
||||
const { args } = call;
|
||||
expect(args.getAllParameterNames()).to.have.lengthOf(1);
|
||||
expect(args.hasArgument(expectedParameterName)).to.equal(
|
||||
true,
|
||||
`Does not include expected parameter: "${expectedParameterName}"\n`
|
||||
+ `But includes: "${args.getAllParameterNames()}"`,
|
||||
);
|
||||
const argument = args.getArgument(expectedParameterName);
|
||||
expect(argument.parameterName).to.equal(expectedParameterName);
|
||||
expect(argument.argumentValue).to.equal(expectedArgumentValue);
|
||||
});
|
||||
it('parses multiple calls as expected', () => {
|
||||
// arrange
|
||||
const getFunctionName = (index: number) => `functionName${index}`;
|
||||
const getParameterName = (index: number) => `parameterName${index}`;
|
||||
const getArgumentValue = (index: number) => `argumentValue${index}`;
|
||||
const createCall = (index: number) => new FunctionCallDataStub()
|
||||
.withName(getFunctionName(index))
|
||||
.withParameters({ [getParameterName(index)]: getArgumentValue(index) });
|
||||
const calls = [createCall(0), createCall(1), createCall(2), createCall(3)];
|
||||
// act
|
||||
const actual = parseFunctionCalls(calls);
|
||||
// assert
|
||||
expect(actual).to.have.lengthOf(calls.length);
|
||||
for (let i = 0; i < calls.length; i++) {
|
||||
const call = actual[i];
|
||||
const expectedParameterName = getParameterName(i);
|
||||
const expectedArgumentValue = getArgumentValue(i);
|
||||
expect(call.functionName).to.equal(getFunctionName(i));
|
||||
expect(call.args.getAllParameterNames()).to.have.lengthOf(1);
|
||||
expect(call.args.hasArgument(expectedParameterName)).to.equal(true);
|
||||
const argument = call.args.getArgument(expectedParameterName);
|
||||
expect(argument.parameterName).to.equal(expectedParameterName);
|
||||
expect(argument.argumentValue).to.equal(expectedArgumentValue);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,197 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import type { FunctionCallsData, FunctionCallData } from '@/application/collections/';
|
||||
import { parseFunctionCalls } from '@/application/Parser/Executable/Script/Compiler/Function/Call/FunctionCallsParser';
|
||||
import { FunctionCallDataStub } from '@tests/unit/shared/Stubs/FunctionCallDataStub';
|
||||
import { itEachAbsentStringValue } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
import type { NonEmptyCollectionAssertion, ObjectAssertion, TypeValidator } from '@/application/Parser/Common/TypeValidator';
|
||||
import { TypeValidatorStub } from '@tests/unit/shared/Stubs/TypeValidatorStub';
|
||||
|
||||
describe('FunctionCallsParser', () => {
|
||||
describe('parseFunctionCalls', () => {
|
||||
describe('throws if single call is not an object or array', () => {
|
||||
// arrange
|
||||
const expectedError = 'called function(s) must be an object or array';
|
||||
const testScenarios: readonly {
|
||||
readonly description: string;
|
||||
readonly invalidData: FunctionCallsData;
|
||||
}[] = [
|
||||
{
|
||||
description: 'given a string',
|
||||
invalidData: 'string' as unknown as FunctionCallsData,
|
||||
},
|
||||
{
|
||||
description: 'given a number',
|
||||
invalidData: 33 as unknown as FunctionCallsData,
|
||||
},
|
||||
{
|
||||
description: 'given a boolean',
|
||||
invalidData: false as unknown as FunctionCallsData,
|
||||
},
|
||||
{
|
||||
description: 'given null',
|
||||
invalidData: null as unknown as FunctionCallsData,
|
||||
},
|
||||
{
|
||||
description: 'given undefined',
|
||||
invalidData: undefined as unknown as FunctionCallsData,
|
||||
},
|
||||
];
|
||||
testScenarios.forEach(({ description, invalidData }) => {
|
||||
it(description, () => {
|
||||
const context = new TestContext()
|
||||
.withData(invalidData);
|
||||
// act
|
||||
const act = () => context.parse();
|
||||
// assert
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('given a single call', () => {
|
||||
it('validates single call as object', () => {
|
||||
// arrange
|
||||
const data = new FunctionCallDataStub();
|
||||
const expectedAssertion: ObjectAssertion<FunctionCallData> = {
|
||||
value: data,
|
||||
valueName: 'function call',
|
||||
allowedProperties: [
|
||||
'function', 'parameters',
|
||||
],
|
||||
};
|
||||
const validator = new TypeValidatorStub();
|
||||
const context = new TestContext()
|
||||
.withData(data)
|
||||
.withTypeValidator(validator);
|
||||
// act
|
||||
context.parse();
|
||||
// assert
|
||||
validator.expectObjectAssertion(expectedAssertion);
|
||||
});
|
||||
it('parses single call as expected', () => {
|
||||
// arrange
|
||||
const expectedFunctionName = 'functionName';
|
||||
const expectedParameterName = 'parameterName';
|
||||
const expectedArgumentValue = 'argumentValue';
|
||||
const data = new FunctionCallDataStub()
|
||||
.withName(expectedFunctionName)
|
||||
.withParameters({ [expectedParameterName]: expectedArgumentValue });
|
||||
// act
|
||||
const actual = parseFunctionCalls(data);
|
||||
// assert
|
||||
expect(actual).to.have.lengthOf(1);
|
||||
const call = actual[0];
|
||||
expect(call.functionName).to.equal(expectedFunctionName);
|
||||
const { args } = call;
|
||||
expect(args.getAllParameterNames()).to.have.lengthOf(1);
|
||||
expect(args.hasArgument(expectedParameterName)).to.equal(
|
||||
true,
|
||||
`Does not include expected parameter: "${expectedParameterName}"\n`
|
||||
+ `But includes: "${args.getAllParameterNames()}"`,
|
||||
);
|
||||
const argument = args.getArgument(expectedParameterName);
|
||||
expect(argument.parameterName).to.equal(expectedParameterName);
|
||||
expect(argument.argumentValue).to.equal(expectedArgumentValue);
|
||||
});
|
||||
});
|
||||
describe('given a call sequence', () => {
|
||||
describe('throws if call sequence has undefined function name', () => {
|
||||
itEachAbsentStringValue((absentValue) => {
|
||||
// arrange
|
||||
const expectedError = 'missing function name in function call';
|
||||
const data = [
|
||||
new FunctionCallDataStub().withName('function-name'),
|
||||
new FunctionCallDataStub().withName(absentValue),
|
||||
];
|
||||
// act
|
||||
const act = () => parseFunctionCalls(data);
|
||||
// assert
|
||||
expect(act).to.throw(expectedError);
|
||||
}, { excludeNull: true, excludeUndefined: true });
|
||||
});
|
||||
it('validates call sequence as non empty collection', () => {
|
||||
// arrange
|
||||
const data: FunctionCallsData = [new FunctionCallDataStub()];
|
||||
const expectedAssertion: NonEmptyCollectionAssertion = {
|
||||
value: data,
|
||||
valueName: 'function call sequence',
|
||||
};
|
||||
const validator = new TypeValidatorStub();
|
||||
const context = new TestContext()
|
||||
.withData(data)
|
||||
.withTypeValidator(validator);
|
||||
// act
|
||||
context.parse();
|
||||
// assert
|
||||
validator.expectNonEmptyCollectionAssertion(expectedAssertion);
|
||||
});
|
||||
it('validates a call in call sequence as object', () => {
|
||||
// arrange
|
||||
const expectedValidatedCallData = new FunctionCallDataStub();
|
||||
const data: FunctionCallsData = [expectedValidatedCallData];
|
||||
const expectedAssertion: ObjectAssertion<FunctionCallData> = {
|
||||
value: expectedValidatedCallData,
|
||||
valueName: 'function call',
|
||||
allowedProperties: [
|
||||
'function', 'parameters',
|
||||
],
|
||||
};
|
||||
const validator = new TypeValidatorStub();
|
||||
const context = new TestContext()
|
||||
.withData(data)
|
||||
.withTypeValidator(validator);
|
||||
// act
|
||||
context.parse();
|
||||
// assert
|
||||
validator.expectObjectAssertion(expectedAssertion);
|
||||
});
|
||||
it('parses multiple calls as expected', () => {
|
||||
// arrange
|
||||
const getFunctionName = (index: number) => `functionName${index}`;
|
||||
const getParameterName = (index: number) => `parameterName${index}`;
|
||||
const getArgumentValue = (index: number) => `argumentValue${index}`;
|
||||
const createCall = (index: number) => new FunctionCallDataStub()
|
||||
.withName(getFunctionName(index))
|
||||
.withParameters({ [getParameterName(index)]: getArgumentValue(index) });
|
||||
const calls = [createCall(0), createCall(1), createCall(2), createCall(3)];
|
||||
// act
|
||||
const actual = parseFunctionCalls(calls);
|
||||
// assert
|
||||
expect(actual).to.have.lengthOf(calls.length);
|
||||
for (let i = 0; i < calls.length; i++) {
|
||||
const call = actual[i];
|
||||
const expectedParameterName = getParameterName(i);
|
||||
const expectedArgumentValue = getArgumentValue(i);
|
||||
expect(call.functionName).to.equal(getFunctionName(i));
|
||||
expect(call.args.getAllParameterNames()).to.have.lengthOf(1);
|
||||
expect(call.args.hasArgument(expectedParameterName)).to.equal(true);
|
||||
const argument = call.args.getArgument(expectedParameterName);
|
||||
expect(argument.parameterName).to.equal(expectedParameterName);
|
||||
expect(argument.argumentValue).to.equal(expectedArgumentValue);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
class TestContext {
|
||||
private validator: TypeValidator = new TypeValidatorStub();
|
||||
|
||||
private calls: FunctionCallsData = [new FunctionCallDataStub()];
|
||||
|
||||
public withTypeValidator(typeValidator: TypeValidator): this {
|
||||
this.validator = typeValidator;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withData(calls: FunctionCallsData): this {
|
||||
this.calls = calls;
|
||||
return this;
|
||||
}
|
||||
|
||||
public parse(): ReturnType<typeof parseFunctionCalls> {
|
||||
return parseFunctionCalls(
|
||||
this.calls,
|
||||
this.validator,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user