Skip to content

Instantly share code, notes, and snippets.

@frogandcode
Created February 16, 2010 02:50
Show Gist options
  • Save frogandcode/305242 to your computer and use it in GitHub Desktop.
Save frogandcode/305242 to your computer and use it in GitHub Desktop.
require 'test/unit'
# Note: Encrypted strings used to validate the tests below code were generated at:
# http://www.braingle.com/brainteasers/codes/caesar.php
# So if the tests pass, they either validate my code or we both have the same bugs :)
class CaesarCipherTest < Test::Unit::TestCase
QUICK_BROWN_FOX = "the quick brown fox jumps over the lazy dog"
QUICK_BROWN_FOX_SHIFT_3 = "wkh txlfn eurzq ira mxpsv ryhu wkh odcb grj"
DEAR_BRUTUS = "The fault, dear Brutus, lies not in our stars but in ourselves."
def test_encrypt
assert_equal QUICK_BROWN_FOX_SHIFT_3, CaesarCipher.encrypt(QUICK_BROWN_FOX)
end
def test_encrypt_uppercase_string_produces_upper_case_result
assert_equal QUICK_BROWN_FOX_SHIFT_3.upcase, CaesarCipher.encrypt(QUICK_BROWN_FOX.upcase)
end
def test_encrypt_with_non_default_shift
encrypted_shift_8 = "bpm ycqks jzwev nwf rcuxa wdmz bpm tihg lwo"
assert_equal encrypted_shift_8, CaesarCipher.encrypt(QUICK_BROWN_FOX, 8)
end
def test_encrypt_with_negative_shift
encrypted_shift_minus_8 = "lzw imauc tjgof xgp bmehk gnwj lzw dsrq vgy"
assert_equal encrypted_shift_minus_8, CaesarCipher.encrypt(QUICK_BROWN_FOX, -8)
end
# Just in case we rigged our impl for the quick brown fox and lazy dog
def test_encrypt_different_string_with_mixed_case
brutus_shift_19 = "Max ytnem, wxtk Uknmnl, ebxl ghm bg hnk lmtkl unm bg hnklxeoxl."
assert_equal brutus_shift_19, CaesarCipher.encrypt(DEAR_BRUTUS, 19), "should preserve case"
end
def test_decrypt
assert_equal QUICK_BROWN_FOX, CaesarCipher.decrypt(QUICK_BROWN_FOX_SHIFT_3)
end
def test_decrypt_uppercase_string_produces_upper_case_result
assert_equal QUICK_BROWN_FOX.upcase, CaesarCipher.decrypt(QUICK_BROWN_FOX_SHIFT_3.upcase)
end
def test_decrypt_with_non_default_shift
encrypted_shift_13 = "gur dhvpx oebja sbk whzcf bire gur ynml qbt"
assert_equal QUICK_BROWN_FOX, CaesarCipher.decrypt(encrypted_shift_13, 13)
end
def test_decrypt_different_string_with_mixed_case
brutus_shift_17 = "Kyv wrlck, uvri Silklj, czvj efk ze fli jkrij slk ze flijvcmvj."
assert_equal DEAR_BRUTUS, CaesarCipher.decrypt(brutus_shift_17, 17)
end
def test_encrypt_and_decrypt_with_alphabet_size_shift_produce_original
assert_equal DEAR_BRUTUS, CaesarCipher.encrypt(DEAR_BRUTUS, 26)
assert_equal DEAR_BRUTUS, CaesarCipher.decrypt(DEAR_BRUTUS, 26)
end
end
# Api for applying a simple Caesar Cipher algorithm (http://en.wikipedia.org/wiki/Caesar_cipher)
# to encrypt and decrypt strings.
class CaesarCipher
ALPHABET = ('a'..'z').to_a
class << self
# Encrypts the string passed, preserving the case of its characters
# so that subsequent decryption will read exactly as the original.
# Handles positive or negative values for the shift.
def encrypt(string, shift=3)
string.chars.map {|c| encrypt_char(c, shift)}.to_s
end
# Decrypts the string passed, preserving the case of its characters.
def decrypt(string, shift=3)
string.chars.map {|c| decrypt_char(c, shift)}.to_s
end
protected
def encrypt_char(char, shift=3)
shift_char(char, shift, true)
end
def decrypt_char(char, shift=3)
shift_char(char, shift, false)
end
# Returns case-sensitive shift transformation of the character passed if it's a letter,
# or the character itself if it's not. Also handles negative shifts.
def shift_char(char, shift, shift_forward=true)
pos = ALPHABET.index(char.downcase)
# If char not in alphabet, simply return it. Handles spaces, punctuation, numbers, etc.
return char if pos.nil?
shift = (shift < 0) ? shift + ALPHABET.length : shift # Handle negative shift
shift_pos_without_mod = shift_forward ? (pos + shift) : (pos - shift)
shifted_pos = shift_pos_without_mod % ALPHABET.length
shifted_char = ALPHABET[shifted_pos]
case_sensitive_char(char, shifted_char) # Keep case of char passed
end
def case_sensitive_char(input_char, result_char)
input_char.downcase == input_char ? result_char : result_char.upcase
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment