Refactor to enforce strictNullChecks
This commit applies `strictNullChecks` to the entire codebase to improve maintainability and type safety. Key changes include: - Remove some explicit null-checks where unnecessary. - Add necessary null-checks. - Refactor static factory functions for a more functional approach. - Improve some test names and contexts for better debugging. - Add unit tests for any additional logic introduced. - Refactor `createPositionFromRegexFullMatch` to its own function as the logic is reused. - Prefer `find` prefix on functions that may return `undefined` and `get` prefix for those that always return a value.
This commit is contained in:
@@ -3,6 +3,7 @@ import { ICategoryCollection } from '@/domain/ICategoryCollection';
|
||||
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||
import { IProjectInformation } from '@/domain/IProjectInformation';
|
||||
import { ProjectInformationStub } from './ProjectInformationStub';
|
||||
import { CategoryCollectionStub } from './CategoryCollectionStub';
|
||||
|
||||
export class ApplicationStub implements IApplication {
|
||||
public info: IProjectInformation = new ProjectInformationStub();
|
||||
@@ -10,24 +11,25 @@ export class ApplicationStub implements IApplication {
|
||||
public collections: ICategoryCollection[] = [];
|
||||
|
||||
public getCollection(operatingSystem: OperatingSystem): ICategoryCollection {
|
||||
return this.collections.find((collection) => collection.os === operatingSystem);
|
||||
const collection = this.collections.find((c) => c.os === operatingSystem);
|
||||
return collection ?? new CategoryCollectionStub();
|
||||
}
|
||||
|
||||
public getSupportedOsList(): OperatingSystem[] {
|
||||
return this.collections.map((collection) => collection.os);
|
||||
}
|
||||
|
||||
public withCollection(collection: ICategoryCollection): ApplicationStub {
|
||||
public withCollection(collection: ICategoryCollection): this {
|
||||
this.collections.push(collection);
|
||||
return this;
|
||||
}
|
||||
|
||||
public withProjectInformation(info: IProjectInformation): ApplicationStub {
|
||||
public withProjectInformation(info: IProjectInformation): this {
|
||||
this.info = info;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withCollections(...collections: readonly ICategoryCollection[]): ApplicationStub {
|
||||
public withCollections(...collections: readonly ICategoryCollection[]): this {
|
||||
this.collections.push(...collections);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -24,10 +24,11 @@ export class CategoryCollectionParserStub {
|
||||
}
|
||||
|
||||
public getStub(): CategoryCollectionParserType {
|
||||
return (data: CollectionData, info: IProjectInformation) => {
|
||||
return (data: CollectionData, info: IProjectInformation): ICategoryCollection => {
|
||||
this.arguments.push({ data, info });
|
||||
if (this.returnValues.has(data)) {
|
||||
return this.returnValues.get(data);
|
||||
const foundReturnValue = this.returnValues.get(data);
|
||||
if (foundReturnValue) {
|
||||
return foundReturnValue;
|
||||
}
|
||||
// Get next OS with a unique OS so mock does not result in an invalid app due to duplicated OS
|
||||
// collections.
|
||||
|
||||
@@ -6,6 +6,7 @@ import { ICategoryCollection } from '@/domain/ICategoryCollection';
|
||||
import { RecommendationLevel } from '@/domain/RecommendationLevel';
|
||||
import { ScriptStub } from './ScriptStub';
|
||||
import { ScriptingDefinitionStub } from './ScriptingDefinitionStub';
|
||||
import { CategoryStub } from './CategoryStub';
|
||||
|
||||
export class CategoryCollectionStub implements ICategoryCollection {
|
||||
public scripting: IScriptingDefinition = new ScriptingDefinitionStub();
|
||||
@@ -20,34 +21,35 @@ export class CategoryCollectionStub implements ICategoryCollection {
|
||||
|
||||
public readonly actions = new Array<ICategory>();
|
||||
|
||||
public withAction(category: ICategory): CategoryCollectionStub {
|
||||
public withAction(category: ICategory): this {
|
||||
this.actions.push(category);
|
||||
return this;
|
||||
}
|
||||
|
||||
public withOs(os: OperatingSystem): CategoryCollectionStub {
|
||||
public withOs(os: OperatingSystem): this {
|
||||
this.os = os;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withScripting(scripting: IScriptingDefinition): CategoryCollectionStub {
|
||||
public withScripting(scripting: IScriptingDefinition): this {
|
||||
this.scripting = scripting;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withInitialScript(script: IScript): CategoryCollectionStub {
|
||||
public withInitialScript(script: IScript): this {
|
||||
this.initialScript = script;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withTotalScripts(totalScripts: number) {
|
||||
public withTotalScripts(totalScripts: number): this {
|
||||
this.totalScripts = totalScripts;
|
||||
return this;
|
||||
}
|
||||
|
||||
public findCategory(categoryId: number): ICategory {
|
||||
public getCategory(categoryId: number): ICategory {
|
||||
return this.getAllCategories()
|
||||
.find((category) => category.id === categoryId);
|
||||
.find((category) => category.id === categoryId)
|
||||
?? new CategoryStub(categoryId);
|
||||
}
|
||||
|
||||
public getScriptsByLevel(level: RecommendationLevel): readonly IScript[] {
|
||||
@@ -55,9 +57,10 @@ export class CategoryCollectionStub implements ICategoryCollection {
|
||||
.filter((script) => script.level !== undefined && script.level <= level);
|
||||
}
|
||||
|
||||
public findScript(scriptId: string): IScript {
|
||||
public getScript(scriptId: string): IScript {
|
||||
return this.getAllScripts()
|
||||
.find((script) => scriptId === script.id);
|
||||
.find((script) => scriptId === script.id)
|
||||
?? new ScriptStub(scriptId);
|
||||
}
|
||||
|
||||
public getAllScripts(): ReadonlyArray<IScript> {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { CategoryData, CategoryOrScriptData, DocumentationData } from '@/application/collections/';
|
||||
import { ScriptDataStub } from './ScriptDataStub';
|
||||
import { createScriptDataWithCode } from '@tests/unit/shared/Stubs/ScriptDataStub';
|
||||
|
||||
export class CategoryDataStub implements CategoryData {
|
||||
public children: readonly CategoryOrScriptData[] = [ScriptDataStub.createWithCode()];
|
||||
public children: readonly CategoryOrScriptData[] = [createScriptDataWithCode()];
|
||||
|
||||
public category = 'category name';
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { BaseEntity } from '@/infrastructure/Entity/BaseEntity';
|
||||
import { ICategory, IScript } from '@/domain/ICategory';
|
||||
import { RecommendationLevel } from '@/domain/RecommendationLevel';
|
||||
import { ScriptStub } from './ScriptStub';
|
||||
|
||||
export class CategoryStub extends BaseEntity<number> implements ICategory {
|
||||
@@ -26,37 +27,44 @@ export class CategoryStub extends BaseEntity<number> implements ICategory {
|
||||
];
|
||||
}
|
||||
|
||||
public withScriptIds(...scriptIds: string[]): CategoryStub {
|
||||
public withScriptIds(...scriptIds: string[]): this {
|
||||
return this.withScripts(
|
||||
...scriptIds.map((id) => new ScriptStub(id)),
|
||||
);
|
||||
}
|
||||
|
||||
public withScripts(...scripts: IScript[]): CategoryStub {
|
||||
public withScripts(...scripts: IScript[]): this {
|
||||
for (const script of scripts) {
|
||||
this.withScript(script);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public withCategories(...categories: ICategory[]): CategoryStub {
|
||||
public withMandatoryScripts(): this {
|
||||
return this
|
||||
.withScript(new ScriptStub(`[${CategoryStub.name}] script-1`).withLevel(RecommendationLevel.Standard))
|
||||
.withScript(new ScriptStub(`[${CategoryStub.name}] script-2`).withLevel(RecommendationLevel.Strict))
|
||||
.withScript(new ScriptStub(`[${CategoryStub.name}] script-3`).withLevel(undefined));
|
||||
}
|
||||
|
||||
public withCategories(...categories: ICategory[]): this {
|
||||
for (const category of categories) {
|
||||
this.withCategory(category);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public withCategory(category: ICategory): CategoryStub {
|
||||
public withCategory(category: ICategory): this {
|
||||
this.subCategories.push(category);
|
||||
return this;
|
||||
}
|
||||
|
||||
public withScript(script: IScript): CategoryStub {
|
||||
public withScript(script: IScript): this {
|
||||
this.scripts.push(script);
|
||||
return this;
|
||||
}
|
||||
|
||||
public withName(categoryName: string) {
|
||||
public withName(categoryName: string): this {
|
||||
this.name = categoryName;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export class CodeValidatorStub implements ICodeValidator {
|
||||
}
|
||||
|
||||
public assertHistory(expected: {
|
||||
validatedCodes: readonly string[],
|
||||
validatedCodes: readonly (string | undefined)[],
|
||||
rules: readonly Constructible<ICodeValidationRule>[],
|
||||
}) {
|
||||
expect(this.callHistory).to.have.lengthOf(expected.validatedCodes.length);
|
||||
|
||||
@@ -3,6 +3,7 @@ import type {
|
||||
} from '@/application/collections/';
|
||||
import { RecommendationLevel } from '@/domain/RecommendationLevel';
|
||||
import { ScriptingLanguage } from '@/domain/ScriptingLanguage';
|
||||
import { createScriptDataWithCode } from './ScriptDataStub';
|
||||
|
||||
export class CollectionDataStub implements CollectionData {
|
||||
public os = 'windows';
|
||||
@@ -13,17 +14,17 @@ export class CollectionDataStub implements CollectionData {
|
||||
|
||||
public functions?: ReadonlyArray<FunctionData>;
|
||||
|
||||
public withActions(actions: readonly CategoryData[]): CollectionDataStub {
|
||||
public withActions(actions: readonly CategoryData[]): this {
|
||||
this.actions = actions;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withOs(os: string): CollectionDataStub {
|
||||
public withOs(os: string): this {
|
||||
this.os = os;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withScripting(scripting: ScriptingDefinitionData): CollectionDataStub {
|
||||
public withScripting(scripting: ScriptingDefinitionData): this {
|
||||
this.scripting = scripting;
|
||||
return this;
|
||||
}
|
||||
@@ -57,11 +58,7 @@ function getScriptStub(
|
||||
scriptName: string,
|
||||
level: RecommendationLevel = RecommendationLevel.Standard,
|
||||
): ScriptData {
|
||||
return {
|
||||
name: scriptName,
|
||||
code: 'script code',
|
||||
revertCode: 'revert code',
|
||||
recommend: RecommendationLevel[level].toLowerCase(),
|
||||
call: undefined,
|
||||
};
|
||||
return createScriptDataWithCode()
|
||||
.withName(scriptName)
|
||||
.withRecommend(RecommendationLevel[level].toLowerCase());
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DelayScheduler } from '@/presentation/components/Scripts/View/Tree/TreeView/Rendering/DelayScheduler';
|
||||
|
||||
export class DelaySchedulerStub implements DelayScheduler {
|
||||
public nextCallback: () => void | undefined = undefined;
|
||||
public nextCallback: (() => void) | undefined = undefined;
|
||||
|
||||
public scheduleNext(callback: () => void): void {
|
||||
this.nextCallback = callback;
|
||||
|
||||
@@ -20,8 +20,9 @@ export class ExpressionParserStub implements IExpressionParser {
|
||||
|
||||
public findExpressions(code: string): IExpression[] {
|
||||
this.callHistory.push(code);
|
||||
if (this.results.has(code)) {
|
||||
return [...this.results.get(code)];
|
||||
const foundResult = this.results.get(code);
|
||||
if (foundResult) {
|
||||
return [...foundResult];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export class ExpressionStub implements IExpression {
|
||||
|
||||
public parameters: IReadOnlyFunctionParameterCollection = new FunctionParameterCollectionStub();
|
||||
|
||||
private result: string = undefined;
|
||||
private result = `[${ExpressionStub.name}] result`;
|
||||
|
||||
public withParameters(parameters: IReadOnlyFunctionParameterCollection) {
|
||||
this.parameters = parameters;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { IExpressionsCompiler } from '@/application/Parser/Script/Compiler/Expressions/IExpressionsCompiler';
|
||||
import { IReadOnlyFunctionCallArgumentCollection } from '@/application/Parser/Script/Compiler/Function/Call/Argument/IFunctionCallArgumentCollection';
|
||||
import { scrambledEqual } from '@/application/Common/Array';
|
||||
import { ISharedFunction } from '@/application/Parser/Script/Compiler/Function/ISharedFunction';
|
||||
import { FunctionBodyType, ISharedFunction } from '@/application/Parser/Script/Compiler/Function/ISharedFunction';
|
||||
import { FunctionCallArgumentCollectionStub } from '@tests/unit/shared/Stubs/FunctionCallArgumentCollectionStub';
|
||||
import { StubWithObservableMethodCalls } from './StubWithObservableMethodCalls';
|
||||
|
||||
@@ -10,7 +10,7 @@ export class ExpressionsCompilerStub
|
||||
implements IExpressionsCompiler {
|
||||
private readonly scenarios = new Array<ExpressionCompilationScenario>();
|
||||
|
||||
public setup(scenario: ExpressionCompilationScenario): ExpressionsCompilerStub {
|
||||
public setup(scenario: ExpressionCompilationScenario): this {
|
||||
this.scenarios.push(scenario);
|
||||
return this;
|
||||
}
|
||||
@@ -18,10 +18,22 @@ export class ExpressionsCompilerStub
|
||||
public setupToReturnFunctionCode(
|
||||
func: ISharedFunction,
|
||||
givenArgs: FunctionCallArgumentCollectionStub,
|
||||
) {
|
||||
return this
|
||||
.setup({ givenCode: func.body.code.execute, givenArgs, result: func.body.code.execute })
|
||||
.setup({ givenCode: func.body.code.revert, givenArgs, result: func.body.code.revert });
|
||||
): this {
|
||||
if (func.body.type !== FunctionBodyType.Code) {
|
||||
throw new Error('not a code body');
|
||||
}
|
||||
if (func.body.code.revert) {
|
||||
this.setup({
|
||||
givenCode: func.body.code.revert,
|
||||
givenArgs,
|
||||
result: func.body.code.revert,
|
||||
});
|
||||
}
|
||||
return this.setup({
|
||||
givenCode: func.body.code.execute,
|
||||
givenArgs,
|
||||
result: func.body.code.execute,
|
||||
});
|
||||
}
|
||||
|
||||
public compileExpressions(
|
||||
@@ -42,7 +54,7 @@ export class ExpressionsCompilerStub
|
||||
.getAllParameterNames()
|
||||
.map((name) => `${name}=${parameters.getArgument(name).argumentValue}`)
|
||||
.join('\n\t');
|
||||
return `[ExpressionsCompilerStub]\ncode: "${code}"\nparameters: ${parametersAndValues}`;
|
||||
return `[${ExpressionsCompilerStub.name}]\ncode: "${code}"\nparameters: ${parametersAndValues}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,12 +12,12 @@ export class FileSystemOpsStub
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public createDirectory(directoryPath: string, isRecursive?: boolean): Promise<string> {
|
||||
public createDirectory(directoryPath: string, isRecursive?: boolean): Promise<void> {
|
||||
this.registerMethodCall({
|
||||
methodName: 'createDirectory',
|
||||
args: [directoryPath, isRecursive],
|
||||
});
|
||||
return Promise.resolve(directoryPath);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public writeToFile(filePath: string, data: string): Promise<void> {
|
||||
|
||||
@@ -1,26 +1,35 @@
|
||||
import { FilterActionType } from '@/application/Context/State/Filter/Event/FilterActionType';
|
||||
import { IFilterChangeDetails, IFilterChangeDetailsVisitor } from '@/application/Context/State/Filter/Event/IFilterChangeDetails';
|
||||
import { FilterAction, IFilterChangeDetails, IFilterChangeDetailsVisitor } from '@/application/Context/State/Filter/Event/IFilterChangeDetails';
|
||||
import { IFilterResult } from '@/application/Context/State/Filter/IFilterResult';
|
||||
|
||||
export class FilterChangeDetailsStub implements IFilterChangeDetails {
|
||||
public static forApply(filter: IFilterResult) {
|
||||
return new FilterChangeDetailsStub(FilterActionType.Apply, filter);
|
||||
return new FilterChangeDetailsStub({
|
||||
type: FilterActionType.Apply,
|
||||
filter,
|
||||
});
|
||||
}
|
||||
|
||||
public static forClear() {
|
||||
return new FilterChangeDetailsStub(FilterActionType.Clear);
|
||||
return new FilterChangeDetailsStub({
|
||||
type: FilterActionType.Clear,
|
||||
});
|
||||
}
|
||||
|
||||
private constructor(
|
||||
public actionType: FilterActionType,
|
||||
public filter?: IFilterResult,
|
||||
public readonly action: FilterAction,
|
||||
) { /* Private constructor to enforce factory methods */ }
|
||||
|
||||
visit(visitor: IFilterChangeDetailsVisitor): void {
|
||||
if (this.filter) {
|
||||
visitor.onApply(this.filter);
|
||||
} else {
|
||||
visitor.onClear();
|
||||
if (this.action.type === FilterActionType.Apply) {
|
||||
if (visitor.onApply) {
|
||||
visitor.onApply(this.action.filter);
|
||||
}
|
||||
}
|
||||
if (this.action.type === FilterActionType.Clear) {
|
||||
if (visitor.onClear) {
|
||||
visitor.onClear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@ import { IFunctionCode } from '@/application/Parser/Script/Compiler/Function/ISh
|
||||
export class FunctionCodeStub implements IFunctionCode {
|
||||
public execute = 'execute code (function-code-stub)';
|
||||
|
||||
public revert? = 'revert code (function-code-stub)';
|
||||
public revert: string | undefined = 'revert code (function-code-stub)';
|
||||
|
||||
public withExecute(code: string) {
|
||||
this.execute = code;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withRevert(revert: string) {
|
||||
public withRevert(revert: string | undefined) {
|
||||
this.revert = revert;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,39 +1,60 @@
|
||||
import type { FunctionData, ParameterDefinitionData, FunctionCallsData } from '@/application/collections/';
|
||||
import type {
|
||||
ParameterDefinitionData, CodeFunctionData,
|
||||
FunctionCallsData, CallFunctionData,
|
||||
} from '@/application/collections/';
|
||||
import { FunctionCallDataStub } from './FunctionCallDataStub';
|
||||
|
||||
export class FunctionDataStub implements FunctionData {
|
||||
public static createWithCode() {
|
||||
return new FunctionDataStub()
|
||||
.withCode('stub-code')
|
||||
.withRevertCode('stub-revert-code');
|
||||
}
|
||||
export function createFunctionDataWithCode(): FunctionDataStub {
|
||||
const instance = new FunctionDataStub()
|
||||
.withCode('stub-code')
|
||||
.withRevertCode('stub-revert-code');
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static createWithCall(call?: FunctionCallsData) {
|
||||
let instance = new FunctionDataStub();
|
||||
if (call) {
|
||||
instance = instance.withCall(call);
|
||||
} else {
|
||||
instance = instance.withMockCall();
|
||||
}
|
||||
return instance;
|
||||
export function createFunctionDataWithCall(
|
||||
call?: FunctionCallsData,
|
||||
): FunctionDataStub {
|
||||
let instance = new FunctionDataStub();
|
||||
if (call) {
|
||||
instance = instance.withCall(call);
|
||||
} else {
|
||||
instance = instance.withMockCall();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static createWithoutCallOrCodes() {
|
||||
return new FunctionDataStub();
|
||||
}
|
||||
export function createFunctionDataWithoutCallOrCode(): FunctionDataStub {
|
||||
return new FunctionDataStub();
|
||||
}
|
||||
|
||||
interface FunctionDataBuilder<T> {
|
||||
withName(name: string): T;
|
||||
withParameters(...parameters: readonly ParameterDefinitionData[]): T;
|
||||
withParametersObject(parameters: readonly ParameterDefinitionData[]): T;
|
||||
}
|
||||
|
||||
interface CodeFunctionDataBuilder extends FunctionDataBuilder<CodeFunctionDataBuilder> {
|
||||
withCode(code: string): this;
|
||||
withRevertCode(revertCode: string): this;
|
||||
}
|
||||
|
||||
interface CallFunctionDataBuilder extends FunctionDataBuilder<CallFunctionDataBuilder> {
|
||||
withCall(call: FunctionCallsData): this;
|
||||
withMockCall(): this;
|
||||
}
|
||||
|
||||
class FunctionDataStub
|
||||
implements CodeFunctionDataBuilder, CallFunctionDataBuilder, CallFunctionData, CodeFunctionData {
|
||||
public name = 'functionDataStub';
|
||||
|
||||
public code: string;
|
||||
|
||||
public revertCode: string;
|
||||
public revertCode?: string;
|
||||
|
||||
public call?: FunctionCallsData;
|
||||
public call: FunctionCallsData;
|
||||
|
||||
public parameters?: readonly ParameterDefinitionData[];
|
||||
|
||||
private constructor() { /* use static factory methods to create an instance */ }
|
||||
|
||||
public withName(name: string) {
|
||||
this.name = name;
|
||||
return this;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ILanguageSyntax } from '@/application/Parser/Script/Validation/Syntax/ILanguageSyntax';
|
||||
|
||||
export class LanguageSyntaxStub implements ILanguageSyntax {
|
||||
public commentDelimiters = [];
|
||||
public commentDelimiters: string[] = [];
|
||||
|
||||
public commonCodeParts = [];
|
||||
public commonCodeParts: string[] = [];
|
||||
|
||||
public withCommentDelimiters(...delimiters: string[]) {
|
||||
this.commentDelimiters = delimiters;
|
||||
|
||||
@@ -24,14 +24,16 @@ export class LocationOpsStub
|
||||
methodName: 'combinePaths',
|
||||
args: pathSegments,
|
||||
});
|
||||
if (this.sequence.length > 0) {
|
||||
return this.sequence.pop();
|
||||
const nextInSequence = this.sequence.pop();
|
||||
if (nextInSequence) {
|
||||
return nextInSequence;
|
||||
}
|
||||
const key = LocationOpsStub.getScenarioKey(pathSegments);
|
||||
if (!this.scenarios.has(key)) {
|
||||
return pathSegments.join('/PATH-SEGMENT-SEPARATOR/');
|
||||
const foundScenario = this.scenarios.get(key);
|
||||
if (foundScenario) {
|
||||
return foundScenario;
|
||||
}
|
||||
return this.scenarios.get(key);
|
||||
return pathSegments.join('/PATH-SEGMENT-SEPARATOR/');
|
||||
}
|
||||
|
||||
private static getScenarioKey(paths: string[]): string {
|
||||
|
||||
@@ -9,7 +9,7 @@ export class NodeMetadataStub implements NodeMetadata {
|
||||
|
||||
public readonly docs: readonly string[] = [];
|
||||
|
||||
public children?: readonly NodeMetadata[] = [];
|
||||
public children: readonly NodeMetadata[] = [];
|
||||
|
||||
public readonly type: NodeType = NodeType.Category;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ export class NodeStateChangeEventArgsStub implements NodeStateChangeEventArgs {
|
||||
return this;
|
||||
}
|
||||
|
||||
public withOldState(oldState: TreeNodeStateDescriptor): this {
|
||||
public withOldState(oldState: TreeNodeStateDescriptor | undefined): this {
|
||||
this.oldState = oldState;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -13,9 +13,6 @@ export class PipeFactoryStub implements IPipeFactory {
|
||||
}
|
||||
|
||||
public withPipe(pipe: IPipe) {
|
||||
if (!pipe) {
|
||||
throw new Error('missing pipe');
|
||||
}
|
||||
this.pipes.push(pipe);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { IProjectInformation } from '@/domain/IProjectInformation';
|
||||
import { ProjectInformationStub } from './ProjectInformationStub';
|
||||
|
||||
export class ProjectInformationParserStub {
|
||||
public readonly arguments = new Array<IAppMetadata>();
|
||||
public readonly arguments = new Array<IAppMetadata | undefined>();
|
||||
|
||||
private returnValue: IProjectInformation = new ProjectInformationStub();
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ export class RuntimeEnvironmentStub implements IRuntimeEnvironment {
|
||||
|
||||
public isDesktop = true;
|
||||
|
||||
public os = OperatingSystem.Windows;
|
||||
public os: OperatingSystem | undefined = OperatingSystem.Windows;
|
||||
|
||||
public withOs(os: OperatingSystem): this {
|
||||
public withOs(os: OperatingSystem | undefined): this {
|
||||
this.os = os;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
import type { ScriptData } from '@/application/collections/';
|
||||
import { IScriptCompiler } from '@/application/Parser/Script/Compiler/IScriptCompiler';
|
||||
import { IScriptCode } from '@/domain/IScriptCode';
|
||||
import { ScriptCodeStub } from './ScriptCodeStub';
|
||||
|
||||
export class ScriptCompilerStub implements IScriptCompiler {
|
||||
public compilables = new Map<ScriptData, IScriptCode>();
|
||||
public compilableScripts = new Map<ScriptData, IScriptCode>();
|
||||
|
||||
public canCompile(script: ScriptData): boolean {
|
||||
return this.compilables.has(script);
|
||||
return this.compilableScripts.has(script);
|
||||
}
|
||||
|
||||
public compile(script: ScriptData): IScriptCode {
|
||||
return this.compilables.get(script);
|
||||
const foundCode = this.compilableScripts.get(script);
|
||||
if (foundCode) {
|
||||
return foundCode;
|
||||
}
|
||||
return new ScriptCodeStub();
|
||||
}
|
||||
|
||||
public withCompileAbility(script: ScriptData, result?: IScriptCode): ScriptCompilerStub {
|
||||
this.compilables.set(
|
||||
public withCompileAbility(script: ScriptData, result?: IScriptCode): this {
|
||||
this.compilableScripts.set(
|
||||
script,
|
||||
result || { execute: `compiled code of ${script.name}`, revert: `compiled revert code of ${script.name}` },
|
||||
result ?? { execute: `compiled code of ${script.name}`, revert: `compiled revert code of ${script.name}` },
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,78 +1,81 @@
|
||||
import type { FunctionCallData, ScriptData } from '@/application/collections/';
|
||||
import type {
|
||||
FunctionCallData, CallScriptData, CodeScriptData,
|
||||
} from '@/application/collections/';
|
||||
import { RecommendationLevel } from '@/domain/RecommendationLevel';
|
||||
import { FunctionCallDataStub } from '@tests/unit/shared/Stubs/FunctionCallDataStub';
|
||||
|
||||
export class ScriptDataStub implements ScriptData {
|
||||
public static createWithCode(): ScriptDataStub {
|
||||
return new ScriptDataStub()
|
||||
.withCode('stub-code')
|
||||
.withRevertCode('stub-revert-code');
|
||||
}
|
||||
export function createScriptDataWithCode(): ScriptDataStub & CodeScriptData {
|
||||
return new ScriptDataStub()
|
||||
.withCode('stub-code')
|
||||
.withRevertCode('stub-revert-code');
|
||||
}
|
||||
|
||||
public static createWithCall(call?: FunctionCallData): ScriptDataStub {
|
||||
let instance = new ScriptDataStub();
|
||||
if (call) {
|
||||
instance = instance.withCall(call);
|
||||
} else {
|
||||
instance = instance.withMockCall();
|
||||
}
|
||||
return instance;
|
||||
export function createScriptDataWithCall(
|
||||
call?: FunctionCallData,
|
||||
): ScriptDataStub & CallScriptData {
|
||||
let instance = new ScriptDataStub();
|
||||
if (call) {
|
||||
instance = instance.withCall(call);
|
||||
} else {
|
||||
instance = instance.withMockCall();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static createWithoutCallOrCodes(): ScriptDataStub {
|
||||
return new ScriptDataStub();
|
||||
}
|
||||
export function createScriptDataWithoutCallOrCodes(): ScriptDataStub {
|
||||
return new ScriptDataStub();
|
||||
}
|
||||
|
||||
class ScriptDataStub implements CallScriptData, CodeScriptData {
|
||||
public name = 'valid-name';
|
||||
|
||||
public code = undefined;
|
||||
public code: string;
|
||||
|
||||
public revertCode = undefined;
|
||||
public revertCode: string | undefined = undefined;
|
||||
|
||||
public call = undefined;
|
||||
public call: FunctionCallData | undefined = undefined;
|
||||
|
||||
public recommend = RecommendationLevel[RecommendationLevel.Standard].toLowerCase();
|
||||
public recommend:
|
||||
string | undefined = RecommendationLevel[RecommendationLevel.Standard].toLowerCase();
|
||||
|
||||
public docs?: readonly string[] = ['hello.com'];
|
||||
|
||||
private constructor() { /* use static methods for constructing */ }
|
||||
|
||||
public withName(name: string): ScriptDataStub {
|
||||
public withName(name: string): this {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withDocs(docs: readonly string[]): ScriptDataStub {
|
||||
public withDocs(docs: readonly string[]): this {
|
||||
this.docs = docs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withCode(code: string): ScriptDataStub {
|
||||
public withCode(code: string): this {
|
||||
this.code = code;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withRevertCode(revertCode: string): ScriptDataStub {
|
||||
public withRevertCode(revertCode: string | undefined): this {
|
||||
this.revertCode = revertCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withMockCall(): ScriptDataStub {
|
||||
public withMockCall(): this {
|
||||
this.call = new FunctionCallDataStub();
|
||||
return this;
|
||||
}
|
||||
|
||||
public withCall(call: FunctionCallData): ScriptDataStub {
|
||||
public withCall(call: FunctionCallData | undefined): this {
|
||||
this.call = call;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withRecommend(recommend: string): ScriptDataStub {
|
||||
public withRecommend(recommend: string | undefined): this {
|
||||
this.recommend = recommend;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withRecommendationLevel(level: RecommendationLevel): ScriptDataStub {
|
||||
public withRecommendationLevel(level: RecommendationLevel): this {
|
||||
this.recommend = RecommendationLevel[level].toLowerCase();
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@ import { BaseEntity } from '@/infrastructure/Entity/BaseEntity';
|
||||
import { IScript } from '@/domain/IScript';
|
||||
import { RecommendationLevel } from '@/domain/RecommendationLevel';
|
||||
import { SelectedScript } from '@/application/Context/State/Selection/SelectedScript';
|
||||
import { IScriptCode } from '@/domain/IScriptCode';
|
||||
|
||||
export class ScriptStub extends BaseEntity<string> implements IScript {
|
||||
public name = `name${this.id}`;
|
||||
|
||||
public code = {
|
||||
public code: IScriptCode = {
|
||||
execute: `REM execute-code (${this.id})`,
|
||||
revert: `REM revert-code (${this.id})`,
|
||||
};
|
||||
@@ -23,23 +24,29 @@ export class ScriptStub extends BaseEntity<string> implements IScript {
|
||||
return Boolean(this.code.revert);
|
||||
}
|
||||
|
||||
public withLevel(value?: RecommendationLevel): ScriptStub {
|
||||
public withLevel(value: RecommendationLevel | undefined): this {
|
||||
this.level = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withCode(value: string): ScriptStub {
|
||||
this.code.execute = value;
|
||||
public withCode(value: string): this {
|
||||
this.code = {
|
||||
execute: value,
|
||||
revert: this.code.revert,
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
public withName(name: string): ScriptStub {
|
||||
public withName(name: string): this {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withRevertCode(revertCode: string): ScriptStub {
|
||||
this.code.revert = revertCode;
|
||||
public withRevertCode(revertCode?: string): this {
|
||||
this.code = {
|
||||
execute: this.code.execute,
|
||||
revert: revertCode,
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,17 +10,17 @@ export class ScriptingDefinitionStub implements IScriptingDefinition {
|
||||
|
||||
public endCode = 'REM end code';
|
||||
|
||||
public withStartCode(startCode: string): ScriptingDefinitionStub {
|
||||
public withStartCode(startCode: string): this {
|
||||
this.startCode = startCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withEndCode(endCode: string): ScriptingDefinitionStub {
|
||||
public withEndCode(endCode: string): this {
|
||||
this.endCode = endCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withLanguage(language: ScriptingLanguage): ScriptingDefinitionStub {
|
||||
public withLanguage(language: ScriptingLanguage): this {
|
||||
this.language = language;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ISharedFunction, FunctionBodyType } from '@/application/Parser/Script/Compiler/Function/ISharedFunction';
|
||||
import { ISharedFunction } from '@/application/Parser/Script/Compiler/Function/ISharedFunction';
|
||||
import { ISharedFunctionCollection } from '@/application/Parser/Script/Compiler/Function/ISharedFunctionCollection';
|
||||
import { SharedFunctionStub } from './SharedFunctionStub';
|
||||
import { createSharedFunctionStubWithCode } from './SharedFunctionStub';
|
||||
|
||||
export class SharedFunctionCollectionStub implements ISharedFunctionCollection {
|
||||
private readonly functions = new Map<string, ISharedFunction>();
|
||||
@@ -13,10 +13,11 @@ export class SharedFunctionCollectionStub implements ISharedFunctionCollection {
|
||||
}
|
||||
|
||||
public getFunctionByName(name: string): ISharedFunction {
|
||||
if (this.functions.has(name)) {
|
||||
return this.functions.get(name);
|
||||
const foundFunction = this.functions.get(name);
|
||||
if (foundFunction) {
|
||||
return foundFunction;
|
||||
}
|
||||
return new SharedFunctionStub(FunctionBodyType.Code)
|
||||
return createSharedFunctionStubWithCode()
|
||||
.withName(name)
|
||||
.withCode('code by SharedFunctionCollectionStub')
|
||||
.withRevertCode('revert-code by SharedFunctionCollectionStub');
|
||||
|
||||
@@ -1,72 +1,103 @@
|
||||
import { ISharedFunction, ISharedFunctionBody, FunctionBodyType } from '@/application/Parser/Script/Compiler/Function/ISharedFunction';
|
||||
import {
|
||||
ISharedFunction, FunctionBodyType, CallFunctionBody, CodeFunctionBody,
|
||||
} from '@/application/Parser/Script/Compiler/Function/ISharedFunction';
|
||||
import { IReadOnlyFunctionParameterCollection } from '@/application/Parser/Script/Compiler/Function/Parameter/IFunctionParameterCollection';
|
||||
import { FunctionCall } from '@/application/Parser/Script/Compiler/Function/Call/FunctionCall';
|
||||
import { FunctionParameterCollectionStub } from './FunctionParameterCollectionStub';
|
||||
import { FunctionCallStub } from './FunctionCallStub';
|
||||
import { FunctionCodeStub } from './FunctionCodeStub';
|
||||
|
||||
export class SharedFunctionStub implements ISharedFunction {
|
||||
public name = 'shared-function-stub-name';
|
||||
type CodeOrCallBody<T extends FunctionBodyType> = T extends FunctionBodyType.Calls
|
||||
? CallFunctionBody : CodeFunctionBody;
|
||||
|
||||
export function createSharedFunctionStubWithCalls(): SharedFunctionStub<FunctionBodyType.Calls> {
|
||||
return new SharedFunctionStub(FunctionBodyType.Calls);
|
||||
}
|
||||
|
||||
export function createSharedFunctionStubWithCode(): SharedFunctionStub<FunctionBodyType.Code> {
|
||||
return new SharedFunctionStub(FunctionBodyType.Code);
|
||||
}
|
||||
|
||||
class SharedFunctionStub<T extends FunctionBodyType>
|
||||
implements ISharedFunction {
|
||||
public name = `${SharedFunctionStub.name}-name`;
|
||||
|
||||
public parameters: IReadOnlyFunctionParameterCollection = new FunctionParameterCollectionStub()
|
||||
.withParameterName('shared-function-stub-parameter-name');
|
||||
.withParameterName(`${SharedFunctionStub.name}-parameter-name`);
|
||||
|
||||
private code = 'shared-function-stub-code';
|
||||
private code = `${SharedFunctionStub.name}-code`;
|
||||
|
||||
private revertCode = 'shared-function-stub-revert-code';
|
||||
private revertCode: string | undefined = `${SharedFunctionStub.name}-revert-code`;
|
||||
|
||||
private bodyType: FunctionBodyType = FunctionBodyType.Code;
|
||||
private readonly bodyType: FunctionBodyType = FunctionBodyType.Code;
|
||||
|
||||
private calls: FunctionCall[] = [new FunctionCallStub()];
|
||||
|
||||
constructor(type: FunctionBodyType) {
|
||||
constructor(type: T) {
|
||||
this.bodyType = type;
|
||||
}
|
||||
|
||||
public get body(): ISharedFunctionBody {
|
||||
return {
|
||||
type: this.bodyType,
|
||||
code: this.bodyType === FunctionBodyType.Code ? {
|
||||
execute: this.code,
|
||||
revert: this.revertCode,
|
||||
} : undefined,
|
||||
calls: this.bodyType === FunctionBodyType.Calls ? this.calls : undefined,
|
||||
};
|
||||
public get body(): CodeOrCallBody<T> {
|
||||
switch (this.bodyType) {
|
||||
case FunctionBodyType.Code:
|
||||
return this.getCodeBody() as CodeOrCallBody<T>;
|
||||
case FunctionBodyType.Calls:
|
||||
return this.getCallBody() as CodeOrCallBody<T>;
|
||||
default:
|
||||
throw new Error(`unknown body type: ${this.bodyType}`);
|
||||
}
|
||||
}
|
||||
|
||||
public withName(name: string) {
|
||||
public withName(name: string): this {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withCode(code: string) {
|
||||
public withCode(code: string): this {
|
||||
this.code = code;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withRevertCode(revertCode: string) {
|
||||
public withRevertCode(revertCode: string | undefined): this {
|
||||
this.revertCode = revertCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withParameters(parameters: IReadOnlyFunctionParameterCollection) {
|
||||
public withParameters(parameters: IReadOnlyFunctionParameterCollection): this {
|
||||
this.parameters = parameters;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withSomeCalls() {
|
||||
public withSomeCalls(): this {
|
||||
return this.withCalls(new FunctionCallStub(), new FunctionCallStub());
|
||||
}
|
||||
|
||||
public withCalls(...calls: readonly FunctionCall[]) {
|
||||
public withCalls(...calls: readonly FunctionCall[]): this {
|
||||
this.calls = [...calls];
|
||||
return this;
|
||||
}
|
||||
|
||||
public withParameterNames(...parameterNames: readonly string[]) {
|
||||
public withParameterNames(...parameterNames: readonly string[]): this {
|
||||
let collection = new FunctionParameterCollectionStub();
|
||||
for (const name of parameterNames) {
|
||||
collection = collection.withParameterName(name);
|
||||
}
|
||||
return this.withParameters(collection);
|
||||
}
|
||||
|
||||
private getCodeBody(): CodeFunctionBody {
|
||||
return {
|
||||
type: FunctionBodyType.Code,
|
||||
code: new FunctionCodeStub()
|
||||
.withExecute(this.code)
|
||||
.withRevert(this.revertCode),
|
||||
};
|
||||
}
|
||||
|
||||
private getCallBody(): CallFunctionBody {
|
||||
return {
|
||||
type: FunctionBodyType.Calls,
|
||||
calls: this.calls,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ export class SharedFunctionsParserStub implements ISharedFunctionsParser {
|
||||
return result || new SharedFunctionCollectionStub();
|
||||
}
|
||||
|
||||
private findResult(functions: readonly FunctionData[]): ISharedFunctionCollection {
|
||||
private findResult(functions: readonly FunctionData[]): ISharedFunctionCollection | undefined {
|
||||
return this.setupResults
|
||||
.find((result) => sequenceEqual(result.functions, functions))
|
||||
?.result;
|
||||
|
||||
@@ -19,7 +19,7 @@ export abstract class StubWithObservableMethodCalls<T> {
|
||||
|
||||
type MethodCall<T> = {
|
||||
[K in FunctionKeys<T>]: {
|
||||
methodName: K;
|
||||
args: T[K] extends (...args: infer A) => unknown ? A : never;
|
||||
readonly methodName: K;
|
||||
readonly args: T[K] extends (...args: infer A) => unknown ? A : never;
|
||||
}
|
||||
}[FunctionKeys<T>];
|
||||
|
||||
@@ -24,7 +24,7 @@ export class TreeNodeStub implements TreeNode {
|
||||
|
||||
public metadata?: object = new NodeMetadataStub();
|
||||
|
||||
public withMetadata(metadata: object): this {
|
||||
public withMetadata(metadata: object | undefined): this {
|
||||
this.metadata = metadata;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ export class UseCollectionStateStub
|
||||
if (scenario.immediateOnly) {
|
||||
handlers = handlers.filter((args) => args[1]?.immediate === true);
|
||||
}
|
||||
const callbacks = handlers.map((args) => args[0] as NewStateEventHandler);
|
||||
const callbacks = handlers.map((args) => args[0]);
|
||||
if (!callbacks.length) {
|
||||
throw new Error('No handler callbacks are registered to handle state change');
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { IFilterResult } from '@/application/Context/State/Filter/IFilterResult'
|
||||
import { IUserFilter } from '@/application/Context/State/Filter/IUserFilter';
|
||||
import { IEventSource } from '@/infrastructure/Events/IEventSource';
|
||||
import { IFilterChangeDetails } from '@/application/Context/State/Filter/Event/IFilterChangeDetails';
|
||||
import { FilterActionType } from '@/application/Context/State/Filter/Event/FilterActionType';
|
||||
import { FilterResultStub } from './FilterResultStub';
|
||||
import { EventSourceStub } from './EventSourceStub';
|
||||
|
||||
@@ -21,7 +22,11 @@ export class UserFilterStub implements IUserFilter {
|
||||
|
||||
public notifyFilterChange(change: IFilterChangeDetails) {
|
||||
this.filterChangedSource.notify(change);
|
||||
this.currentFilter = change.filter;
|
||||
if (change.action.type === FilterActionType.Apply) {
|
||||
this.currentFilter = change.action.filter;
|
||||
} else {
|
||||
this.currentFilter = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
public withNoCurrentFilter() {
|
||||
|
||||
@@ -6,30 +6,30 @@ import { SystemOperationsStub } from './SystemOperationsStub';
|
||||
import { LoggerStub } from './LoggerStub';
|
||||
|
||||
export class WindowVariablesStub implements WindowVariables {
|
||||
public system: ISystemOperations = new SystemOperationsStub();
|
||||
public system?: ISystemOperations = new SystemOperationsStub();
|
||||
|
||||
public isDesktop = false;
|
||||
public isDesktop? = false;
|
||||
|
||||
public os: OperatingSystem = OperatingSystem.BlackBerryOS;
|
||||
public os?: OperatingSystem = OperatingSystem.BlackBerryOS;
|
||||
|
||||
public log: ILogger = new LoggerStub();
|
||||
public log?: ILogger = new LoggerStub();
|
||||
|
||||
public withLog(log: ILogger): this {
|
||||
public withLog(log?: ILogger): this {
|
||||
this.log = log;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withIsDesktop(value: boolean): this {
|
||||
public withIsDesktop(value?: boolean): this {
|
||||
this.isDesktop = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withOs(value: OperatingSystem): this {
|
||||
public withOs(value: OperatingSystem | undefined): this {
|
||||
this.os = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withSystem(value: ISystemOperations): this {
|
||||
public withSystem(value?: ISystemOperations): this {
|
||||
this.system = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user