bgneal@2: // Copyright (C) 2012 by Brian Neal. bgneal@2: // This file is part of Cpp-Enigma, the Enigma Machine simulation. bgneal@2: // Cpp-Enigma is released under the MIT License (see License.txt). bgneal@2: // bgneal@2: // test_rotor.t.h - rotor unit tests bgneal@2: bgneal@2: #include bgneal@2: #include bgneal@2: #include bgneal@2: #include bgneal@2: #include "rotor.h" bgneal@2: #include "enigma_utils.h" bgneal@2: #include "rotor_data.h" bgneal@2: #include "rotor_factory.h" bgneal@2: bgneal@2: using namespace enigma; bgneal@2: bgneal@2: const char* const wiring = "EKMFLGDQVZNTOWYHXUSPAIBRCJ"; bgneal@2: bgneal@2: bgneal@3: class rotor_test_suite : public CxxTest::TestSuite bgneal@2: { bgneal@2: public: bgneal@2: bgneal@2: void test_bad_wiring() bgneal@2: { bgneal@2: TS_ASSERT_THROWS(rotor("I", ""), rotor_error); bgneal@2: TS_ASSERT_THROWS(rotor("I", "ABC"), rotor_error); bgneal@2: TS_ASSERT_THROWS(rotor("I", "123"), rotor_error); bgneal@2: TS_ASSERT_THROWS(rotor("I", "!\"#$%&'()*+,-./:;<=>?@[\\]^"), rotor_error); bgneal@2: TS_ASSERT_THROWS(rotor("I", "ABCDABCDABCDABCDABCDABCDAB"), rotor_error); bgneal@2: } bgneal@2: bgneal@2: void test_bad_ring_setting() bgneal@2: { bgneal@2: TS_ASSERT_THROWS(rotor("I", wiring, -1), rotor_error); bgneal@2: TS_ASSERT_THROWS(rotor("I", wiring, 26), rotor_error); bgneal@2: } bgneal@2: bgneal@2: void test_bad_stepping() bgneal@2: { bgneal@2: TS_ASSERT_THROWS(rotor("I", wiring, 1, "0"), rotor_error); bgneal@2: TS_ASSERT_THROWS(rotor("I", wiring, 1, "-"), rotor_error); bgneal@2: TS_ASSERT_THROWS(rotor("I", wiring, 1, "A%"), rotor_error); bgneal@2: TS_ASSERT_THROWS(rotor("I", wiring, 1, "A%14"), rotor_error); bgneal@2: } bgneal@2: bgneal@2: void test_display() bgneal@2: { bgneal@2: for (int i = 0; i < 26; ++i) bgneal@2: { bgneal@2: rotor r{"I", wiring, i}; bgneal@2: for (int j = 0; j < 26; ++j) bgneal@2: { bgneal@2: r.set_display(j + 'A'); bgneal@2: TS_ASSERT_EQUALS(j + 'A', r.get_display()); bgneal@2: } bgneal@2: } bgneal@2: } bgneal@2: bgneal@2: // Loop through all ring settings & rotor positions and test the wiring. bgneal@2: void test_wiring() bgneal@2: { bgneal@2: for (int r = 0; r < 26; ++r) bgneal@2: { bgneal@2: rotor test_rotor("I", wiring, r); bgneal@2: bgneal@2: for (int n = 0; n < 26; ++n) bgneal@2: { bgneal@2: const char d = n + 'A'; bgneal@2: test_rotor.set_display(d); bgneal@2: bgneal@2: std::deque wiring_deque(wiring, wiring + 26); bgneal@2: // rotate contents to the right if positive, left if negative: bgneal@2: int rotate_count = r - n; bgneal@2: const bool rotate_right = rotate_count >= 0; bgneal@2: if (rotate_count < 0) bgneal@2: { bgneal@2: rotate_count = -rotate_count; bgneal@2: } bgneal@2: for (int x = 0; x < rotate_count; ++x) bgneal@2: { bgneal@2: if (rotate_right) bgneal@2: { bgneal@2: wiring_deque.push_front(wiring_deque.back()); bgneal@2: wiring_deque.pop_back(); bgneal@2: } bgneal@2: else bgneal@2: { bgneal@2: wiring_deque.push_back(wiring_deque.front()); bgneal@2: wiring_deque.pop_front(); bgneal@2: } bgneal@2: } bgneal@2: bgneal@2: for (int i = 0; i < 26; ++i) bgneal@2: { bgneal@2: int output = test_rotor.signal_in(i); bgneal@2: int expected = alpha_mod(wiring_deque[i] - 'A' + r - n); bgneal@2: TS_ASSERT_EQUALS(output, expected); bgneal@2: bgneal@2: output = test_rotor.signal_out(expected); bgneal@2: TS_ASSERT_EQUALS(output, i); bgneal@2: } bgneal@2: } bgneal@2: } bgneal@2: } bgneal@2: bgneal@2: // For every rotor we simulate, ensure that the notch setting is correct bgneal@2: // regardless of the ring setting. bgneal@2: void test_notches() bgneal@2: { bgneal@2: for (const auto& p : simulated_rotors) bgneal@2: { bgneal@2: const std::string& rotor_name(p.first); bgneal@2: const rotor_data& rd(p.second); bgneal@2: if (rd.stepping == nullptr) bgneal@2: { bgneal@2: continue; bgneal@2: } bgneal@2: const std::string notches(rd.stepping); bgneal@2: bgneal@2: for (int r = 0; r < 26; ++r) bgneal@2: { bgneal@2: std::unique_ptr rp = create_rotor(rotor_name.c_str(), r); bgneal@2: rp->set_display('A'); bgneal@2: bgneal@2: for (int n = 0; n < 26; ++n) bgneal@2: { bgneal@2: const bool over_notch = notches.find(rp->get_display()) != std::string::npos; bgneal@2: TS_ASSERT_EQUALS(over_notch, rp->notch_over_pawl()); bgneal@2: } bgneal@2: } bgneal@2: } bgneal@2: } bgneal@2: bgneal@2: void test_rotate() bgneal@2: { bgneal@2: for (int r = 0; r < 26; ++r) bgneal@2: { bgneal@2: rotor r1("X", wiring, r); bgneal@2: rotor r2("Y", wiring, r); bgneal@2: bgneal@2: r2.set_display('A'); bgneal@2: for (int i = 0; i < 26; ++i) bgneal@2: { bgneal@2: r1.set_display(i + 'A'); bgneal@2: TS_ASSERT_EQUALS(r1.get_display(), r2.get_display()); bgneal@2: r2.rotate(); bgneal@2: } bgneal@2: } bgneal@2: } bgneal@2: bgneal@2: void test_ring_setting() bgneal@2: { bgneal@2: rotor r("X", wiring, 0); bgneal@2: for (int n = 0; n < 26; ++n) bgneal@2: { bgneal@2: r.set_ring_setting(n); bgneal@2: TS_ASSERT_EQUALS(n, r.get_ring_setting()); bgneal@2: bgneal@2: r.set_display('A'); bgneal@2: for (int a = 0; a < 26; ++a) bgneal@2: { bgneal@2: TS_ASSERT_EQUALS(a + 'A', r.get_display()); bgneal@2: r.rotate(); bgneal@2: } bgneal@2: } bgneal@2: } bgneal@2: };