Move stubs from ./stubs to ./shared/Stubs

Gathers all shared test code in single place.
This commit is contained in:
undergroundwires
2022-01-25 08:37:03 +01:00
parent 43ce834750
commit 803ef2bb3e
94 changed files with 134 additions and 134 deletions

View File

@@ -0,0 +1,10 @@
import { ICodeChangedEvent } from '@/application/Context/State/Code/Event/ICodeChangedEvent';
import { IApplicationCode } from '@/application/Context/State/Code/IApplicationCode';
import { IEventSource } from '@/infrastructure/Events/IEventSource';
import { EventSource } from '@/infrastructure/Events/EventSource';
export class ApplicationCodeStub implements IApplicationCode {
public changed: IEventSource<ICodeChangedEvent> = new EventSource<ICodeChangedEvent>();
public current = '';
}

View File

@@ -0,0 +1,34 @@
import { IApplication } from '@/domain/IApplication';
import { ICategoryCollection } from '@/domain/ICategoryCollection';
import { OperatingSystem } from '@/domain/OperatingSystem';
import { IProjectInformation } from '@/domain/IProjectInformation';
import { ProjectInformationStub } from './ProjectInformationStub';
export class ApplicationStub implements IApplication {
public info: IProjectInformation = new ProjectInformationStub();
public collections: ICategoryCollection[] = [];
public getCollection(operatingSystem: OperatingSystem): ICategoryCollection {
return this.collections.find((collection) => collection.os === operatingSystem);
}
public getSupportedOsList(): OperatingSystem[] {
return this.collections.map((collection) => collection.os);
}
public withCollection(collection: ICategoryCollection): ApplicationStub {
this.collections.push(collection);
return this;
}
public withProjectInformation(info: IProjectInformation): ApplicationStub {
this.info = info;
return this;
}
public withCollections(...collections: readonly ICategoryCollection[]): ApplicationStub {
this.collections.push(...collections);
return this;
}
}

View File

@@ -0,0 +1,21 @@
import { ICategoryCollectionParseContext } from '@/application/Parser/Script/ICategoryCollectionParseContext';
import { IScriptCompiler } from '@/application/Parser/Script/Compiler/IScriptCompiler';
import { ILanguageSyntax } from '@/domain/ScriptCode';
import { ScriptCompilerStub } from './ScriptCompilerStub';
import { LanguageSyntaxStub } from './LanguageSyntaxStub';
export class CategoryCollectionParseContextStub implements ICategoryCollectionParseContext {
public compiler: IScriptCompiler = new ScriptCompilerStub();
public syntax: ILanguageSyntax = new LanguageSyntaxStub();
public withCompiler(compiler: IScriptCompiler) {
this.compiler = compiler;
return this;
}
public withSyntax(syntax: ILanguageSyntax) {
this.syntax = syntax;
return this;
}
}

View File

@@ -0,0 +1,36 @@
import { IApplicationCode } from '@/application/Context/State/Code/IApplicationCode';
import { IUserFilter } from '@/application/Context/State/Filter/IUserFilter';
import { ICategoryCollectionState } from '@/application/Context/State/ICategoryCollectionState';
import { OperatingSystem } from '@/domain/OperatingSystem';
import { SelectedScript } from '@/application/Context/State/Selection/SelectedScript';
import { IScript } from '@/domain/IScript';
import { CategoryCollectionStub } from './CategoryCollectionStub';
import { UserSelectionStub } from './UserSelectionStub';
import { UserFilterStub } from './UserFilterStub';
import { ApplicationCodeStub } from './ApplicationCodeStub';
import { CategoryStub } from './CategoryStub';
export class CategoryCollectionStateStub implements ICategoryCollectionState {
public readonly code: IApplicationCode = new ApplicationCodeStub();
public readonly filter: IUserFilter = new UserFilterStub();
public readonly os = OperatingSystem.Windows;
public readonly collection: CategoryCollectionStub;
public readonly selection: UserSelectionStub;
constructor(readonly allScripts: IScript[]) {
this.selection = new UserSelectionStub(allScripts);
this.collection = new CategoryCollectionStub()
.withOs(this.os)
.withTotalScripts(this.allScripts.length)
.withAction(new CategoryStub(0).withScripts(...allScripts));
}
public withSelectedScripts(initialScripts: readonly SelectedScript[]) {
this.selection.withSelectedScripts(initialScripts);
return this;
}
}

View File

