瀏覽代碼

Converted Vignere, added more tests and cleaned stuff up

Matt C 7 年之前
父節點
當前提交
6bec68021c

+ 1 - 1
src/core/operations/AffineCipherDecode.mjs

@@ -54,7 +54,7 @@ class AffineCipherDecode extends Operation {
         }
 
         if (Utils.gcd(a, 26) !== 1) {
-            return "The value of a must be coprime to 26.";
+            return "The value of `a` must be coprime to 26.";
         }
 
         for (let i = 0; i < input.length; i++) {

+ 4 - 7
src/core/operations/BifidCipherDecode.mjs

@@ -1,6 +1,6 @@
 /**
- * @author n1474335 [n1474335@gmail.com]
- * @copyright Crown Copyright 2016
+ * @author Matt C [matt@artemisbot.uk]
+ * @copyright Crown Copyright 2018
  * @license Apache-2.0
  */
 
@@ -47,11 +47,8 @@ class BifidCipherDecode extends Operation {
             count = 0,
             trans = "";
 
-        if (keyword.length > 25)
-            return "The alphabet keyword must be less than 25 characters.";
-
-        if (!/^[a-zA-Z]+$/.test(keywordStr) && keyword.length > 0)
-            return "The key must consist only of letters";
+        if (!/^[A-Z]+$/.test(keywordStr) && keyword.length > 0)
+            return "The key must consist only of letters in the English alphabet";
 
         const polybius = genPolybiusSquare(keywordStr);
 

+ 4 - 6
src/core/operations/BifidCipherEncode.mjs

@@ -1,6 +1,6 @@
 /**
- * @author n1474335 [n1474335@gmail.com]
- * @copyright Crown Copyright 2016
+ * @author Matt C [matt@artemisbot.uk]
+ * @copyright Crown Copyright 2018
  * @license Apache-2.0
  */
 
@@ -48,11 +48,9 @@ class BifidCipherEncode extends Operation {
         let output = "",
             count = 0;
 
-        if (keyword.length > 25)
-            return "The alphabet keyword must be less than 25 characters.";
 
-        if (!/^[a-zA-Z]+$/.test(keywordStr) && keyword.length > 0)
-            return "The key must consist only of letters";
+        if (!/^[A-Z]+$/.test(keywordStr) && keyword.length > 0)
+            return "The key must consist only of letters in the English alphabet";
 
         const polybius = genPolybiusSquare(keywordStr);
 

+ 101 - 0
src/core/operations/VigenèreDecode.mjs

@@ -0,0 +1,101 @@
+/**
+ * @author Matt C [matt@artemisbot.uk]
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+
+/**
+ * Vigenère Decode operation
+ */
+class VigenèreDecode extends Operation {
+
+    /**
+     * VigenèreDecode constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "Vigenère Decode";
+        this.module = "Ciphers";
+        this.description = "The Vigenere cipher is a method of encrypting alphabetic text by using a series of different Caesar ciphers based on the letters of a keyword. It is a simple form of polyalphabetic substitution.";
+        this.inputType = "string";
+        this.outputType = "string";
+        this.args = [
+            {
+                "name": "Key",
+                "type": "string",
+                "value": ""
+            }
+        ];
+    }
+
+    /**
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    run(input, args) {
+        const alphabet = "abcdefghijklmnopqrstuvwxyz",
+            key = args[0].toLowerCase();
+        let output = "",
+            fail = 0,
+            keyIndex,
+            msgIndex,
+            chr;
+
+        if (!key) return "No key entered";
+        if (!/^[a-zA-Z]+$/.test(key)) return "The key must consist only of letters";
+
+        for (let i = 0; i < input.length; i++) {
+            if (alphabet.indexOf(input[i]) >= 0) {
+                chr = key[(i - fail) % key.length];
+                keyIndex = alphabet.indexOf(chr);
+                msgIndex = alphabet.indexOf(input[i]);
+                // Subtract indexes from each other, add 26 just in case the value is negative,
+                // modulo to remove if neccessary
+                output += alphabet[(msgIndex - keyIndex + alphabet.length) % 26];
+            } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
+                chr = key[(i - fail) % key.length].toLowerCase();
+                keyIndex = alphabet.indexOf(chr);
+                msgIndex = alphabet.indexOf(input[i].toLowerCase());
+                output += alphabet[(msgIndex + alphabet.length - keyIndex) % 26].toUpperCase();
+            } else {
+                output += input[i];
+                fail++;
+            }
+        }
+
+        return output;
+    }
+
+    /**
+     * Highlight Vigenère Decode
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlight(pos, args) {
+        return pos;
+    }
+
+    /**
+     * Highlight Vigenère Decode in reverse
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlightReverse(pos, args) {
+        return pos;
+    }
+
+}
+
+export default VigenèreDecode;

+ 105 - 0
src/core/operations/VigenèreEncode.mjs

@@ -0,0 +1,105 @@
+/**
+ * @author Matt C [matt@artemisbot.uk]
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+
+/**
+ * Vigenère Encode operation
+ */
+class VigenèreEncode extends Operation {
+
+    /**
+     * VigenèreEncode constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "Vigenère Encode";
+        this.module = "Ciphers";
+        this.description = "The Vigenere cipher is a method of encrypting alphabetic text by using a series of different Caesar ciphers based on the letters of a keyword. It is a simple form of polyalphabetic substitution.";
+        this.inputType = "string";
+        this.outputType = "string";
+        this.args = [
+            {
+                "name": "Key",
+                "type": "string",
+                "value": ""
+            }
+        ];
+    }
+
+    /**
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    run(input, args) {
+        const alphabet = "abcdefghijklmnopqrstuvwxyz",
+            key = args[0].toLowerCase();
+        let output = "",
+            fail = 0,
+            keyIndex,
+            msgIndex,
+            chr;
+
+        if (!key) return "No key entered";
+        if (!/^[a-zA-Z]+$/.test(key)) return "The key must consist only of letters";
+
+        for (let i = 0; i < input.length; i++) {
+            if (alphabet.indexOf(input[i]) >= 0) {
+                // Get the corresponding character of key for the current letter, accounting
+                // for chars not in alphabet
+                chr = key[(i - fail) % key.length];
+                // Get the location in the vigenere square of the key char
+                keyIndex = alphabet.indexOf(chr);
+                // Get the location in the vigenere square of the message char
+                msgIndex = alphabet.indexOf(input[i]);
+                // Get the encoded letter by finding the sum of indexes modulo 26 and finding
+                // the letter corresponding to that
+                output += alphabet[(keyIndex + msgIndex) % 26];
+            } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
+                chr = key[(i - fail) % key.length].toLowerCase();
+                keyIndex = alphabet.indexOf(chr);
+                msgIndex = alphabet.indexOf(input[i].toLowerCase());
+                output += alphabet[(keyIndex + msgIndex) % 26].toUpperCase();
+            } else {
+                output += input[i];
+                fail++;
+            }
+        }
+
+        return output;
+    }
+
+    /**
+     * Highlight Vigenère Encode
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlight(pos, args) {
+        return pos;
+    }
+
+    /**
+     * Highlight Vigenère Encode in reverse
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlightReverse(pos, args) {
+        return pos;
+    }
+
+}
+
+export default VigenèreEncode;

+ 0 - 343
src/core/operations/legacy/Cipher.js

@@ -569,349 +569,6 @@ DES uses a key length of 8 bytes (64 bits).`;
     },
 
 
-    /**
-     * Vigenère Encode operation.
-     *
-     * @author Matt C [matt@artemisbot.uk]
-     * @param {string} input
-     * @param {Object[]} args
-     * @returns {string}
-     */
-    runVigenereEnc: function (input, args) {
-        let alphabet = "abcdefghijklmnopqrstuvwxyz",
-            key = args[0].toLowerCase(),
-            output = "",
-            fail = 0,
-            keyIndex,
-            msgIndex,
-            chr;
-
-        if (!key) return "No key entered";
-        if (!/^[a-zA-Z]+$/.test(key)) return "The key must consist only of letters";
-
-        for (let i = 0; i < input.length; i++) {
-            if (alphabet.indexOf(input[i]) >= 0) {
-                // Get the corresponding character of key for the current letter, accounting
-                // for chars not in alphabet
-                chr = key[(i - fail) % key.length];
-                // Get the location in the vigenere square of the key char
-                keyIndex = alphabet.indexOf(chr);
-                // Get the location in the vigenere square of the message char
-                msgIndex = alphabet.indexOf(input[i]);
-                // Get the encoded letter by finding the sum of indexes modulo 26 and finding
-                // the letter corresponding to that
-                output += alphabet[(keyIndex + msgIndex) % 26];
-            } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
-                chr = key[(i - fail) % key.length].toLowerCase();
-                keyIndex = alphabet.indexOf(chr);
-                msgIndex = alphabet.indexOf(input[i].toLowerCase());
-                output += alphabet[(keyIndex + msgIndex) % 26].toUpperCase();
-            } else {
-                output += input[i];
-                fail++;
-            }
-        }
-
-        return output;
-    },
-
-
-    /**
-     * Vigenère Decode operation.
-     *
-     * @author Matt C [matt@artemisbot.uk]
-     * @param {string} input
-     * @param {Object[]} args
-     * @returns {string}
-     */
-    runVigenereDec: function (input, args) {
-        let alphabet = "abcdefghijklmnopqrstuvwxyz",
-            key = args[0].toLowerCase(),
-            output = "",
-            fail = 0,
-            keyIndex,
-            msgIndex,
-            chr;
-
-        if (!key) return "No key entered";
-        if (!/^[a-zA-Z]+$/.test(key)) return "The key must consist only of letters";
-
-        for (let i = 0; i < input.length; i++) {
-            if (alphabet.indexOf(input[i]) >= 0) {
-                chr = key[(i - fail) % key.length];
-                keyIndex = alphabet.indexOf(chr);
-                msgIndex = alphabet.indexOf(input[i]);
-                // Subtract indexes from each other, add 26 just in case the value is negative,
-                // modulo to remove if neccessary
-                output += alphabet[(msgIndex - keyIndex + alphabet.length) % 26];
-            } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
-                chr = key[(i - fail) % key.length].toLowerCase();
-                keyIndex = alphabet.indexOf(chr);
-                msgIndex = alphabet.indexOf(input[i].toLowerCase());
-                output += alphabet[(msgIndex + alphabet.length - keyIndex) % 26].toUpperCase();
-            } else {
-                output += input[i];
-                fail++;
-            }
-        }
-
-        return output;
-    },
-
-
-    /**
-     * @constant
-     * @default
-     */
-    AFFINE_A: 1,
-    /**
-     * @constant
-     * @default
-     */
-    AFFINE_B: 0,
-
-    /**
-     * Affine Cipher Encode operation.
-     *
-     * @author Matt C [matt@artemisbot.uk]
-     * @param {string} input
-     * @param {Object[]} args
-     * @returns {string}
-     */
-    runAffineEnc: function (input, args) {
-        let alphabet = "abcdefghijklmnopqrstuvwxyz",
-            a = args[0],
-            b = args[1],
-            output = "";
-
-        if (!/^\+?(0|[1-9]\d*)$/.test(a) || !/^\+?(0|[1-9]\d*)$/.test(b)) {
-            return "The values of a and b can only be integers.";
-        }
-
-        for (let i = 0; i < input.length; i++) {
-            if (alphabet.indexOf(input[i]) >= 0) {
-                // Uses the affine function ax+b % m = y (where m is length of the alphabet)
-                output += alphabet[((a * alphabet.indexOf(input[i])) + b) % 26];
-            } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
-                // Same as above, accounting for uppercase
-                output += alphabet[((a * alphabet.indexOf(input[i].toLowerCase())) + b) % 26].toUpperCase();
-            } else {
-                // Non-alphabetic characters
-                output += input[i];
-            }
-        }
-        return output;
-    },
-
-
-    /**
-     * Affine Cipher Decode operation.
-     *
-     * @author Matt C [matt@artemisbot.uk]
-     * @param {string} input
-     * @param {Object[]} args
-     * @returns {string}
-     */
-    runAffineDec: function (input, args) {
-        let alphabet = "abcdefghijklmnopqrstuvwxyz",
-            a = args[0],
-            b = args[1],
-            output = "",
-            aModInv;
-
-        if (!/^\+?(0|[1-9]\d*)$/.test(a) || !/^\+?(0|[1-9]\d*)$/.test(b)) {
-            return "The values of a and b can only be integers.";
-        }
-
-        if (Utils.gcd(a, 26) !== 1) {
-            return "The value of a must be coprime to 26.";
-        }
-
-        // Calculates modular inverse of a
-        aModInv = Utils.modInv(a, 26);
-
-        for (let i = 0; i < input.length; i++) {
-            if (alphabet.indexOf(input[i]) >= 0) {
-                // Uses the affine decode function (y-b * A') % m = x (where m is length of the alphabet and A' is modular inverse)
-                output += alphabet[Utils.mod((alphabet.indexOf(input[i]) - b) * aModInv, 26)];
-            } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
-                // Same as above, accounting for uppercase
-                output += alphabet[Utils.mod((alphabet.indexOf(input[i].toLowerCase()) - b) * aModInv, 26)].toUpperCase();
-            } else {
-                // Non-alphabetic characters
-                output += input[i];
-            }
-        }
-        return output;
-    },
-
-
-    /**
-     * Atbash Cipher Encode operation.
-     *
-     * @author Matt C [matt@artemisbot.uk]
-     * @param {string} input
-     * @param {Object[]} args
-     * @returns {string}
-     */
-    runAtbash: function (input, args) {
-        return Cipher.runAffineEnc(input, [25, 25]);
-    },
-
-
-    /**
-     * Generates a polybius square for the given keyword
-     *
-     * @private
-     * @author Matt C [matt@artemisbot.uk]
-     * @param {string} keyword - Must be upper case
-     * @returns {string}
-     */
-    _genPolybiusSquare: function (keyword) {
-        const alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
-        const polArray = `${keyword}${alpha}`.split("").unique();
-        let polybius = [];
-
-        for (let i = 0; i < 5; i++) {
-            polybius[i] = polArray.slice(i*5, i*5 + 5);
-        }
-
-        return polybius;
-    },
-
-    /**
-     * Bifid Cipher Encode operation
-     *
-     * @author Matt C [matt@artemisbot.uk]
-     * @param {string} input
-     * @param {Object[]} args
-     * @returns {string}
-     */
-    runBifidEnc: function (input, args) {
-        const keywordStr = args[0].toUpperCase().replace("J", "I"),
-            keyword = keywordStr.split("").unique(),
-            alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
-
-        let output = "",
-            xCo = [],
-            yCo = [],
-            structure = [],
-            count = 0;
-
-        if (keyword.length > 25)
-            return "The alphabet keyword must be less than 25 characters.";
-
-        if (!/^[a-zA-Z]+$/.test(keywordStr) && keyword.length > 0)
-            return "The key must consist only of letters";
-
-        const polybius = Cipher._genPolybiusSquare(keywordStr);
-
-        input.replace("J", "I").split("").forEach(letter => {
-            let alpInd = alpha.split("").indexOf(letter.toLocaleUpperCase()) >= 0,
-                polInd;
-
-            if (alpInd) {
-                for (let i = 0; i < 5; i++) {
-                    polInd = polybius[i].indexOf(letter.toLocaleUpperCase());
-                    if (polInd >= 0) {
-                        xCo.push(polInd);
-                        yCo.push(i);
-                    }
-                }
-
-                if (alpha.split("").indexOf(letter) >= 0) {
-                    structure.push(true);
-                } else if (alpInd) {
-                    structure.push(false);
-                }
-            } else {
-                structure.push(letter);
-            }
-        });
-
-        const trans = `${yCo.join("")}${xCo.join("")}`;
-
-        structure.forEach(pos => {
-            if (typeof pos === "boolean") {
-                let coords = trans.substr(2*count, 2).split("");
-
-                output += pos ?
-                    polybius[coords[0]][coords[1]] :
-                    polybius[coords[0]][coords[1]].toLocaleLowerCase();
-                count++;
-            } else {
-                output += pos;
-            }
-        });
-
-        return output;
-    },
-
-    /**
-     * Bifid Cipher Decode operation
-     *
-     * @author Matt C [matt@artemisbot.uk]
-     * @param {string} input
-     * @param {Object[]} args
-     * @returns {string}
-     */
-    runBifidDec: function (input, args) {
-        const keywordStr = args[0].toUpperCase().replace("J", "I"),
-            keyword = keywordStr.split("").unique(),
-            alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
-
-        let output = "",
-            structure = [],
-            count = 0,
-            trans = "";
-
-        if (keyword.length > 25)
-            return "The alphabet keyword must be less than 25 characters.";
-
-        if (!/^[a-zA-Z]+$/.test(keywordStr) && keyword.length > 0)
-            return "The key must consist only of letters";
-
-        const polybius = Cipher._genPolybiusSquare(keywordStr);
-
-        input.replace("J", "I").split("").forEach((letter) => {
-            let alpInd = alpha.split("").indexOf(letter.toLocaleUpperCase()) >= 0,
-                polInd;
-
-            if (alpInd) {
-                for (let i = 0; i < 5; i++) {
-                    polInd = polybius[i].indexOf(letter.toLocaleUpperCase());
-                    if (polInd >= 0) {
-                        trans += `${i}${polInd}`;
-                    }
-                }
-
-                if (alpha.split("").indexOf(letter) >= 0) {
-                    structure.push(true);
-                } else if (alpInd) {
-                    structure.push(false);
-                }
-            } else {
-                structure.push(letter);
-            }
-        });
-
-        structure.forEach(pos => {
-            if (typeof pos === "boolean") {
-                let coords = [trans[count], trans[count+trans.length/2]];
-
-                output += pos ?
-                    polybius[coords[0]][coords[1]] :
-                    polybius[coords[0]][coords[1]].toLocaleLowerCase();
-                count++;
-            } else {
-                output += pos;
-            }
-        });
-
-        return output;
-    },
-
-
     /**
      * @constant
      * @default

+ 143 - 0
test/tests/operations/Ciphers.mjs

@@ -22,6 +22,17 @@ TestRegister.addTests([
             }
         ],
     },
+    {
+        name: "Affine Encode: invalid a & b (non-integer)",
+        input: "some keys are shaped as locks. index[me]",
+        expectedOutput: "The values of a and b can only be integers.",
+        recipeConfig: [
+            {
+                op: "Affine Cipher Encode",
+                args: [0.1, 0.00001]
+            }
+        ],
+    },
     {
         name: "Affine Encode: no effect",
         input: "some keys are shaped as locks. index[me]",
@@ -55,6 +66,28 @@ TestRegister.addTests([
             }
         ],
     },
+    {
+        name: "Affine Decode: invalid a & b (non-integer)",
+        input: "vhnl tldv xyl vcxelo xv qhrtv. zkolg[nl]",
+        expectedOutput: "The values of a and b can only be integers.",
+        recipeConfig: [
+            {
+                op: "Affine Cipher Decode",
+                args: [0.1, 0.00001]
+            }
+        ],
+    },
+    {
+        name: "Affine Decode: invalid a (coprime)",
+        input: "vhnl tldv xyl vcxelo xv qhrtv. zkolg[nl]",
+        expectedOutput: "The value of `a` must be coprime to 26.",
+        recipeConfig: [
+            {
+                op: "Affine Cipher Decode",
+                args: [8, 23]
+            }
+        ],
+    },
     {
         name: "Affine Decode: no effect",
         input: "vhnl tldv xyl vcxelo xv qhrtv. zkolg[nl]",
@@ -121,6 +154,17 @@ TestRegister.addTests([
             }
         ],
     },
+    {
+        name: "Bifid Cipher Encode: invalid key (non-alphabetic)",
+        input: "We recreate conditions similar to the Van-Allen radiation belt in our secure facilities.",
+        expectedOutput: "The key must consist only of letters in the English alphabet",
+        recipeConfig: [
+            {
+                "op": "Bifid Cipher Encode",
+                "args": ["abc123"]
+            }
+        ],
+    },
     {
         name: "Bifid Cipher Encode: normal",
         input: "We recreate conditions similar to the Van-Allen radiation belt in our secure facilities.",
@@ -154,6 +198,17 @@ TestRegister.addTests([
             }
         ],
     },
+    {
+        name: "Bifid Cipher Decode: invalid key (non-alphabetic)",
+        input: "Vq daqcliho rmltofvlnc qbdhlcr nt qdq Fbm-Rdkkm vuoottnoi aitp al axf tdtmvt owppkaodtx.",
+        expectedOutput: "The key must consist only of letters in the English alphabet",
+        recipeConfig: [
+            {
+                "op": "Bifid Cipher Decode",
+                "args": ["abc123"]
+            }
+        ],
+    },
     {
         name: "Bifid Cipher Decode: normal",
         input: "Wc snpsigdd cpfrrcxnfi hikdnnp dm crc Fcb-Pdeug vueageacc vtyl sa zxm crebzp lyoeuaiwpv.",
@@ -165,4 +220,92 @@ TestRegister.addTests([
             }
         ],
     },
+    {
+        name: "Vigenère Encode: no input",
+        input: "",
+        expectedOutput: "",
+        recipeConfig: [
+            {
+                "op": "Vigenère Encode",
+                "args": ["nothing"]
+            }
+        ],
+    },
+    {
+        name: "Vigenère Encode: no key",
+        input: "LUGGAGEBASEMENTVARENNESALLIESCANBECLOTHEDASENEMIESENEMIESCANBECLOTHEDASALLIESALWAYSUSEID",
+        expectedOutput: "No key entered",
+        recipeConfig: [
+            {
+                "op": "Vigenère Encode",
+                "args": [""]
+            }
+        ],
+    },
+    {
+        name: "Vigenère Encode: invalid key",
+        input: "LUGGAGEBASEMENTVARENNESALLIESCANBECLOTHEDASENEMIESENEMIESCANBECLOTHEDASALLIESALWAYSUSEID",
+        expectedOutput: "The key must consist only of letters",
+        recipeConfig: [
+            {
+                "op": "Vigenère Encode",
+                "args": ["abc123"]
+            }
+        ],
+    },
+    {
+        name: "Vigenère Encode: normal",
+        input: "LUGGAGEBASEMENTVARENNESALLIESCANBECLOTHEDASENEMIESENEMIESCANBECLOTHEDASALLIESALWAYSUSEID",
+        expectedOutput: "PXCGRJIEWSVPIQPVRUIQJEJDPOEEJFEQXETOSWDEUDWHJEDLIVANVPMHOCRQFHYLFWLHZAJDPOEEJDPZWYJXWHED",
+        recipeConfig: [
+            {
+                "op": "Vigenère Encode",
+                "args": ["Edward"]
+            }
+        ],
+    },
+    {
+        name: "Vigenère Decode: no input",
+        input: "",
+        expectedOutput: "",
+        recipeConfig: [
+            {
+                "op": "Vigenère Decode",
+                "args": ["nothing"]
+            }
+        ],
+    },
+    {
+        name: "Vigenère Decode: no key",
+        input: "PXCGRJIEWSVPIQPVRUIQJEJDPOEEJFEQXETOSWDEUDWHJEDLIVANVPMHOCRQFHYLFWLHZAJDPOEEJDPZWYJXWHED",
+        expectedOutput: "No key entered",
+        recipeConfig: [
+            {
+                "op": "Vigenère Decode",
+                "args": [""]
+            }
+        ],
+    },
+    {
+        name: "Vigenère Decode: invalid key",
+        input: "PXCGRJIEWSVPIQPVRUIQJEJDPOEEJFEQXETOSWDEUDWHJEDLIVANVPMHOCRQFHYLFWLHZAJDPOEEJDPZWYJXWHED",
+        expectedOutput: "The key must consist only of letters",
+        recipeConfig: [
+            {
+                "op": "Vigenère Decode",
+                "args": ["abc123"]
+            }
+        ],
+    },
+    {
+        name: "Vigenère Decode: normal",
+        input: "PXCGRJIEWSVPIQPVRUIQJEJDPOEEJFEQXETOSWDEUDWHJEDLIVANVPMHOCRQFHYLFWLHZAJDPOEEJDPZWYJXWHED",
+        expectedOutput: "LUGGAGEBASEMENTVARENNESALLIESCANBECLOTHEDASENEMIESENEMIESCANBECLOTHEDASALLIESALWAYSUSEID",
+        recipeConfig: [
+            {
+                "op": "Vigenère Decode",
+                "args": ["Edward"]
+            }
+        ],
+    },
 ]);