annotate enigma/tests/test_rotor.t.h @ 16:280facb82b80

Add the ability to change ring settings at the machine level.
author Brian Neal <bgneal@gmail.com>
date Sat, 07 Jul 2012 11:42:31 -0500
parents f4e25e6b76c3
children
rev   line source
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 };