@@ -0,0 +1,87 @@
import { OperatingSystem } from '@/domain/OperatingSystem';
import { IScriptingDefinition } from '@/domain/IScriptingDefinition';
import { IScript } from '@/domain/IScript';
import { ICategory } from '@/domain/ICategory';
import { ICategoryCollection } from '@/domain/ICategoryCollection';
import { RecommendationLevel } from '@/domain/RecommendationLevel';
import { ScriptStub } from './ScriptStub';
import { ScriptingDefinitionStub } from './ScriptingDefinitionStub';
export class CategoryCollectionStub implements ICategoryCollection {
public scripting: IScriptingDefinition = new ScriptingDefinitionStub();
public os = OperatingSystem.Linux;
public initialScript: IScript = new ScriptStub('55');
public totalScripts = 0;
public totalCategories = 0;
public readonly actions = new Array<ICategory>();
public withAction(category: ICategory): CategoryCollectionStub {
this.actions.push(category);
return this;
}
public withOs(os: OperatingSystem): CategoryCollectionStub {
this.os = os;
return this;
}
public withScripting(scripting: IScriptingDefinition): CategoryCollectionStub {
this.scripting = scripting;
return this;
}
public withInitialScript(script: IScript): CategoryCollectionStub {
this.initialScript = script;
return this;
}
public withTotalScripts(totalScripts: number) {
this.totalScripts = totalScripts;
return this;
}
public findCategory(categoryId: number): ICategory {
return this.getAllCategories()
.find((category) => category.id === categoryId);
}
public getScriptsByLevel(level: RecommendationLevel): readonly IScript[] {
return this.getAllScripts()
.filter((script) => script.level !== undefined && script.level <= level);
}
public findScript(scriptId: string): IScript {
return this.getAllScripts()
.find((script) => scriptId === script.id);
}
public getAllScripts(): ReadonlyArray<IScript> {
return this.actions.flatMap((category) => getScriptsRecursively(category));
}
public getAllCategories(): ReadonlyArray<ICategory> {
return this.actions.flatMap(
(category) => [category, ...getSubCategoriesRecursively(category)],
);
}
}
function getSubCategoriesRecursively(category: ICategory): ReadonlyArray<ICategory> {
return (category.subCategories || []).flatMap(
(subCategory) => [subCategory, ...getSubCategoriesRecursively(subCategory)],
);
}
function getScriptsRecursively(category: ICategory): ReadonlyArray<IScript> {
return [
...(category.scripts || []),
...(category.subCategories || []).flatMap(
(subCategory) => getScriptsRecursively(subCategory),
),
];
}

View File

@@ -0,0 +1,25 @@
import { CategoryData, CategoryOrScriptData, DocumentationUrlsData } from 'js-yaml-loader!@/*';
import { ScriptDataStub } from './ScriptDataStub';
export class CategoryDataStub implements CategoryData {
public children: readonly CategoryOrScriptData[] = [ScriptDataStub.createWithCode()];
public category = 'category name';
public docs?: DocumentationUrlsData;
public withChildren(children: readonly CategoryOrScriptData[]) {
this.children = children;
return this;
}
public withName(name: string) {
this.category = name;
return this;
}
public withDocs(docs: DocumentationUrlsData) {
this.docs = docs;
return this;
}
}

View File

@@ -0,0 +1,63 @@
import { BaseEntity } from '@/infrastructure/Entity/BaseEntity';
import { ICategory, IScript } from '@/domain/ICategory';
import { ScriptStub } from './ScriptStub';
export class CategoryStub extends BaseEntity<number> implements ICategory {
public name = `category-with-id-${this.id}`;
public readonly subCategories = new Array<ICategory>();
public readonly scripts = new Array<IScript>();
public readonly documentationUrls = new Array<string>();
public constructor(id: number) {
super(id);
}
public includes(script: IScript): boolean {
return this.getAllScriptsRecursively().some((s) => s.id === script.id);
}
public getAllScriptsRecursively(): readonly IScript[] {
return [
...this.scripts,
...this.subCategories.flatMap((c) => c.getAllScriptsRecursively()),
];
}
public withScriptIds(...scriptIds: string[]): CategoryStub {
return this.withScripts(
...scriptIds.map((id) => new ScriptStub(id)),
);
}
public withScripts(...scripts: IScript[]): CategoryStub {
for (const script of scripts) {
this.withScript(script);
}
return this;
}
public withCategories(...categories: ICategory[]): CategoryStub {
for (const category of categories) {
this.withCategory(category);
}
return this;
}
public withCategory(category: ICategory): CategoryStub {
this.subCategories.push(category);
return this;
}
public withScript(script: IScript): CategoryStub {
this.scripts.push(script);
return this;
}
public withName(categoryName: string) {
this.name = categoryName;
return this;
}
}

View File

@@ -0,0 +1,20 @@
import { IProjectInformation } from '@/domain/IProjectInformation';
import { ICodeSubstituter } from '@/application/Parser/ScriptingDefinition/ICodeSubstituter';
export class CodeSubstituterStub implements ICodeSubstituter {
private readonly scenarios =
new Array<{ code: string, info: IProjectInformation, result: string }>();
public substitute(code: string, info: IProjectInformation): string {
const scenario = this.scenarios.find((s) => s.code === code && s.info === info);
if (scenario) {
return scenario.result;
}
return `[CodeSubstituterStub] - code: ${code}`;
}
public setup(code: string, info: IProjectInformation, result: string) {
this.scenarios.push({ code, info, result });
return this;
}
}

View File

@@ -0,0 +1,67 @@
import {
CategoryData, ScriptData, CollectionData, ScriptingDefinitionData, FunctionData,
} from 'js-yaml-loader!@/*';
import { RecommendationLevel } from '@/domain/RecommendationLevel';
import { ScriptingLanguage } from '@/domain/ScriptingLanguage';
export class CollectionDataStub implements CollectionData {
public os = 'windows';
public actions: readonly CategoryData[] = [getCategoryStub()];
public scripting: ScriptingDefinitionData = getTestDefinitionStub();
public functions?: ReadonlyArray<FunctionData>;
public withActions(actions: readonly CategoryData[]): CollectionDataStub {
this.actions = actions;
return this;
}
public withOs(os: string): CollectionDataStub {
this.os = os;
return this;
}
public withScripting(scripting: ScriptingDefinitionData): CollectionDataStub {
this.scripting = scripting;
return this;
}
public withFunctions(functions: ReadonlyArray<FunctionData>) {
this.functions = functions;
return this;
}
}
export function getCategoryStub(scriptPrefix = 'testScript'): CategoryData {
return {
category: 'category name',
children: [
getScriptStub(`${scriptPrefix}-standard`, RecommendationLevel.Standard),
getScriptStub(`${scriptPrefix}-strict`, RecommendationLevel.Strict),
],
};
}
function getTestDefinitionStub(): ScriptingDefinitionData {
return {
fileExtension: '.bat',
language: ScriptingLanguage[ScriptingLanguage.batchfile],
startCode: 'start',
endCode: 'end',
};
}
function getScriptStub(
scriptName: string,
level: RecommendationLevel = RecommendationLevel.Standard,
): ScriptData {
return {
name: scriptName,
code: 'script code',
revertCode: 'revert code',
recommend: RecommendationLevel[level].toLowerCase(),
call: undefined,
};
}

