diff --git a/src/_Classics_/caesar_cipher/caesarCipher.test.js b/src/_Classics_/caesar_cipher/caesarCipher.test.js new file mode 100644 index 00000000..cfa68026 --- /dev/null +++ b/src/_Classics_/caesar_cipher/caesarCipher.test.js @@ -0,0 +1,67 @@ +/* eslint-disable linebreak-style */ +/* eslint-disable no-else-return */ +const caesarCipher = require('./caeserCipher'); + +describe('Caesar Cipher tests', () => { + it('Shift not passed', () => { + const ocString = 'Hello World'; + const enCiphered = caesarCipher(ocString); + expect(ocString).toBe(enCiphered); + }); + + it('Encipher equals decipher', () => { + const ocString = 'Hello World'; + const enCiphered = caesarCipher(ocString, 1); + const deCiphered = caesarCipher(enCiphered, -1); + expect(ocString).toBe(deCiphered); + }); + + it('Shift lower than string length works', () => { + const ocString = 'Hello World'; + const enCiphered = caesarCipher(ocString, 1); + const idealResult = 'Ifmmp Xpsme'; + expect(enCiphered).toBe(idealResult); + }); + + it('Shift Higher than string length works', () => { + const ocString = 'Hello World'; + const enCiphered = caesarCipher(ocString, 63); + const idealResult = caesarCipher(ocString, 1); + expect(enCiphered).toBe(idealResult); + }); + + it('Negative shift Works', () => { + const ocString = 'Ifmmp Xpsme'; + const enCiphered = caesarCipher(ocString, -1); + const idealResult = 'Hello World'; + expect(enCiphered).toBe(idealResult); + }); + + it('Shift is a numerical string', () => { + const ocString = 'Hello World'; + const enCiphered = caesarCipher(ocString, '1'); + const idealResult = 'Ifmmp Xpsme'; + expect(enCiphered).toBe(idealResult); + }); + + it('Shift is not a numbered string', () => { + function test() { + caesarCipher('Hello World', 'abc'); + } + expect(test).toThrow('Invalid Shift Provided'); + }); + + it('toEncipher is NaN', () => { + function test() { + caesarCipher(NaN, 1); + } + expect(test).toThrowError('Invalid string provided'); + }); + + it('toEncipher is undefined', () => { + function test() { + caesarCipher(undefined, 1); + } + expect(test).toThrowError('Invalid string provided'); + }); +}); diff --git a/src/_Classics_/caesar_cipher/caeserCipher.js b/src/_Classics_/caesar_cipher/caeserCipher.js new file mode 100644 index 00000000..3988dafe --- /dev/null +++ b/src/_Classics_/caesar_cipher/caeserCipher.js @@ -0,0 +1,46 @@ +/** + * Most simplest encryption scheme. Read more: [http://practicalcryptography.com/ciphers/caesar-cipher/] + **/ +function caesarCipher(toEncipher, shift = 0) { + // If required for very strict shift checking then remove '=0' + if (Number.isNaN(Number(shift)) === true) { + throw new Error('Invalid Shift Provided'); + } else { + shift = parseInt(Number(shift), 10); + } + + if (typeof (toEncipher) === 'string' || (typeof (toEncipher) === 'number' && Number.isNaN(toEncipher) === false)) { + toEncipher = String(toEncipher); + } else { + throw new Error('Invalid string provided'); + } + + // These are the valid entries aacepted, you can change it according to requirements + const validEntries = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + + shift %= validEntries.length; + + let output = ''; + for (const char of toEncipher) { + if (char === ' ') { + output += ' '; + continue; + // ------- If you donot want to accept invalid entries then uncomment below block + /* + ======================================================================================================== + } else if (validEntries.indexOf(char) === -1) {return Error ('invalid character' + char)} + ======================================================================================================== + and comment out the below block + */ + //= ====================================================================================================== + } else if (validEntries.indexOf(char) === -1) { + output += char; + continue; + } + //= ====================================================================================================== + output += (validEntries.indexOf(char) + shift <= validEntries.length) ? validEntries[validEntries.indexOf(char) + shift] : validEntries[(validEntries.indexOf(char) + shift) % validEntries.length]; + } + return output; +} + +module.exports = caesarCipher; diff --git a/src/_Classics_/caeser_cipher/index.js b/src/_Classics_/caeser_cipher/index.js deleted file mode 100644 index 8851bf03..00000000 --- a/src/_Classics_/caeser_cipher/index.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Most simplest encryption scheme. Read more: [http://practicalcryptography.com/ciphers/caesar-cipher/] - * @param {String} str - * @param {Number} num - */ - -function caesarCipher(str, num) { - if (!num) throw new Error('Missing argument: num'); - - const lowerCaseString = str.toLowerCase(); - const alphabets = 'abcdefghijklmnopqrstuvwxyz'.split(''); - const totalAlphabets = alphabets.length; - let result = ''; - - // handle large number, like 300 or -300 - num %= totalAlphabets; - - const alphabetsMap = new Map(); - - for (const index in alphabets) { - alphabetsMap[alphabets[index]] = index; - } - - for (let index in lowerCaseString) { - // get the current character - const currentCharacter = lowerCaseString[index]; - - // if character is space, add it to the result and continue to next - if (currentCharacter === ' ') { - result += currentCharacter; - continue; - } - - // determine the new index - /** - * const currentIndex = alphabets.indexOf(currentCharacter); - * - * With indexOf complexity will be O(n*26) - * With Map complexity will be O(n). - */ - const currentIndex = Number(alphabetsMap[currentCharacter]); - let newIndex = currentIndex + num; - - // if the index passes 25, restart from 0 - if (newIndex > totalAlphabets - 1) { - newIndex -= totalAlphabets; - } - - if (newIndex < 0) { - newIndex = totalAlphabets + newIndex; - } - - // check if the character in original string was upper case - if (str[index] === str[index].toUpperCase()) { - result += alphabets[newIndex].toUpperCase(); - } else { - result += alphabets[newIndex]; - } - } - return result; -}