bgneal@4
|
1 // Copyright (C) 2012 by Brian Neal.
|
bgneal@4
|
2 // This file is part of Cpp-Enigma, the Enigma Machine simulation.
|
bgneal@4
|
3 // Cpp-Enigma is released under the MIT License (see License.txt).
|
bgneal@4
|
4 //
|
bgneal@4
|
5 // test_machine.t.h - Unit tests for the enigma_machine class.
|
bgneal@4
|
6
|
bgneal@4
|
7 #include <memory>
|
bgneal@4
|
8 #include <string>
|
bgneal@4
|
9 #include <vector>
|
bgneal@4
|
10 #include <cxxtest/TestSuite.h>
|
bgneal@4
|
11 #include "machine.h"
|
bgneal@4
|
12 #include "enigma_utils.h"
|
bgneal@4
|
13
|
bgneal@4
|
14 using namespace enigma;
|
bgneal@4
|
15
|
bgneal@4
|
16
|
bgneal@7
|
17 class display_suite : public CxxTest::TestSuite
|
bgneal@7
|
18 {
|
bgneal@7
|
19 public:
|
bgneal@7
|
20
|
bgneal@7
|
21 void test_set_display3()
|
bgneal@7
|
22 {
|
bgneal@7
|
23 enigma_machine m({"II", "IV", "V"}, {}, "B");
|
bgneal@7
|
24 TS_ASSERT_THROWS(m.set_display("ABCD"), enigma_machine_error);
|
bgneal@7
|
25 TS_ASSERT_THROWS_NOTHING(m.set_display("ABC"));
|
bgneal@7
|
26 }
|
bgneal@7
|
27
|
bgneal@7
|
28 void test_set_display4()
|
bgneal@7
|
29 {
|
bgneal@7
|
30 enigma_machine m({"Gamma", "II", "IV", "V"}, {}, "B-Thin");
|
bgneal@7
|
31 TS_ASSERT_THROWS(m.set_display("BCD"), enigma_machine_error);
|
bgneal@7
|
32 TS_ASSERT_THROWS_NOTHING(m.set_display("ABCD"));
|
bgneal@7
|
33 }
|
bgneal@8
|
34
|
bgneal@8
|
35 void test_navy_str()
|
bgneal@8
|
36 {
|
bgneal@8
|
37 const std::string stecker = "1/20 2/12 4/6 7/10 8/13 14/23 15/16 17/25 18/26 22/24";
|
bgneal@8
|
38 enigma_machine machine({"Beta", "II", "IV", "I"}, {0, 0, 0, 21}, "B-Thin", stecker);
|
bgneal@8
|
39
|
bgneal@8
|
40 TS_ASSERT_EQUALS(machine.navy_str(), "B-Thin Beta/0 II/0 IV/0 I/21 AAAA "
|
bgneal@8
|
41 "1/20 2/12 4/6 7/10 8/13 14/23 15/16 17/25 18/26 22/24");
|
bgneal@8
|
42 }
|
bgneal@8
|
43
|
bgneal@8
|
44 void test_army_str()
|
bgneal@8
|
45 {
|
bgneal@8
|
46 enigma_machine machine({"II", "IV", "V"}, {1, 20, 11}, "B",
|
bgneal@8
|
47 "AV BS CG DL FU HZ IN KM OW RX");
|
bgneal@8
|
48
|
bgneal@8
|
49 TS_ASSERT_EQUALS(machine.army_str(), "B II/1 IV/20 V/11 AAA "
|
bgneal@8
|
50 "AV BS CG DL FU HZ IN KM OW RX");
|
bgneal@8
|
51 }
|
bgneal@7
|
52 };
|
bgneal@7
|
53
|
bgneal@4
|
54 class stepping_test_suite : public CxxTest::TestSuite
|
bgneal@4
|
55 {
|
bgneal@4
|
56 public:
|
bgneal@4
|
57
|
bgneal@4
|
58 void test_double_stepping()
|
bgneal@4
|
59 {
|
bgneal@4
|
60 // Ensure the rotors step realistically by testing for a "double-step"
|
bgneal@4
|
61 // This example taken from
|
bgneal@4
|
62 // http://users.telenet.be/d.rijmenants/en/enigmatech.htm
|
bgneal@4
|
63 // in the section on "The Stepping Mechanism."
|
bgneal@4
|
64
|
bgneal@4
|
65 enigma_machine m({"III", "II", "I"}, {});
|
bgneal@4
|
66 m.set_display('K', 'D', 'O');
|
bgneal@4
|
67
|
bgneal@4
|
68 const std::vector<std::string> truth_data = {
|
bgneal@4
|
69 "KDP", "KDQ", "KER", "LFS", "LFT", "LFU",
|
bgneal@4
|
70 };
|
bgneal@4
|
71
|
bgneal@4
|
72 for (const auto& expected : truth_data)
|
bgneal@4
|
73 {
|
bgneal@4
|
74 m.key_press('A');
|
bgneal@4
|
75 TS_ASSERT_EQUALS(m.get_display(), expected);
|
bgneal@4
|
76 }
|
bgneal@4
|
77 }
|
bgneal@4
|
78 };
|
bgneal@4
|
79
|
bgneal@4
|
80
|
bgneal@4
|
81 class simple_cipher_test_suite : public CxxTest::TestSuite
|
bgneal@4
|
82 {
|
bgneal@4
|
83 public:
|
bgneal@4
|
84
|
bgneal@4
|
85 void setUp()
|
bgneal@4
|
86 {
|
bgneal@4
|
87 m.reset(new enigma_machine({"I", "II", "III"}, {}));
|
bgneal@4
|
88 m->set_display('A', 'A', 'A');
|
bgneal@4
|
89 plaintext = "AAAAA";
|
bgneal@4
|
90 ciphertext = "BDZGO";
|
bgneal@4
|
91 }
|
bgneal@4
|
92
|
bgneal@4
|
93 void test_simple_encrypt()
|
bgneal@4
|
94 {
|
bgneal@4
|
95 std::vector<char> buffer(plaintext.size());
|
bgneal@4
|
96 m->process_text(plaintext.c_str(), buffer.data(), plaintext.size());
|
bgneal@4
|
97 TS_ASSERT_EQUALS(ciphertext, std::string(buffer.begin(), buffer.end()));
|
bgneal@4
|
98 }
|
bgneal@4
|
99
|
bgneal@4
|
100 void test_simple_decrypt()
|
bgneal@4
|
101 {
|
bgneal@4
|
102 std::vector<char> buffer(plaintext.size());
|
bgneal@4
|
103 m->process_text(ciphertext.c_str(), buffer.data(), ciphertext.size());
|
bgneal@4
|
104 TS_ASSERT_EQUALS(plaintext, std::string(buffer.begin(), buffer.end()));
|
bgneal@4
|
105 }
|
bgneal@4
|
106
|
bgneal@4
|
107 private:
|
bgneal@4
|
108 std::unique_ptr<enigma_machine> m;
|
bgneal@4
|
109 std::string plaintext;
|
bgneal@4
|
110 std::string ciphertext;
|
bgneal@4
|
111 };
|
bgneal@4
|
112
|
bgneal@4
|
113
|
bgneal@4
|
114 // This example taken from Dirk Rijmenants' simulator manual.
|
bgneal@4
|
115 //
|
bgneal@4
|
116 // It is credited to Frode Weierud and Geoff Sullivan.
|
bgneal@4
|
117 // http://cryptocellar.com
|
bgneal@4
|
118 //
|
bgneal@4
|
119 class actual_decrypt_test_suite : public CxxTest::TestSuite
|
bgneal@4
|
120 {
|
bgneal@4
|
121 public:
|
bgneal@4
|
122 void setUp()
|
bgneal@4
|
123 {
|
bgneal@4
|
124 m.reset(new enigma_machine({"II", "IV", "V"}, {1, 20, 11}, "B",
|
bgneal@4
|
125 "AV BS CG DL FU HZ IN KM OW RX"));
|
bgneal@4
|
126 }
|
bgneal@4
|
127
|
bgneal@4
|
128 void decrypt(const std::string& start,
|
bgneal@4
|
129 const std::string& enc_key,
|
bgneal@4
|
130 const std::string& ciphertext,
|
bgneal@4
|
131 const std::string& truth_data)
|
bgneal@4
|
132 {
|
bgneal@4
|
133 // remove spaces & Kenngruppen from ciphertext
|
bgneal@4
|
134 std::string ctext(ciphertext.begin() + 5, ciphertext.end());
|
bgneal@4
|
135 ctext = remove_spaces(ctext);
|
bgneal@4
|
136
|
bgneal@4
|
137 // remove spaces from truth_data
|
bgneal@4
|
138 const std::string expected(remove_spaces(truth_data));
|
bgneal@4
|
139
|
bgneal@4
|
140 // decrypt message key to get start position
|
bgneal@4
|
141 m->set_display(start[0], start[1], start[2]);
|
bgneal@4
|
142 std::string key = m->process_text(enc_key);
|
bgneal@4
|
143
|
bgneal@4
|
144 // decrypt the message with the key
|
bgneal@4
|
145 m->set_display(key[0], key[1], key[2]);
|
bgneal@4
|
146
|
bgneal@4
|
147 const std::string plaintext = m->process_text(ctext);
|
bgneal@4
|
148
|
bgneal@4
|
149 TS_ASSERT_EQUALS(plaintext, expected);
|
bgneal@4
|
150 }
|
bgneal@4
|
151
|
bgneal@4
|
152 void test_decrpyt_1()
|
bgneal@4
|
153 {
|
bgneal@4
|
154 const std::string ciphertext =
|
bgneal@4
|
155 "RFUGZ EDPUD NRGYS ZRCXN"
|
bgneal@4
|
156 "UYTPO MRMBO FKTBZ REZKM"
|
bgneal@4
|
157 "LXLVE FGUEY SIOZV EQMIK"
|
bgneal@4
|
158 "UBPMM YLKLT TDEIS MDICA"
|
bgneal@4
|
159 "GYKUA CTCDO MOHWX MUUIA"
|
bgneal@4
|
160 "UBSTS LRNBZ SZWNR FXWFY"
|
bgneal@4
|
161 "SSXJZ VIJHI DISHP RKLKA"
|
bgneal@4
|
162 "YUPAD TXQSP INQMA TLPIF"
|
bgneal@4
|
163 "SVKDA SCTAC DPBOP VHJK";
|
bgneal@4
|
164
|
bgneal@4
|
165 const std::string truth_data =
|
bgneal@4
|
166 "AUFKL XABTE ILUNG XVONX"
|
bgneal@4
|
167 "KURTI NOWAX KURTI NOWAX"
|
bgneal@4
|
168 "NORDW ESTLX SEBEZ XSEBE"
|
bgneal@4
|
169 "ZXUAF FLIEG ERSTR ASZER"
|
bgneal@4
|
170 "IQTUN GXDUB ROWKI XDUBR"
|
bgneal@4
|
171 "OWKIX OPOTS CHKAX OPOTS"
|
bgneal@4
|
172 "CHKAX UMXEI NSAQT DREIN"
|
bgneal@4
|
173 "ULLXU HRANG ETRET ENXAN"
|
bgneal@4
|
174 "GRIFF XINFX RGTX";
|
bgneal@4
|
175
|
bgneal@4
|
176 decrypt("WXC", "KCH", ciphertext, truth_data);
|
bgneal@4
|
177 }
|
bgneal@4
|
178
|
bgneal@4
|
179 void test_decrpyt_2()
|
bgneal@4
|
180 {
|
bgneal@4
|
181 const std::string ciphertext =
|
bgneal@4
|
182 "FNJAU SFBWD NJUSE GQOBH"
|
bgneal@4
|
183 "KRTAR EEZMW KPPRB XOHDR"
|
bgneal@4
|
184 "OEQGB BGTQV PGVKB VVGBI"
|
bgneal@4
|
185 "MHUSZ YDAJQ IROAX SSSNR"
|
bgneal@4
|
186 "EHYGG RPISE ZBOVM QIEMM"
|
bgneal@4
|
187 "ZCYSG QDGRE RVBIL EKXYQ"
|
bgneal@4
|
188 "IRGIR QNRDN VRXCY YTNJR";
|
bgneal@4
|
189
|
bgneal@4
|
190 const std::string truth_data =
|
bgneal@4
|
191 "DREIG EHTLA NGSAM ABERS"
|
bgneal@4
|
192 "IQERV ORWAE RTSXE INSSI"
|
bgneal@4
|
193 "EBENN ULLSE QSXUH RXROE"
|
bgneal@4
|
194 "MXEIN SXINF RGTXD REIXA"
|
bgneal@4
|
195 "UFFLI EGERS TRASZ EMITA"
|
bgneal@4
|
196 "NFANG XEINS SEQSX KMXKM"
|
bgneal@4
|
197 "XOSTW XKAME NECXK";
|
bgneal@4
|
198
|
bgneal@4
|
199 decrypt("CRS", "YPJ", ciphertext, truth_data);
|
bgneal@4
|
200 }
|
bgneal@4
|
201
|
bgneal@4
|
202 private:
|
bgneal@4
|
203 std::unique_ptr<enigma_machine> m;
|
bgneal@4
|
204 };
|
bgneal@4
|
205
|
bgneal@4
|
206
|
bgneal@4
|
207 // This is the Kriegsmarine example from Dirk Rijmenants' simulator manual.
|
bgneal@4
|
208 //
|
bgneal@4
|
209 // It is credited to Stefan Krah and the M4 project:
|
bgneal@4
|
210 // http://www.bytereef.org/m4_project.html
|
bgneal@4
|
211 //
|
bgneal@4
|
212 class kriegsmarine_test_suite : public CxxTest::TestSuite
|
bgneal@4
|
213 {
|
bgneal@4
|
214 public:
|
bgneal@4
|
215
|
bgneal@4
|
216 void test_decrypt()
|
bgneal@4
|
217 {
|
bgneal@4
|
218 const std::string stecker = "1/20 2/12 4/6 7/10 8/13 14/23 15/16 17/25 18/26 22/24";
|
bgneal@4
|
219
|
bgneal@4
|
220 enigma_machine machine({"Beta", "II", "IV", "I"}, {0, 0, 0, 21}, "B-Thin", stecker);
|
bgneal@4
|
221
|
bgneal@4
|
222 std::string ciphertext = remove_spaces(
|
bgneal@4
|
223 "FCLC QRKN NCZW VUSX PNYM INHZ XMQX SFWX WLKJ AHSH NMCO CCAK UQPM KCSM"
|
bgneal@4
|
224 "HKSE INJU SBLK IOSX CKUB HMLL XCSJ USRR DVKO HULX WCCB GVLI YXEO AHXR"
|
bgneal@4
|
225 "HKKF VDRE WEZL XOBA FGYU JQUK GRTV UKAM EURB VEKS UHHV OYHA BCJW MAKL"
|
bgneal@4
|
226 "FKLM YFVN RIZR VVRT KOFD ANJM OLBG FFLE OPRG TFLV RHOW OPBE KVWM UQFM"
|
bgneal@4
|
227 "PWPA RMFH AGKX IIBG FCLC QRKM VA");
|
bgneal@4
|
228
|
bgneal@4
|
229 // remove the message indicators from the message (the first and last 2
|
bgneal@4
|
230 // groups of the message -- it appears the last partial group 'VA' should
|
bgneal@4
|
231 // be removed also)
|
bgneal@4
|
232
|
bgneal@4
|
233 ciphertext = std::string(ciphertext.begin() + 8, ciphertext.end() - 10);
|
bgneal@4
|
234
|
bgneal@4
|
235 machine.set_display('V', 'J', 'N', 'A');
|
bgneal@4
|
236 const std::string plaintext = machine.process_text(ciphertext);
|
bgneal@4
|
237
|
bgneal@4
|
238 const std::string truth_data = remove_spaces(
|
bgneal@4
|
239 "VONV ONJL OOKS JHFF TTTE"
|
bgneal@4
|
240 "INSE INSD REIZ WOYY QNNS"
|
bgneal@4
|
241 "NEUN INHA LTXX BEIA NGRI"
|
bgneal@4
|
242 "FFUN TERW ASSE RGED RUEC"
|
bgneal@4
|
243 "KTYW ABOS XLET ZTER GEGN"
|
bgneal@4
|
244 "ERST ANDN ULAC HTDR EINU"
|
bgneal@4
|
245 "LUHR MARQ UANT ONJO TANE"
|
bgneal@4
|
246 "UNAC HTSE YHSD REIY ZWOZ"
|
bgneal@4
|
247 "WONU LGRA DYAC HTSM YSTO"
|
bgneal@4
|
248 "SSEN ACHX EKNS VIER MBFA"
|
bgneal@4
|
249 "ELLT YNNN NNNO OOVI ERYS"
|
bgneal@4
|
250 "ICHT EINS NULL");
|
bgneal@4
|
251
|
bgneal@4
|
252 TS_ASSERT_EQUALS(plaintext, truth_data);
|
bgneal@4
|
253 }
|
bgneal@4
|
254
|
bgneal@4
|
255 };
|
bgneal@16
|
256
|
bgneal@16
|
257 class ring_settings_test_suite : public CxxTest::TestSuite
|
bgneal@16
|
258 {
|
bgneal@16
|
259 public:
|
bgneal@16
|
260
|
bgneal@16
|
261 void test_ring_settings()
|
bgneal@16
|
262 {
|
bgneal@16
|
263 enigma_machine machine({"Beta", "II", "IV", "I"}, {0, 2, 8, 21}, "B-Thin");
|
bgneal@16
|
264
|
bgneal@16
|
265 TS_ASSERT_EQUALS(machine.get_ring_setting(0), 0);
|
bgneal@16
|
266 TS_ASSERT_EQUALS(machine.get_ring_setting(1), 2);
|
bgneal@16
|
267 TS_ASSERT_EQUALS(machine.get_ring_setting(2), 8);
|
bgneal@16
|
268 TS_ASSERT_EQUALS(machine.get_ring_setting(3), 21);
|
bgneal@16
|
269
|
bgneal@16
|
270 std::vector<int> rings(machine.get_ring_settings());
|
bgneal@16
|
271 std::vector<int> expected{ 0, 2, 8, 21 };
|
bgneal@16
|
272 TS_ASSERT_EQUALS(rings, expected);
|
bgneal@16
|
273
|
bgneal@16
|
274 machine.set_ring_setting(0, 25);
|
bgneal@16
|
275 TS_ASSERT_EQUALS(machine.get_ring_setting(0), 25);
|
bgneal@16
|
276 TS_ASSERT_EQUALS(machine.get_ring_setting(1), 2);
|
bgneal@16
|
277 TS_ASSERT_EQUALS(machine.get_ring_setting(2), 8);
|
bgneal@16
|
278 TS_ASSERT_EQUALS(machine.get_ring_setting(3), 21);
|
bgneal@16
|
279
|
bgneal@16
|
280 expected = { 25, 2, 8, 21 };
|
bgneal@16
|
281 TS_ASSERT_EQUALS(machine.get_ring_settings(), expected);
|
bgneal@16
|
282
|
bgneal@16
|
283 machine.set_ring_setting(1, 18);
|
bgneal@16
|
284 TS_ASSERT_EQUALS(machine.get_ring_setting(0), 25);
|
bgneal@16
|
285 TS_ASSERT_EQUALS(machine.get_ring_setting(1), 18);
|
bgneal@16
|
286 TS_ASSERT_EQUALS(machine.get_ring_setting(2), 8);
|
bgneal@16
|
287 TS_ASSERT_EQUALS(machine.get_ring_setting(3), 21);
|
bgneal@16
|
288
|
bgneal@16
|
289 expected = { 25, 18, 8, 21 };
|
bgneal@16
|
290 TS_ASSERT_EQUALS(machine.get_ring_settings(), expected);
|
bgneal@16
|
291
|
bgneal@16
|
292 machine.set_ring_setting(2, 11);
|
bgneal@16
|
293 TS_ASSERT_EQUALS(machine.get_ring_setting(0), 25);
|
bgneal@16
|
294 TS_ASSERT_EQUALS(machine.get_ring_setting(1), 18);
|
bgneal@16
|
295 TS_ASSERT_EQUALS(machine.get_ring_setting(2), 11);
|
bgneal@16
|
296 TS_ASSERT_EQUALS(machine.get_ring_setting(3), 21);
|
bgneal@16
|
297
|
bgneal@16
|
298 expected = { 25, 18, 11, 21 };
|
bgneal@16
|
299 TS_ASSERT_EQUALS(machine.get_ring_settings(), expected);
|
bgneal@16
|
300
|
bgneal@16
|
301 machine.set_ring_setting(3, 3);
|
bgneal@16
|
302 TS_ASSERT_EQUALS(machine.get_ring_setting(0), 25);
|
bgneal@16
|
303 TS_ASSERT_EQUALS(machine.get_ring_setting(1), 18);
|
bgneal@16
|
304 TS_ASSERT_EQUALS(machine.get_ring_setting(2), 11);
|
bgneal@16
|
305 TS_ASSERT_EQUALS(machine.get_ring_setting(3), 3);
|
bgneal@16
|
306
|
bgneal@16
|
307 expected = { 25, 18, 11, 3 };
|
bgneal@16
|
308 TS_ASSERT_EQUALS(machine.get_ring_settings(), expected);
|
bgneal@16
|
309
|
bgneal@16
|
310 expected = { 8, 9, 10, 11 };
|
bgneal@16
|
311 machine.set_ring_settings(expected);
|
bgneal@16
|
312 TS_ASSERT_EQUALS(machine.get_ring_settings(), expected);
|
bgneal@16
|
313 }
|
bgneal@16
|
314 };
|