View File

@@ -0,0 +1,31 @@
import { IEnumParser } from '@/application/Common/Enum';
export class EnumParserStub<T> implements IEnumParser<T> {
private readonly scenarios =
new Array<{ inputName: string, inputValue: string, outputValue: T }>();
private defaultValue: T;
public setup(inputName: string, inputValue: string, outputValue: T) {
this.scenarios.push({ inputName, inputValue, outputValue });
return this;
}
public setupDefaultValue(outputValue: T) {
this.defaultValue = outputValue;
return this;
}
public parseEnum(value: string, propertyName: string): T {
const scenario = this.scenarios.find(
(s) => s.inputName === propertyName && s.inputValue === value,
);
if (scenario) {
return scenario.outputValue;
}
if (this.defaultValue) {
return this.defaultValue;
}
throw new Error('enum parser is not set up');
}
}

View File

@@ -0,0 +1,13 @@
import { IEnvironment } from '@/application/Environment/IEnvironment';
import { OperatingSystem } from '@/domain/OperatingSystem';
export class EnvironmentStub implements IEnvironment {
public isDesktop = true;
public os = OperatingSystem.Windows;
public withOs(os: OperatingSystem): EnvironmentStub {
this.os = os;
return this;
}
}

View File

@@ -0,0 +1,22 @@
import { IExpressionEvaluationContext } from '@/application/Parser/Script/Compiler/Expressions/Expression/ExpressionEvaluationContext';
import { IPipelineCompiler } from '@/application/Parser/Script/Compiler/Expressions/Pipes/IPipelineCompiler';
import { IReadOnlyFunctionCallArgumentCollection } from '@/application/Parser/Script/Compiler/Function/Call/Argument/IFunctionCallArgumentCollection';
import { FunctionCallArgumentCollectionStub } from './FunctionCallArgumentCollectionStub';
import { PipelineCompilerStub } from './PipelineCompilerStub';
export class ExpressionEvaluationContextStub implements IExpressionEvaluationContext {
public args: IReadOnlyFunctionCallArgumentCollection = new FunctionCallArgumentCollectionStub()
.withArgument('test-arg', 'test-value');
public pipelineCompiler: IPipelineCompiler = new PipelineCompilerStub();
public withArgs(args: IReadOnlyFunctionCallArgumentCollection) {
this.args = args;
return this;
}
public withPipelineCompiler(pipelineCompiler: IPipelineCompiler) {
this.pipelineCompiler = pipelineCompiler;
return this;
}
}

View File

@@ -0,0 +1,18 @@
import { IExpression } from '@/application/Parser/Script/Compiler/Expressions/Expression/IExpression';
import { IExpressionParser } from '@/application/Parser/Script/Compiler/Expressions/Parser/IExpressionParser';
export class ExpressionParserStub implements IExpressionParser {
public callHistory = new Array<string>();
private result: IExpression[] = [];
public withResult(result: IExpression[]) {
this.result = result;
return this;
}
public findExpressions(code: string): IExpression[] {
this.callHistory.push(code);
return this.result;
}
}

View File

@@ -0,0 +1,43 @@
import { ExpressionPosition } from '@/application/Parser/Script/Compiler/Expressions/Expression/ExpressionPosition';
import { IExpression } from '@/application/Parser/Script/Compiler/Expressions/Expression/IExpression';
import { IReadOnlyFunctionParameterCollection } from '@/application/Parser/Script/Compiler/Function/Parameter/IFunctionParameterCollection';
import { IExpressionEvaluationContext } from '@/application/Parser/Script/Compiler/Expressions/Expression/ExpressionEvaluationContext';
import { FunctionParameterCollectionStub } from './FunctionParameterCollectionStub';
export class ExpressionStub implements IExpression {
public callHistory = new Array<IExpressionEvaluationContext>();
public position = new ExpressionPosition(0, 5);
public parameters: IReadOnlyFunctionParameterCollection = new FunctionParameterCollectionStub();
private result: string;
public withParameters(parameters: IReadOnlyFunctionParameterCollection) {
this.parameters = parameters;
return this;
}
public withParameterNames(parameterNames: readonly string[], isOptional = false) {
const collection = new FunctionParameterCollectionStub()
.withParameterNames(parameterNames, isOptional);
return this.withParameters(collection);
}
public withPosition(start: number, end: number) {
this.position = new ExpressionPosition(start, end);
return this;
}
public withEvaluatedResult(result: string) {
this.result = result;
return this;
}
public evaluate(context: IExpressionEvaluationContext): string {
const { args } = context;
this.callHistory.push(context);
const result = this.result || `[expression-stub] args: ${args ? Object.keys(args).map((key) => `${key}: ${args[key]}`).join('", "') : 'none'}`;
return result;
}
}

View File

