bgneal@2
|
1 // Copyright (C) 2012 by Brian Neal.
|
bgneal@2
|
2 // This file is part of Cpp-Enigma, the Enigma Machine simulation.
|
bgneal@2
|
3 // Cpp-Enigma is released under the MIT License (see License.txt).
|
bgneal@2
|
4 //
|
bgneal@2
|
5 // test_rotor.t.h - rotor unit tests
|
bgneal@2
|
6
|
bgneal@2
|
7 #include <deque>
|
bgneal@2
|
8 #include <string>
|
bgneal@2
|
9 #include <memory>
|
bgneal@2
|
10 #include <cxxtest/TestSuite.h>
|
bgneal@2
|
11 #include "rotor.h"
|
bgneal@2
|
12 #include "enigma_utils.h"
|
bgneal@2
|
13 #include "rotor_data.h"
|
bgneal@2
|
14 #include "rotor_factory.h"
|
bgneal@2
|
15
|
bgneal@2
|
16 using namespace enigma;
|
bgneal@2
|
17
|
bgneal@2
|
18 const char* const wiring = "EKMFLGDQVZNTOWYHXUSPAIBRCJ";
|
bgneal@2
|
19
|
bgneal@2
|
20
|
bgneal@3
|
21 class rotor_test_suite : public CxxTest::TestSuite
|
bgneal@2
|
22 {
|
bgneal@2
|
23 public:
|
bgneal@2
|
24
|
bgneal@2
|
25 void test_bad_wiring()
|
bgneal@2
|
26 {
|
bgneal@2
|
27 TS_ASSERT_THROWS(rotor("I", ""), rotor_error);
|
bgneal@2
|
28 TS_ASSERT_THROWS(rotor("I", "ABC"), rotor_error);
|
bgneal@2
|
29 TS_ASSERT_THROWS(rotor("I", "123"), rotor_error);
|
bgneal@2
|
30 TS_ASSERT_THROWS(rotor("I", "!\"#$%&'()*+,-./:;<=>?@[\\]^"), rotor_error);
|
bgneal@2
|
31 TS_ASSERT_THROWS(rotor("I", "ABCDABCDABCDABCDABCDABCDAB"), rotor_error);
|
bgneal@2
|
32 }
|
bgneal@2
|
33
|
bgneal@2
|
34 void test_bad_ring_setting()
|
bgneal@2
|
35 {
|
bgneal@2
|
36 TS_ASSERT_THROWS(rotor("I", wiring, -1), rotor_error);
|
bgneal@2
|
37 TS_ASSERT_THROWS(rotor("I", wiring, 26), rotor_error);
|
bgneal@2
|
38 }
|
bgneal@2
|
39
|
bgneal@2
|
40 void test_bad_stepping()
|
bgneal@2
|
41 {
|
bgneal@2
|
42 TS_ASSERT_THROWS(rotor("I", wiring, 1, "0"), rotor_error);
|
bgneal@2
|
43 TS_ASSERT_THROWS(rotor("I", wiring, 1, "-"), rotor_error);
|
bgneal@2
|
44 TS_ASSERT_THROWS(rotor("I", wiring, 1, "A%"), rotor_error);
|
bgneal@2
|
45 TS_ASSERT_THROWS(rotor("I", wiring, 1, "A%14"), rotor_error);
|
bgneal@2
|
46 }
|
bgneal@2
|
47
|
bgneal@2
|
48 void test_display()
|
bgneal@2
|
49 {
|
bgneal@2
|
50 for (int i = 0; i < 26; ++i)
|
bgneal@2
|
51 {
|
bgneal@2
|
52 rotor r{"I", wiring, i};
|
bgneal@2
|
53 for (int j = 0; j < 26; ++j)
|
bgneal@2
|
54 {
|
bgneal@2
|
55 r.set_display(j + 'A');
|
bgneal@2
|
56 TS_ASSERT_EQUALS(j + 'A', r.get_display());
|
bgneal@2
|
57 }
|
bgneal@2
|
58 }
|
bgneal@2
|
59 }
|
bgneal@2
|
60
|
bgneal@2
|
61 // Loop through all ring settings & rotor positions and test the wiring.
|
bgneal@2
|
62 void test_wiring()
|
bgneal@2
|
63 {
|
bgneal@2
|
64 for (int r = 0; r < 26; ++r)
|
bgneal@2
|
65 {
|
bgneal@2
|
66 rotor test_rotor("I", wiring, r);
|
bgneal@2
|
67
|
bgneal@2
|
68 for (int n = 0; n < 26; ++n)
|
bgneal@2
|
69 {
|
bgneal@2
|
70 const char d = n + 'A';
|
bgneal@2
|
71 test_rotor.set_display(d);
|
bgneal@2
|
72
|
bgneal@2
|
73 std::deque<char> wiring_deque(wiring, wiring + 26);
|
bgneal@2
|
74 // rotate contents to the right if positive, left if negative:
|
bgneal@2
|
75 int rotate_count = r - n;
|
bgneal@2
|
76 const bool rotate_right = rotate_count >= 0;
|
bgneal@2
|
77 if (rotate_count < 0)
|
bgneal@2
|
78 {
|
bgneal@2
|
79 rotate_count = -rotate_count;
|
bgneal@2
|
80 }
|
bgneal@2
|
81 for (int x = 0; x < rotate_count; ++x)
|
bgneal@2
|
82 {
|
bgneal@2
|
83 if (rotate_right)
|
bgneal@2
|
84 {
|
bgneal@2
|
85 wiring_deque.push_front(wiring_deque.back());
|
bgneal@2
|
86 wiring_deque.pop_back();
|
bgneal@2
|
87 }
|
bgneal@2
|
88 else
|
bgneal@2
|
89 {
|
bgneal@2
|
90 wiring_deque.push_back(wiring_deque.front());
|
bgneal@2
|
91 wiring_deque.pop_front();
|
bgneal@2
|
92 }
|
bgneal@2
|
93 }
|
bgneal@2
|
94
|
bgneal@2
|
95 for (int i = 0; i < 26; ++i)
|
bgneal@2
|
96 {
|
bgneal@2
|
97 int output = test_rotor.signal_in(i);
|
bgneal@2
|
98 int expected = alpha_mod(wiring_deque[i] - 'A' + r - n);
|
bgneal@2
|
99 TS_ASSERT_EQUALS(output, expected);
|
bgneal@2
|
100
|
bgneal@2
|
101 output = test_rotor.signal_out(expected);
|
bgneal@2
|
102 TS_ASSERT_EQUALS(output, i);
|
bgneal@2
|
103 }
|
bgneal@2
|
104 }
|
bgneal@2
|
105 }
|
bgneal@2
|
106 }
|
bgneal@2
|
107
|
bgneal@2
|
108 // For every rotor we simulate, ensure that the notch setting is correct
|
bgneal@2
|
109 // regardless of the ring setting.
|
bgneal@2
|
110 void test_notches()
|
bgneal@2
|
111 {
|
bgneal@2
|
112 for (const auto& p : simulated_rotors)
|
bgneal@2
|
113 {
|
bgneal@2
|
114 const std::string& rotor_name(p.first);
|
bgneal@2
|
115 const rotor_data& rd(p.second);
|
bgneal@2
|
116 if (rd.stepping == nullptr)
|
bgneal@2
|
117 {
|
bgneal@2
|
118 continue;
|
bgneal@2
|
119 }
|
bgneal@2
|
120 const std::string notches(rd.stepping);
|
bgneal@2
|
121
|
bgneal@2
|
122 for (int r = 0; r < 26; ++r)
|
bgneal@2
|
123 {
|
bgneal@2
|
124 std::unique_ptr<rotor> rp = create_rotor(rotor_name.c_str(), r);
|
bgneal@2
|
125 rp->set_display('A');
|
bgneal@2
|
126
|
bgneal@2
|
127 for (int n = 0; n < 26; ++n)
|
bgneal@2
|
128 {
|
bgneal@2
|
129 const bool over_notch = notches.find(rp->get_display()) != std::string::npos;
|
bgneal@2
|
130 TS_ASSERT_EQUALS(over_notch, rp->notch_over_pawl());
|
bgneal@2
|
131 }
|
bgneal@2
|
132 }
|
bgneal@2
|
133 }
|
bgneal@2
|
134 }
|
bgneal@2
|
135
|
bgneal@2
|
136 void test_rotate()
|
bgneal@2
|
137 {
|
bgneal@2
|
138 for (int r = 0; r < 26; ++r)
|
bgneal@2
|
139 {
|
bgneal@2
|
140 rotor r1("X", wiring, r);
|
bgneal@2
|
141 rotor r2("Y", wiring, r);
|
bgneal@2
|
142
|
bgneal@2
|
143 r2.set_display('A');
|
bgneal@2
|
144 for (int i = 0; i < 26; ++i)
|
bgneal@2
|
145 {
|
bgneal@2
|
146 r1.set_display(i + 'A');
|
bgneal@2
|
147 TS_ASSERT_EQUALS(r1.get_display(), r2.get_display());
|
bgneal@2
|
148 r2.rotate();
|
bgneal@2
|
149 }
|
bgneal@2
|
150 }
|
bgneal@2
|
151 }
|
bgneal@2
|
152
|
bgneal@2
|
153 void test_ring_setting()
|
bgneal@2
|
154 {
|
bgneal@2
|
155 rotor r("X", wiring, 0);
|
bgneal@2
|
156 for (int n = 0; n < 26; ++n)
|
bgneal@2
|
157 {
|
bgneal@2
|
158 r.set_ring_setting(n);
|
bgneal@2
|
159 TS_ASSERT_EQUALS(n, r.get_ring_setting());
|
bgneal@2
|
160
|
bgneal@2
|
161 r.set_display('A');
|
bgneal@2
|
162 for (int a = 0; a < 26; ++a)
|
bgneal@2
|
163 {
|
bgneal@2
|
164 TS_ASSERT_EQUALS(a + 'A', r.get_display());
|
bgneal@2
|
165 r.rotate();
|
bgneal@2
|
166 }
|
bgneal@2
|
167 }
|
bgneal@2
|
168 }
|
bgneal@2
|
169 };
|