feat: Implement automated option-type ingredient validation (#2625)
This commit is contained in:
parent
9ab5108664
commit
86746296be
@ -76,8 +76,15 @@ class Ingredient {
|
|||||||
if (this.disabled) return true;
|
if (this.disabled) return true;
|
||||||
|
|
||||||
let checkVal = val;
|
let checkVal = val;
|
||||||
if (this.type === "toggleString" && val && typeof val === "object" && "string" in val) {
|
if (checkVal === null || checkVal === undefined) {
|
||||||
checkVal = val.string;
|
checkVal = this.defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.type === "toggleString" && checkVal && typeof checkVal === "object" && "string" in checkVal) {
|
||||||
|
checkVal = checkVal.string;
|
||||||
|
}
|
||||||
|
if (this.type === "option" && Array.isArray(checkVal)) {
|
||||||
|
checkVal = checkVal[this.defaultIndex ?? 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. check if empty
|
// 1. check if empty
|
||||||
@ -89,7 +96,11 @@ class Ingredient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isEmpty) {
|
if (isEmpty) {
|
||||||
if (this.allowEmpty === false) {
|
let isAllowedOptionEmpty = false;
|
||||||
|
if (this.type === "option" && Array.isArray(this.defaultValue)) {
|
||||||
|
isAllowedOptionEmpty = this.defaultValue.includes("");
|
||||||
|
}
|
||||||
|
if (this.allowEmpty === false || (this.type === "option" && !isAllowedOptionEmpty)) {
|
||||||
throw new OperationError(`${this.name} cannot be empty.`);
|
throw new OperationError(`${this.name} cannot be empty.`);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -110,20 +121,35 @@ class Ingredient {
|
|||||||
|
|
||||||
// 3. number checks
|
// 3. number checks
|
||||||
if (this.type === "number") {
|
if (this.type === "number") {
|
||||||
if (val === null || val === undefined || isNaN(val)) {
|
if (checkVal === null || checkVal === undefined || isNaN(checkVal)) {
|
||||||
throw new OperationError(`${this.name} must be a number.`);
|
throw new OperationError(`${this.name} must be a number.`);
|
||||||
}
|
}
|
||||||
if (this.integer && !Number.isInteger(val)) {
|
if (this.integer && !Number.isInteger(checkVal)) {
|
||||||
throw new OperationError(`${this.name} must be an integer.`);
|
throw new OperationError(`${this.name} must be an integer.`);
|
||||||
}
|
}
|
||||||
if (typeof this.min === "number" && val < this.min) {
|
if (typeof this.min === "number" && checkVal < this.min) {
|
||||||
throw new OperationError(`${this.name} must be greater than or equal to ${this.min}.`);
|
throw new OperationError(`${this.name} must be greater than or equal to ${this.min}.`);
|
||||||
}
|
}
|
||||||
if (typeof this.max === "number" && val > this.max) {
|
if (typeof this.max === "number" && checkVal > this.max) {
|
||||||
throw new OperationError(`${this.name} must be less than or equal to ${this.max}.`);
|
throw new OperationError(`${this.name} must be less than or equal to ${this.max}.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 4. option checks
|
||||||
|
if (this.type === "option") {
|
||||||
|
if (Array.isArray(this.defaultValue)) {
|
||||||
|
const permittedOptions = this.defaultValue.filter(opt => {
|
||||||
|
if (typeof opt !== "string") return false;
|
||||||
|
return !opt.match(/^\[\/?[a-z0-9 -()^]+\]$/i);
|
||||||
|
});
|
||||||
|
const valStr = (checkVal !== null && checkVal !== undefined) ? String(checkVal).toLowerCase() : "";
|
||||||
|
const matchedOption = permittedOptions.find(opt => opt.toLowerCase() === valStr);
|
||||||
|
if (!matchedOption) {
|
||||||
|
throw new OperationError(`${this.name} must be one of the following: ${permittedOptions.join(", ")}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -60,6 +60,12 @@ class AutomatedValidationTestOp extends Operation {
|
|||||||
},
|
},
|
||||||
"toggleValues": ["Option A", "Option B"],
|
"toggleValues": ["Option A", "Option B"],
|
||||||
"allowEmpty": false
|
"allowEmpty": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Option Ingredient",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["[Group 1]", "Option 1", "Option 2", "[/Group 1]", "[Group 2]", "Option 3", "[/Group 2]"],
|
||||||
|
"allowEmpty": false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,7 @@ class SM4Encrypt extends Operation {
|
|||||||
{
|
{
|
||||||
"name": "Mode",
|
"name": "Mode",
|
||||||
"type": "option",
|
"type": "option",
|
||||||
"value": ["CBC", "CFB", "OFB", "CTR", "ECB"]
|
"value": ["CBC", "CFB", "OFB", "CTR", "ECB", "CBC/NoPadding", "ECB/NoPadding"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Input",
|
"name": "Input",
|
||||||
|
|||||||
@ -74,7 +74,7 @@ function transformArgs(opArgsList, newArgs) {
|
|||||||
return opArgs.map((arg) => {
|
return opArgs.map((arg) => {
|
||||||
if (arg.type === "option") {
|
if (arg.type === "option") {
|
||||||
// pick default option if not already chosen
|
// pick default option if not already chosen
|
||||||
return typeof arg.value === "string" ? arg.value : arg.value[arg.defaultIndex ?? 0];
|
return !Array.isArray(arg.value) ? arg.value : arg.value[arg.defaultIndex ?? 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg.type === "editableOption") {
|
if (arg.type === "editableOption") {
|
||||||
|
|||||||
@ -15,7 +15,7 @@ TestRegister.addTests([
|
|||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Automated Validation Test Op",
|
op: "Automated Validation Test Op",
|
||||||
args: [5, 1.5, "hello", "", { "option": "Option A", "string": "test" }]
|
args: [5, 1.5, "hello", "", { "option": "Option A", "string": "test" }, "Option 1"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -26,7 +26,7 @@ TestRegister.addTests([
|
|||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Automated Validation Test Op",
|
op: "Automated Validation Test Op",
|
||||||
args: [4, 1.5, "hello", "", { "option": "Option A", "string": "test" }]
|
args: [4, 1.5, "hello", "", { "option": "Option A", "string": "test" }, "Option 1"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -37,7 +37,7 @@ TestRegister.addTests([
|
|||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Automated Validation Test Op",
|
op: "Automated Validation Test Op",
|
||||||
args: [11, 1.5, "hello", "", { "option": "Option A", "string": "test" }]
|
args: [11, 1.5, "hello", "", { "option": "Option A", "string": "test" }, "Option 1"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -48,7 +48,7 @@ TestRegister.addTests([
|
|||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Automated Validation Test Op",
|
op: "Automated Validation Test Op",
|
||||||
args: [5.5, 1.5, "hello", "", { "option": "Option A", "string": "test" }]
|
args: [5.5, 1.5, "hello", "", { "option": "Option A", "string": "test" }, "Option 1"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -59,7 +59,7 @@ TestRegister.addTests([
|
|||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Automated Validation Test Op",
|
op: "Automated Validation Test Op",
|
||||||
args: [5, 1.4, "hello", "", { "option": "Option A", "string": "test" }]
|
args: [5, 1.4, "hello", "", { "option": "Option A", "string": "test" }, "Option 1"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -70,7 +70,7 @@ TestRegister.addTests([
|
|||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Automated Validation Test Op",
|
op: "Automated Validation Test Op",
|
||||||
args: [5, 5.6, "hello", "", { "option": "Option A", "string": "test" }]
|
args: [5, 5.6, "hello", "", { "option": "Option A", "string": "test" }, "Option 1"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -81,7 +81,7 @@ TestRegister.addTests([
|
|||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Automated Validation Test Op",
|
op: "Automated Validation Test Op",
|
||||||
args: [5, 1.5, "helloooo", "", { "option": "Option A", "string": "test" }]
|
args: [5, 1.5, "helloooo", "", { "option": "Option A", "string": "test" }, "Option 1"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -92,7 +92,7 @@ TestRegister.addTests([
|
|||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Automated Validation Test Op",
|
op: "Automated Validation Test Op",
|
||||||
args: [5, 1.5, "", "", { "option": "Option A", "string": "test" }]
|
args: [5, 1.5, "", "", { "option": "Option A", "string": "test" }, "Option 1"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -103,7 +103,7 @@ TestRegister.addTests([
|
|||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Automated Validation Test Op",
|
op: "Automated Validation Test Op",
|
||||||
args: [5, 1.5, "hello", "", { "option": "Option A", "string": "test" }]
|
args: [5, 1.5, "hello", "", { "option": "Option A", "string": "test" }, "Option 1"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -114,7 +114,40 @@ TestRegister.addTests([
|
|||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Automated Validation Test Op",
|
op: "Automated Validation Test Op",
|
||||||
args: [5, 1.5, "hello", "", { "option": "Option A", "string": "" }]
|
args: [5, 1.5, "hello", "", { "option": "Option A", "string": "" }, "Option 1"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Automated Validation: Invalid Option value",
|
||||||
|
input: "test",
|
||||||
|
expectedOutput: "Option Ingredient must be one of the following: Option 1, Option 2, Option 3.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Automated Validation Test Op",
|
||||||
|
args: [5, 1.5, "hello", "", { "option": "Option A", "string": "test" }, "Option 4"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Automated Validation: Option value as optgroup heading (invalid)",
|
||||||
|
input: "test",
|
||||||
|
expectedOutput: "Option Ingredient must be one of the following: Option 1, Option 2, Option 3.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Automated Validation Test Op",
|
||||||
|
args: [5, 1.5, "hello", "", { "option": "Option A", "string": "test" }, "[Group 1]"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Automated Validation: Option value empty (invalid)",
|
||||||
|
input: "test",
|
||||||
|
expectedOutput: "Option Ingredient cannot be empty.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Automated Validation Test Op",
|
||||||
|
args: [5, 1.5, "hello", "", { "option": "Option A", "string": "test" }, ""]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -71,7 +71,7 @@ TestRegister.addTests([
|
|||||||
{
|
{
|
||||||
name: "Encode text: empty encoding",
|
name: "Encode text: empty encoding",
|
||||||
input: "hello",
|
input: "hello",
|
||||||
expectedOutput: "Invalid encoding",
|
expectedOutput: "Encoding cannot be empty.",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Encode text",
|
"op": "Encode text",
|
||||||
@ -82,7 +82,7 @@ TestRegister.addTests([
|
|||||||
{
|
{
|
||||||
name: "Decode text: empty encoding",
|
name: "Decode text: empty encoding",
|
||||||
input: "68 65 6c 6c 6f",
|
input: "68 65 6c 6c 6f",
|
||||||
expectedOutput: "Invalid encoding",
|
expectedOutput: "Encoding cannot be empty.",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "From Hex",
|
"op": "From Hex",
|
||||||
|
|||||||
@ -67,12 +67,12 @@ TestRegister.addTests([
|
|||||||
{
|
{
|
||||||
name: "Generate Lorem Ipsum: Incorrect lengthType",
|
name: "Generate Lorem Ipsum: Incorrect lengthType",
|
||||||
input: "",
|
input: "",
|
||||||
expectedOutput: "Invalid length type",
|
expectedOutput: "Length in must be one of the following: Paragraphs, Sentences, Words, Bytes.",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Generate Lorem Ipsum",
|
"op": "Generate Lorem Ipsum",
|
||||||
"args": [999_999, "Novels"]
|
"args": [999_999, "Novels"]
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -48,7 +48,7 @@ TestRegister.addTests([
|
|||||||
{
|
{
|
||||||
name: "Generate Image: empty mode",
|
name: "Generate Image: empty mode",
|
||||||
input: "",
|
input: "",
|
||||||
expectedOutput: "Unsupported Mode: ()",
|
expectedOutput: "Mode cannot be empty.",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Generate Image",
|
op: "Generate Image",
|
||||||
|
|||||||
@ -113,7 +113,7 @@ TestRegister.addTests([
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"op": "SM2 Decrypt",
|
"op": "SM2 Decrypt",
|
||||||
"args": [PRIVATE_K, "C1C2C2", CURVE]
|
"args": [PRIVATE_K, "C1C2C3", CURVE]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user