@@ -0,0 +1,66 @@
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 { FunctionCallArgumentCollectionStub } from '@tests/unit/shared/Stubs/FunctionCallArgumentCollectionStub';
export class ExpressionsCompilerStub implements IExpressionsCompiler {
public readonly callHistory =
new Array<{ code: string, parameters: IReadOnlyFunctionCallArgumentCollection }>();
private readonly scenarios = new Array<ITestScenario>();
public setup(scenario: ITestScenario): ExpressionsCompilerStub {
this.scenarios.push(scenario);
return this;
}
public setupToReturnFunctionCode(
func: ISharedFunction,
givenArgs: FunctionCallArgumentCollectionStub,
) {
return this
.setup({ givenCode: func.body.code.do, givenArgs, result: func.body.code.do })
.setup({ givenCode: func.body.code.revert, givenArgs, result: func.body.code.revert });
}
public compileExpressions(
code: string,
parameters: IReadOnlyFunctionCallArgumentCollection,
): string {
this.callHistory.push({ code, parameters });
const scenario = this.scenarios.find(
(s) => s.givenCode === code && deepEqual(s.givenArgs, parameters),
);
if (scenario) {
return scenario.result;
}
const parametersAndValues = parameters
.getAllParameterNames()
.map((name) => `${name}=${parameters.getArgument(name).argumentValue}`)
.join('\n\t');
return `[ExpressionsCompilerStub]\ncode: "${code}"\nparameters: ${parametersAndValues}`;
}
}
interface ITestScenario {
readonly givenCode: string;
readonly givenArgs: IReadOnlyFunctionCallArgumentCollection;
readonly result: string;
}
function deepEqual(
expected: IReadOnlyFunctionCallArgumentCollection,
actual: IReadOnlyFunctionCallArgumentCollection,
): boolean {
const expectedParameterNames = expected.getAllParameterNames();
const actualParameterNames = actual.getAllParameterNames();
if (!scrambledEqual(expectedParameterNames, actualParameterNames)) {
return false;
}
return expectedParameterNames.every((parameterName) => {
const expectedValue = expected.getArgument(parameterName).argumentValue;
const actualValue = actual.getArgument(parameterName).argumentValue;
return expectedValue === actualValue;
});
}

View File

@@ -0,0 +1,42 @@
import { IFunctionCallArgument } from '@/application/Parser/Script/Compiler/Function/Call/Argument/IFunctionCallArgument';
import { IFunctionCallArgumentCollection } from '@/application/Parser/Script/Compiler/Function/Call/Argument/IFunctionCallArgumentCollection';
import { FunctionCallArgumentStub } from './FunctionCallArgumentStub';
export class FunctionCallArgumentCollectionStub implements IFunctionCallArgumentCollection {
private args = new Array<IFunctionCallArgument>();
public withArgument(parameterName: string, argumentValue: string) {
const arg = new FunctionCallArgumentStub()
.withParameterName(parameterName)
.withArgumentValue(argumentValue);
this.addArgument(arg);
return this;
}
public withArguments(args: { readonly [index: string]: string }) {
for (const [name, value] of Object.entries(args)) {
this.withArgument(name, value);
}
return this;
}
public hasArgument(parameterName: string): boolean {
return this.args.some((a) => a.parameterName === parameterName);
}
public addArgument(argument: IFunctionCallArgument): void {
this.args.push(argument);
}
public getAllParameterNames(): string[] {
return this.args.map((a) => a.parameterName);
}
public getArgument(parameterName: string): IFunctionCallArgument {
const arg = this.args.find((a) => a.parameterName === parameterName);
if (!arg) {
throw new Error(`no argument exists for parameter "${parameterName}"`);
}
return arg;
}
}

View File

@@ -0,0 +1,17 @@
import { IFunctionCallArgument } from '@/application/Parser/Script/Compiler/Function/Call/Argument/IFunctionCallArgument';
export class FunctionCallArgumentStub implements IFunctionCallArgument {
public parameterName = 'stub-parameter-name';
public argumentValue = 'stub-arg-name';
public withParameterName(parameterName: string) {
this.parameterName = parameterName;
return this;
}
public withArgumentValue(argumentValue: string) {
this.argumentValue = argumentValue;
return this;
}
}

View File

@@ -0,0 +1,48 @@
import { ICompiledCode } from '@/application/Parser/Script/Compiler/Function/Call/Compiler/ICompiledCode';
import { IFunctionCallCompiler } from '@/application/Parser/Script/Compiler/Function/Call/Compiler/IFunctionCallCompiler';
import { ISharedFunctionCollection } from '@/application/Parser/Script/Compiler/Function/ISharedFunctionCollection';
import { IFunctionCall } from '@/application/Parser/Script/Compiler/Function/Call/IFunctionCall';
interface IScenario {
calls: IFunctionCall[];
functions: ISharedFunctionCollection;
result: ICompiledCode;
}
export class FunctionCallCompilerStub implements IFunctionCallCompiler {
public scenarios = new Array<IScenario>();
public setup(
calls: IFunctionCall[],
functions: ISharedFunctionCollection,
result: ICompiledCode,
) {
this.scenarios.push({ calls, functions, result });
}
public compileCall(
calls: IFunctionCall[],
functions: ISharedFunctionCollection,
): ICompiledCode {
const predefined = this.scenarios
.find((s) => areEqual(s.calls, calls) && s.functions === functions);
if (predefined) {
return predefined.result;
}
return {
code: 'function code [FunctionCallCompilerStub]',
revertCode: 'function revert code [FunctionCallCompilerStub]',
};
}
}
function areEqual(
first: readonly IFunctionCall[],
second: readonly IFunctionCall[],
) {
const comparer = (a: IFunctionCall, b: IFunctionCall) => a.functionName
.localeCompare(b.functionName);
const printSorted = (calls: readonly IFunctionCall[]) => JSON
.stringify([...calls].sort(comparer));
return printSorted(first) === printSorted(second);
}

