// For Step 1, implement the Caesar cipher, which seems clear enough except // maybe for figuring out whether to add or subtract. // // For Step 2, implement a shift cipher, like Caesar except the shift amount // is specified as an int. (Each letter of "ddddddddddddddddd", is 'd'; // 'd'-'a' == 3, so the corresponding shift amount is 3.) // // Steps 2 and 3 seem to be describing the Vigenère cipher (Google it) // so let's do that too. The random thing, don't worry about. There is // no test for that. // // API: // // type Cipher interface { // Encode(string) string // Decode(string) string // } // NewCaesar() Cipher // NewShift(int) Cipher // NewVigenere(string) Cipher // // Interface Cipher is in file cipher.go. // // Argument for NewShift must be in the range 1 to 25 or -1 to -25. // Zero is disallowed. For invalid arguments NewShift returns nil. // // Argument for NewVigenere must consist of lower case letters a-z only. // Values consisting entirely of the letter 'a' are disallowed. // For invalid arguments NewVigenere returns nil. package cipher import ( "fmt" "testing" ) // type for testing cipher encoding alone, without requiring any text prep. type prepped struct { pt string // prepped text == decoded plain text ct string // cipher text } // +3? -3? Positions vary. Your code just has to pass the tests. var caesarPrepped = []prepped{ {"iamapandabear", "ldpdsdqgdehdu"}, {"programmingisawesome", "surjudpplqjlvdzhvrph"}, {"todayisholiday", "wrgdblvkrolgdb"}, {"venividivici", "yhqlylglylfl"}, } func TestCaesarPrepped(t *testing.T) { c := NewCaesar() for _, test := range caesarPrepped { if enc := c.Encode(test.pt); enc != test.ct { t.Fatalf("Caesar Encode(%q) = %q, want %q.", test.pt, enc, test.ct) } } } // type for testing implementations of the Cipher interface type cipherTest struct { source string // source text, any UTF-8 cipher string // cipher text, result of Encode(st) plain string // decoded plain text, result of Decode(ct) } var caesarTests = []cipherTest{ {"Go, go, gophers", "jrjrjrskhuv", "gogogophers"}, {"I am a panda bear.", "ldpdsdqgdehdu", "iamapandabear"}, {"Programming is AWESOME!", "surjudpplqjlvdzhvrph", "programmingisawesome"}, {"today is holiday", "wrgdblvkrolgdb", "todayisholiday"}, {"Twas the night before Christmas", "wzdvwkhqljkwehiruhfkulvwpdv", "twasthenightbeforechristmas"}, {"venividivici", "yhqlylglylfl", "venividivici"}, {" -- @#!", "", ""}, {"", "", ""}, } func TestCaesar(t *testing.T) { testCipher("Caesar", NewCaesar(), caesarTests, t) } func testCipher(name string, c Cipher, tests []cipherTest, t *testing.T) { for _, test := range tests { if enc := c.Encode(test.source); enc != test.cipher { t.Fatalf("%s Encode(%q) = %q, want %q.", name, test.plain, enc, test.cipher) } if dec := c.Decode(test.cipher); dec != test.plain { t.Fatalf("%s Decode(%q) = %q, want %q.", name, test.cipher, dec, test.plain) } } } var NSATests = []cipherTest{ {"THE ENEMY IS NEAR", "qebbkbjvfpkbxo", "theenemyisnear"}, {"SPIES SEND SECRET MESSAGES", "pmfbppbkapbzobqjbppxdbp", "spiessendsecretmessages"}, {"THOMAS JEFFERSON DESIGNED A SUBSTITUTION CIPHER", "qeljxpgbccboplkabpfdkbaxprypqfqrqflkzfmebo", "thomasjeffersondesignedasubstitutioncipher"}, {"the quick brown fox jumps over the lazy dog", "qebnrfzhyoltkclugrjmplsboqebixwvald", "thequickbrownfoxjumpsoverthelazydog"}, } func TestShift(t *testing.T) { // test shift(3) against Caesar cases. c := NewShift(3) if c == nil { t.Fatal("NewShift(3) returned nil, want non-nil Cipher") } testCipher("Shift(3)", c, caesarTests, t) // NSA and WP say Caesar uses shift of -3 c = NewShift(-3) if c == nil { t.Fatal("NewShift(-3) returned nil, want non-nil Cipher") } testCipher("Shift(-3)", c, NSATests, t) // invalid shifts for _, s := range []int{-27, -26, 0, 26, 27} { if NewShift(s) != nil { t.Fatal("NewShift(%d) returned non-nil, "+ "Want nil return for invalid argument.", s) } } } var vtests = []struct { key string tests []cipherTest }{ {"lemon", []cipherTest{{"ATTACKATDAWN", "lxfopvefrnhr", "attackatdawn"}}}, {"abcdefghij", []cipherTest{ {"aaaaaaaaaa", "abcdefghij", "aaaaaaaaaa"}, {"zzzzzzzzzz", "zabcdefghi", "zzzzzzzzzz"}, }}, {"iamapandabear", []cipherTest{ {"I am a panda bear.", "qayaeaagaciai", "iamapandabear"}, }}, {"duxrceqyaimciuucnelkeoxjhdyduu", []cipherTest{ {"Diffie Hellman", "gccwkixcltycv", "diffiehellman"}, }}, {"qgbvno", []cipherTest{ {"cof-FEE, 123!", "sugars", "coffee"}, }}, } func TestVigenere(t *testing.T) { for _, test := range vtests { v := NewVigenere(test.key) if v == nil { t.Fatalf("NewVigenere(%q) returned nil, want non-nil Cipher", test.key) } testCipher(fmt.Sprintf("Vigenere(%q)", test.key), v, test.tests, t) } // invalid keys for _, k := range []string{"", "a", "aa", "no way", "CAT", "3", "and,"} { if NewVigenere(k) != nil { t.Fatalf("NewVigenere(%q) returned non-nil, "+ "Want nil return for invalid argument.", k) } } } // Benchmark combined time to run all tests. // Note other ciphers test different data; times cannot be compared. func BenchmarkEncodeCaesar(b *testing.B) { c := NewCaesar() b.ResetTimer() for i := 0; i < b.N; i++ { for _, test := range caesarTests { c.Encode(test.source) } } } func BenchmarkDecodeCaesar(b *testing.B) { c := NewCaesar() b.ResetTimer() for i := 0; i < b.N; i++ { for _, test := range caesarTests { c.Decode(test.cipher) } } } func BenchmarkNewShift(b *testing.B) { for i := 0; i < b.N; i++ { for s := -27; s <= 27; s++ { NewShift(s) } } } func BenchmarkEncodeShift(b *testing.B) { s := NewShift(5) all := append(caesarTests, NSATests...) b.ResetTimer() for i := 0; i < b.N; i++ { for _, test := range all { s.Encode(test.source) } } } func BenchmarkDecodeShift(b *testing.B) { s := NewShift(5) all := append(caesarTests, NSATests...) b.ResetTimer() for i := 0; i < b.N; i++ { for _, test := range all { s.Decode(test.cipher) } } } func BenchmarkNewVigenere(b *testing.B) { for i := 0; i < b.N; i++ { for _, test := range vtests { NewVigenere(test.key) } } } func BenchmarkEncVigenere(b *testing.B) { v := make([]Cipher, len(vtests)) for i, test := range vtests { v[i] = NewVigenere(test.key) if v[i] == nil { b.Skip("Benchmark requires valid Vigenere test cases") } } b.ResetTimer() for j := 0; j < b.N; j++ { for i, test := range vtests { vi := v[i] for _, test := range test.tests { vi.Encode(test.source) } } } } func BenchmarkDecVigenere(b *testing.B) { v := make([]Cipher, len(vtests)) for i, test := range vtests { v[i] = NewVigenere(test.key) if v[i] == nil { b.Skip("Benchmark requires valid Vigenere test cases") } } b.ResetTimer() for j := 0; j < b.N; j++ { for i, test := range vtests { vi := v[i] for _, test := range test.tests { vi.Decode(test.cipher) } } } }