View File

@@ -0,0 +1,17 @@
import { FunctionCallData, FunctionCallParametersData } from 'js-yaml-loader!@/*';
export class FunctionCallDataStub implements FunctionCallData {
public function = 'callDatStubCalleeFunction';
public parameters: { [index: string]: string } = { testParameter: 'testArgument' };
public withName(functionName: string) {
this.function = functionName;
return this;
}
public withParameters(parameters: FunctionCallParametersData) {
this.parameters = parameters;
return this;
}
}

View File

@@ -0,0 +1,28 @@
import { IFunctionCall } from '@/application/Parser/Script/Compiler/Function/Call/IFunctionCall';
import { FunctionCallArgumentCollectionStub } from './FunctionCallArgumentCollectionStub';
export class FunctionCallStub implements IFunctionCall {
public functionName = 'functionCallStub';
public args = new FunctionCallArgumentCollectionStub();
public withFunctionName(functionName: string) {
this.functionName = functionName;
return this;
}
public withArgument(parameterName: string, argumentValue: string) {
this.args.withArgument(parameterName, argumentValue);
return this;
}
public withArguments(args: { readonly [index: string]: string }) {
this.args.withArguments(args);
return this;
}
public withArgumentCollection(args: FunctionCallArgumentCollectionStub) {
this.args = args;
return this;
}
}

View File

@@ -0,0 +1,17 @@
import { IFunctionCode } from '@/application/Parser/Script/Compiler/Function/ISharedFunction';
export class FunctionCodeStub implements IFunctionCode {
public do = 'do code (function-code-stub)';
public revert? = 'revert code (function-code-stub)';
public withDo(code: string) {
this.do = code;
return this;
}
public withRevert(revert: string) {
this.revert = revert;
return this;
}
}

View File

@@ -0,0 +1,70 @@
import { FunctionData, ParameterDefinitionData, FunctionCallsData } from 'js-yaml-loader!@/*';
import { FunctionCallDataStub } from './FunctionCallDataStub';
export class FunctionDataStub implements FunctionData {
public static createWithCode() {
return new FunctionDataStub()
.withCode('stub-code')
.withRevertCode('stub-revert-code');
}
public static createWithCall(call?: FunctionCallsData) {
let instance = new FunctionDataStub();
if (call) {
instance = instance.withCall(call);
} else {
instance = instance.withMockCall();
}
return instance;
}
public static createWithoutCallOrCodes() {
return new FunctionDataStub();
}
public name = 'functionDataStub';
public code: string;
public revertCode: string;
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;
}
public withParameters(...parameters: readonly ParameterDefinitionData[]) {
return this.withParametersObject(parameters);
}
public withParametersObject(parameters: readonly ParameterDefinitionData[]) {
this.parameters = parameters;
return this;
}
public withCode(code: string) {
this.code = code;
return this;
}
public withRevertCode(revertCode: string) {
this.revertCode = revertCode;
return this;
}
public withCall(call: FunctionCallsData) {
this.call = call;
return this;
}
public withMockCall() {
this.call = new FunctionCallDataStub();
return this;
}
}

View File

@@ -0,0 +1,30 @@
import { IFunctionParameter } from '@/application/Parser/Script/Compiler/Function/Parameter/IFunctionParameter';
import { IFunctionParameterCollection } from '@/application/Parser/Script/Compiler/Function/Parameter/IFunctionParameterCollection';
import { FunctionParameterStub } from './FunctionParameterStub';
export class FunctionParameterCollectionStub implements IFunctionParameterCollection {
private parameters = new Array<IFunctionParameter>();
public addParameter(parameter: IFunctionParameter): void {
this.parameters.push(parameter);
}
public get all(): readonly IFunctionParameter[] {
return this.parameters;
}
public withParameterName(parameterName: string, isOptional = true) {
const parameter = new FunctionParameterStub()
.withName(parameterName)
.withOptionality(isOptional);
this.addParameter(parameter);
return this;
}
public withParameterNames(parameterNames: readonly string[], isOptional = true) {
for (const parameterName of parameterNames) {
this.withParameterName(parameterName, isOptional);
}
return this;
}
}

View File

@@ -0,0 +1,17 @@
import { IFunctionParameter } from '@/application/Parser/Script/Compiler/Function/Parameter/IFunctionParameter';
export class FunctionParameterStub implements IFunctionParameter {
public name = 'function-parameter-stub';
public isOptional = true;
public withName(name: string) {
this.name = name;
return this;
}
public withOptionality(isOptional: boolean) {
this.isOptional = isOptional;
return this;
}
}

View File

@@ -0,0 +1,17 @@
import { ILanguageSyntax } from '@/domain/ScriptCode';
export class LanguageSyntaxStub implements ILanguageSyntax {
public commentDelimiters = [];
public commonCodeParts = [];
public withCommentDelimiters(...delimiters: string[]) {
this.commentDelimiters = delimiters;
return this;
}
public withCommonCodeParts(...codeParts: string[]) {
this.commonCodeParts = codeParts;
return this;
}
}

View File

@@ -0,0 +1,14 @@
import { BaseEntity } from '@/infrastructure/Entity/BaseEntity';
export class NumericEntityStub extends BaseEntity<number> {
public customProperty = 'customProperty';
public constructor(id: number) {
super(id);
}
public withCustomProperty(value: string): NumericEntityStub {
this.customProperty = value;
return this;
}
}

View File

@@ -0,0 +1,17 @@
import { ParameterDefinitionData } from 'js-yaml-loader!@/*';
export class ParameterDefinitionDataStub implements ParameterDefinitionData {
public name: string;
public optional?: boolean;
public withName(name: string) {
this.name = name;
return this;
}
public withOptionality(isOptional: boolean) {
this.optional = isOptional;
return this;
}
}

View File

@@ -0,0 +1,29 @@
import { IPipe } from '@/application/Parser/Script/Compiler/Expressions/Pipes/IPipe';
import { IPipeFactory } from '@/application/Parser/Script/Compiler/Expressions/Pipes/PipeFactory';
export class PipeFactoryStub implements IPipeFactory {
private readonly pipes = new Array<IPipe>();
public get(pipeName: string): IPipe {
const result = this.pipes.find((pipe) => pipe.name === pipeName);
if (!result) {
throw new Error(`pipe not registered: "${pipeName}"`);
}
return result;
}
public withPipe(pipe: IPipe) {
if (!pipe) {
throw new Error('missing pipe');
}
this.pipes.push(pipe);
return this;
}
public withPipes(pipes: IPipe[]) {
for (const pipe of pipes) {
this.withPipe(pipe);
}
return this;
}
}

View File

@@ -0,0 +1,19 @@
import { IPipe } from '@/application/Parser/Script/Compiler/Expressions/Pipes/IPipe';
export class PipeStub implements IPipe {
public name = 'pipeStub';
public apply(raw: string): string {
return raw;
}
public withName(name: string): PipeStub {
this.name = name;
return this;
}
public withApplier(applier: (input: string) => string): PipeStub {
this.apply = applier;
return this;
}
}

View File

@@ -0,0 +1,10 @@
import { IPipelineCompiler } from '@/application/Parser/Script/Compiler/Expressions/Pipes/IPipelineCompiler';
export class PipelineCompilerStub implements IPipelineCompiler {
public compileHistory: Array<{ value: string, pipeline: string }> = [];
public compile(value: string, pipeline: string): string {
this.compileHistory.push({ value, pipeline });
return `value: ${value}"\n${pipeline}: ${pipeline}`;
}
}

View File

@@ -0,0 +1,8 @@
export function getProcessEnvironmentStub(): NodeJS.ProcessEnv {
return {
VUE_APP_VERSION: 'stub-version',
VUE_APP_NAME: 'stub-name',
VUE_APP_REPOSITORY_URL: 'stub-repository-url',
VUE_APP_HOMEPAGE_URL: 'stub-homepage-url',
};
}

View File

@@ -0,0 +1,58 @@
import { IProjectInformation } from '@/domain/IProjectInformation';
export class ProjectInformationStub implements IProjectInformation {
public name = 'name';
public version = 'version';
public repositoryUrl = 'repositoryUrl';
public homepage = 'homepage';
public feedbackUrl = 'feedbackUrl';
public releaseUrl = 'releaseUrl';
public repositoryWebUrl = 'repositoryWebUrl';
public downloadUrl = 'downloadUrl';
public withName(name: string): ProjectInformationStub {
this.name = name;
return this;
}
public withVersion(version: string): ProjectInformationStub {
this.version = version;
return this;
}
public withRepositoryUrl(repositoryUrl: string): ProjectInformationStub {
this.repositoryUrl = repositoryUrl;
return this;
}
public withHomepageUrl(homepageUrl: string): ProjectInformationStub {
this.homepage = homepageUrl;
return this;
}
public withFeedbackUrl(feedbackUrl: string): ProjectInformationStub {
this.feedbackUrl = feedbackUrl;
return this;
}
public withReleaseUrl(releaseUrl: string): ProjectInformationStub {
this.releaseUrl = releaseUrl;
return this;
}
public withRepositoryWebUrl(repositoryWebUrl: string): ProjectInformationStub {
this.repositoryWebUrl = repositoryWebUrl;
return this;
}
public getDownloadUrl(): string {
return this.downloadUrl;
}
}

View File

@@ -0,0 +1,17 @@
import { IScriptCode } from '@/domain/IScriptCode';
export class ScriptCodeStub implements IScriptCode {
public execute = 'default execute code';
public revert = 'default revert code';
public withExecute(code: string) {
this.execute = code;
return this;
}
public withRevert(revert: string) {
this.revert = revert;
return this;
}
}

View File

@@ -0,0 +1,23 @@
import { ScriptData } from 'js-yaml-loader!@/*';
import { IScriptCompiler } from '@/application/Parser/Script/Compiler/IScriptCompiler';
import { IScriptCode } from '@/domain/IScriptCode';
export class ScriptCompilerStub implements IScriptCompiler {
public compilables = new Map<ScriptData, IScriptCode>();
public canCompile(script: ScriptData): boolean {
return this.compilables.has(script);
}
public compile(script: ScriptData): IScriptCode {
return this.compilables.get(script);
}
public withCompileAbility(script: ScriptData, result?: IScriptCode): ScriptCompilerStub {
this.compilables.set(
script,
result || { execute: `compiled code of ${script.name}`, revert: `compiled revert code of ${script.name}` },
);
return this;
}
}

View File

@@ -0,0 +1,79 @@
import { FunctionCallData, ScriptData } from 'js-yaml-loader!@/*';
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');
}
public static createWithCall(call?: FunctionCallData): ScriptDataStub {
let instance = new ScriptDataStub();
if (call) {
instance = instance.withCall(call);
} else {
instance = instance.withMockCall();
}
return instance;
}
public static createWithoutCallOrCodes(): ScriptDataStub {
return new ScriptDataStub();
}
public name = 'valid-name';
public code = undefined;
public revertCode = undefined;
public call = undefined;
public recommend = RecommendationLevel[RecommendationLevel.Standard].toLowerCase();
public docs = ['hello.com'];
private constructor() { /* use static methods for constructing */ }
public withName(name: string): ScriptDataStub {
this.name = name;
return this;
}
public withDocs(docs: string[]): ScriptDataStub {
this.docs = docs;
return this;
}
public withCode(code: string): ScriptDataStub {
this.code = code;
return this;
}
public withRevertCode(revertCode: string): ScriptDataStub {
this.revertCode = revertCode;
return this;
}
public withMockCall(): ScriptDataStub {
this.call = new FunctionCallDataStub();
return this;
}
public withCall(call: FunctionCallData): ScriptDataStub {
this.call = call;
return this;
}
public withRecommend(recommend: string): ScriptDataStub {
this.recommend = recommend;
return this;
}
public withRecommendationLevel(level: RecommendationLevel): ScriptDataStub {
this.recommend = RecommendationLevel[level].toLowerCase();
return this;
}
}

View File

@@ -0,0 +1,49 @@
import { BaseEntity } from '@/infrastructure/Entity/BaseEntity';
import { IScript } from '@/domain/IScript';
import { RecommendationLevel } from '@/domain/RecommendationLevel';
import { SelectedScript } from '@/application/Context/State/Selection/SelectedScript';
export class ScriptStub extends BaseEntity<string> implements IScript {
public name = `name${this.id}`;
public code = {
execute: `REM execute-code (${this.id})`,
revert: `REM revert-code (${this.id})`,
};
public readonly documentationUrls = new Array<string>();
public level? = RecommendationLevel.Standard;
constructor(public readonly id: string) {
super(id);
}
public canRevert(): boolean {
return Boolean(this.code.revert);
}
public withLevel(value?: RecommendationLevel): ScriptStub {
this.level = value;
return this;
}
public withCode(value: string): ScriptStub {
this.code.execute = value;
return this;
}
public withName(name: string): ScriptStub {
this.name = name;
return this;
}
public withRevertCode(revertCode: string): ScriptStub {
this.code.revert = revertCode;
return this;
}
public toSelectedScript(isReverted = false): SelectedScript {
return new SelectedScript(this, isReverted);
}
}

View File

@@ -0,0 +1,32 @@
import { ScriptingDefinitionData } from 'js-yaml-loader!@/*';
import { ScriptingLanguage } from '@/domain/ScriptingLanguage';
export class ScriptingDefinitionDataStub implements ScriptingDefinitionData {
public language = ScriptingLanguage[ScriptingLanguage.batchfile];
public fileExtension = 'bat';
public startCode = 'startCode';
public endCode = 'endCode';
public withLanguage(language: string): ScriptingDefinitionDataStub {
this.language = language;
return this;
}
public withStartCode(startCode: string): ScriptingDefinitionDataStub {
this.startCode = startCode;
return this;
}
public withEndCode(endCode: string): ScriptingDefinitionDataStub {
this.endCode = endCode;
return this;
}
public withExtension(extension: string): ScriptingDefinitionDataStub {
this.fileExtension = extension;
return this;
}
}

View File

@@ -0,0 +1,27 @@
import { IScriptingDefinition } from '@/domain/IScriptingDefinition';
import { ScriptingLanguage } from '@/domain/ScriptingLanguage';
export class ScriptingDefinitionStub implements IScriptingDefinition {
public fileExtension = '.bat';
public language = ScriptingLanguage.batchfile;
public startCode = 'REM start code';
public endCode = 'REM end code';
public withStartCode(startCode: string): ScriptingDefinitionStub {
this.startCode = startCode;
return this;
}
public withEndCode(endCode: string): ScriptingDefinitionStub {
this.endCode = endCode;
return this;
}
public withLanguage(language: ScriptingLanguage): ScriptingDefinitionStub {
this.language = language;
return this;
}
}

View File

@@ -0,0 +1,8 @@
import { SelectedScript } from '@/application/Context/State/Selection/SelectedScript';
import { ScriptStub } from './ScriptStub';
export class SelectedScriptStub extends SelectedScript {
constructor(id: string, revert = false) {
super(new ScriptStub(id), revert);
}
}

View File

@@ -0,0 +1,24 @@
import { ISharedFunction, FunctionBodyType } from '@/application/Parser/Script/Compiler/Function/ISharedFunction';
import { ISharedFunctionCollection } from '@/application/Parser/Script/Compiler/Function/ISharedFunctionCollection';
import { SharedFunctionStub } from './SharedFunctionStub';
export class SharedFunctionCollectionStub implements ISharedFunctionCollection {
private readonly functions = new Map<string, ISharedFunction>();
public withFunction(...funcs: readonly ISharedFunction[]) {
for (const func of funcs) {
this.functions.set(func.name, func);
}
return this;
}
public getFunctionByName(name: string): ISharedFunction {
if (this.functions.has(name)) {
return this.functions.get(name);
}
return new SharedFunctionStub(FunctionBodyType.Code)
.withName(name)
.withCode('code by SharedFunctionCollectionStub')
.withRevertCode('revert-code by SharedFunctionCollectionStub');
}
}

View File

@@ -0,0 +1,68 @@
import { ISharedFunction, ISharedFunctionBody, FunctionBodyType } from '@/application/Parser/Script/Compiler/Function/ISharedFunction';
import { IReadOnlyFunctionParameterCollection } from '@/application/Parser/Script/Compiler/Function/Parameter/IFunctionParameterCollection';
import { IFunctionCall } from '@/application/Parser/Script/Compiler/Function/Call/IFunctionCall';
import { FunctionParameterCollectionStub } from './FunctionParameterCollectionStub';
import { FunctionCallStub } from './FunctionCallStub';
export class SharedFunctionStub implements ISharedFunction {
public name = 'shared-function-stub-name';
public parameters: IReadOnlyFunctionParameterCollection = new FunctionParameterCollectionStub()
.withParameterName('shared-function-stub-parameter-name');
private code = 'shared-function-stub-code';
private revertCode = 'shared-function-stub-revert-code';
private bodyType: FunctionBodyType = FunctionBodyType.Code;
private calls: IFunctionCall[] = [new FunctionCallStub()];
constructor(type: FunctionBodyType) {
this.bodyType = type;
}
public get body(): ISharedFunctionBody {
return {
type: this.bodyType,
code: this.bodyType === FunctionBodyType.Code ? {
do: this.code,
revert: this.revertCode,
} : undefined,
calls: this.bodyType === FunctionBodyType.Calls ? this.calls : undefined,
};
}
public withName(name: string) {
this.name = name;
return this;
}
public withCode(code: string) {
this.code = code;
return this;
}
public withRevertCode(revertCode: string) {
this.revertCode = revertCode;
return this;
}
public withParameters(parameters: IReadOnlyFunctionParameterCollection) {
this.parameters = parameters;
return this;
}
public withCalls(...calls: readonly IFunctionCall[]) {
this.calls = [...calls];
return this;
}
public withParameterNames(...parameterNames: readonly string[]) {
let collection = new FunctionParameterCollectionStub();
for (const name of parameterNames) {
collection = collection.withParameterName(name);
}
return this.withParameters(collection);
}
}

View File

@@ -0,0 +1,27 @@
import { FunctionData } from 'js-yaml-loader!@/*';
import { sequenceEqual } from '@/application/Common/Array';
import { ISharedFunctionCollection } from '@/application/Parser/Script/Compiler/Function/ISharedFunctionCollection';
import { ISharedFunctionsParser } from '@/application/Parser/Script/Compiler/Function/ISharedFunctionsParser';
import { SharedFunctionCollectionStub } from './SharedFunctionCollectionStub';
export class SharedFunctionsParserStub implements ISharedFunctionsParser {
private setupResults = new Array<{
functions: readonly FunctionData[],
result: ISharedFunctionCollection,
}>();
public setup(functions: readonly FunctionData[], result: ISharedFunctionCollection) {
this.setupResults.push({ functions, result });
}
public parseFunctions(functions: readonly FunctionData[]): ISharedFunctionCollection {
const result = this.findResult(functions);
return result || new SharedFunctionCollectionStub();
}
private findResult(functions: readonly FunctionData[]): ISharedFunctionCollection {
return this.setupResults
.find((result) => sequenceEqual(result.functions, functions))
?.result;
}
}

View File

@@ -0,0 +1,19 @@
import { IFilterResult } from '@/application/Context/State/Filter/IFilterResult';
import { IUserFilter } from '@/application/Context/State/Filter/IUserFilter';
import { IEventSource } from '@/infrastructure/Events/IEventSource';
export class UserFilterStub implements IUserFilter {
public currentFilter: IFilterResult;
public filtered: IEventSource<IFilterResult>;
public filterRemoved: IEventSource<void>;
public setFilter(): void {
throw new Error('Method not implemented.');
}
public removeFilter(): void {
throw new Error('Method not implemented.');
}
}

View File

@@ -0,0 +1,64 @@
import { IUserSelection } from '@/application/Context/State/Selection/IUserSelection';
import { SelectedScript } from '@/application/Context/State/Selection/SelectedScript';
import { IScript } from '@/domain/IScript';
import { IEventSource } from '@/infrastructure/Events/IEventSource';
import { EventSource } from '@/infrastructure/Events/EventSource';
export class UserSelectionStub implements IUserSelection {
public readonly changed: IEventSource<readonly SelectedScript[]> =
new EventSource<readonly SelectedScript[]>();
public selectedScripts: readonly SelectedScript[] = [];
constructor(private readonly allScripts: readonly IScript[]) {
}
public withSelectedScripts(selectedScripts: readonly SelectedScript[]) {
this.selectedScripts = selectedScripts;
}
public areAllSelected(): boolean {
throw new Error('Method not implemented.');
}
public isAnySelected(): boolean {
throw new Error('Method not implemented.');
}
public removeAllInCategory(): void {
throw new Error('Method not implemented.');
}
public addOrUpdateAllInCategory(): void {
throw new Error('Method not implemented.');
}
public addSelectedScript(): void {
throw new Error('Method not implemented.');
}
public addOrUpdateSelectedScript(): void {
throw new Error('Method not implemented.');
}
public removeSelectedScript(): void {
throw new Error('Method not implemented.');
}
public selectOnly(scripts: ReadonlyArray<IScript>): void {
this.selectedScripts = scripts.map((s) => new SelectedScript(s, false));
}
public isSelected(): boolean {
throw new Error('Method not implemented.');
}
public selectAll(): void {
this.selectOnly(this.allScripts);
}
public deselectAll(): void {
this.selectedScripts = [];
}
}