# HG changeset patch # User Brian Neal # Date 1340420575 18000 # Node ID 713fa2a9ea9a82935f2915fa84164347f95bc651 # Parent 1459e74fda3f1eb7646150eba1665c714be2368b CxxTest support. Added rotor tests. diff -r 1459e74fda3f -r 713fa2a9ea9a .hgignore --- a/.hgignore Fri Jun 22 20:15:11 2012 -0500 +++ b/.hgignore Fri Jun 22 22:02:55 2012 -0500 @@ -2,3 +2,5 @@ build .*.swp .sconsign.dblite +cxxtest +site_scons diff -r 1459e74fda3f -r 713fa2a9ea9a SConstruct --- a/SConstruct Fri Jun 22 20:15:11 2012 -0500 +++ b/SConstruct Fri Jun 22 22:02:55 2012 -0500 @@ -1,5 +1,9 @@ env = Environment( + tools = ['default', 'cxxtest'], CXXFLAGS='-std=c++0x -Wall -Wextra -pedantic', + CPPPATH='#/enigma', + LIBS='enigma', + LIBPATH='#/build', ) SConscript(['enigma/SConscript'], exports='env', variant_dir='build', duplicate=0) diff -r 1459e74fda3f -r 713fa2a9ea9a enigma/SConscript --- a/enigma/SConscript Fri Jun 22 20:15:11 2012 -0500 +++ b/enigma/SConscript Fri Jun 22 22:02:55 2012 -0500 @@ -6,3 +6,5 @@ """) env.StaticLibrary('enigma', sources) + +SConscript(['tests/SConscript'], exports='env', variant_dir='build', duplicate=0) diff -r 1459e74fda3f -r 713fa2a9ea9a enigma/rotor.cpp --- a/enigma/rotor.cpp Fri Jun 22 20:15:11 2012 -0500 +++ b/enigma/rotor.cpp Fri Jun 22 22:02:55 2012 -0500 @@ -91,7 +91,7 @@ if (stepping != nullptr) { - for (char c = *stepping; *stepping != '\0'; ++stepping) + for (char c = *stepping; *stepping != '\0'; c = *(++stepping)) { if (ucase_set.find(c) != ucase_set.end()) { diff -r 1459e74fda3f -r 713fa2a9ea9a enigma/tests/SConscript --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/enigma/tests/SConscript Fri Jun 22 22:02:55 2012 -0500 @@ -0,0 +1,4 @@ +Import('env') + +env.CxxTest('rotor_suite', 'test_rotor.t.h') + diff -r 1459e74fda3f -r 713fa2a9ea9a enigma/tests/test_rotor.t.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/enigma/tests/test_rotor.t.h Fri Jun 22 22:02:55 2012 -0500 @@ -0,0 +1,169 @@ +// Copyright (C) 2012 by Brian Neal. +// This file is part of Cpp-Enigma, the Enigma Machine simulation. +// Cpp-Enigma is released under the MIT License (see License.txt). +// +// test_rotor.t.h - rotor unit tests + +#include +#include +#include +#include +#include "rotor.h" +#include "enigma_utils.h" +#include "rotor_data.h" +#include "rotor_factory.h" + +using namespace enigma; + +const char* const wiring = "EKMFLGDQVZNTOWYHXUSPAIBRCJ"; + + +class MyTestSuite1 : public CxxTest::TestSuite +{ +public: + + void test_bad_wiring() + { + TS_ASSERT_THROWS(rotor("I", ""), rotor_error); + TS_ASSERT_THROWS(rotor("I", "ABC"), rotor_error); + TS_ASSERT_THROWS(rotor("I", "123"), rotor_error); + TS_ASSERT_THROWS(rotor("I", "!\"#$%&'()*+,-./:;<=>?@[\\]^"), rotor_error); + TS_ASSERT_THROWS(rotor("I", "ABCDABCDABCDABCDABCDABCDAB"), rotor_error); + } + + void test_bad_ring_setting() + { + TS_ASSERT_THROWS(rotor("I", wiring, -1), rotor_error); + TS_ASSERT_THROWS(rotor("I", wiring, 26), rotor_error); + } + + void test_bad_stepping() + { + TS_ASSERT_THROWS(rotor("I", wiring, 1, "0"), rotor_error); + TS_ASSERT_THROWS(rotor("I", wiring, 1, "-"), rotor_error); + TS_ASSERT_THROWS(rotor("I", wiring, 1, "A%"), rotor_error); + TS_ASSERT_THROWS(rotor("I", wiring, 1, "A%14"), rotor_error); + } + + void test_display() + { + for (int i = 0; i < 26; ++i) + { + rotor r{"I", wiring, i}; + for (int j = 0; j < 26; ++j) + { + r.set_display(j + 'A'); + TS_ASSERT_EQUALS(j + 'A', r.get_display()); + } + } + } + + // Loop through all ring settings & rotor positions and test the wiring. + void test_wiring() + { + for (int r = 0; r < 26; ++r) + { + rotor test_rotor("I", wiring, r); + + for (int n = 0; n < 26; ++n) + { + const char d = n + 'A'; + test_rotor.set_display(d); + + std::deque wiring_deque(wiring, wiring + 26); + // rotate contents to the right if positive, left if negative: + int rotate_count = r - n; + const bool rotate_right = rotate_count >= 0; + if (rotate_count < 0) + { + rotate_count = -rotate_count; + } + for (int x = 0; x < rotate_count; ++x) + { + if (rotate_right) + { + wiring_deque.push_front(wiring_deque.back()); + wiring_deque.pop_back(); + } + else + { + wiring_deque.push_back(wiring_deque.front()); + wiring_deque.pop_front(); + } + } + + for (int i = 0; i < 26; ++i) + { + int output = test_rotor.signal_in(i); + int expected = alpha_mod(wiring_deque[i] - 'A' + r - n); + TS_ASSERT_EQUALS(output, expected); + + output = test_rotor.signal_out(expected); + TS_ASSERT_EQUALS(output, i); + } + } + } + } + + // For every rotor we simulate, ensure that the notch setting is correct + // regardless of the ring setting. + void test_notches() + { + for (const auto& p : simulated_rotors) + { + const std::string& rotor_name(p.first); + const rotor_data& rd(p.second); + if (rd.stepping == nullptr) + { + continue; + } + const std::string notches(rd.stepping); + + for (int r = 0; r < 26; ++r) + { + std::unique_ptr rp = create_rotor(rotor_name.c_str(), r); + rp->set_display('A'); + + for (int n = 0; n < 26; ++n) + { + const bool over_notch = notches.find(rp->get_display()) != std::string::npos; + TS_ASSERT_EQUALS(over_notch, rp->notch_over_pawl()); + } + } + } + } + + void test_rotate() + { + for (int r = 0; r < 26; ++r) + { + rotor r1("X", wiring, r); + rotor r2("Y", wiring, r); + + r2.set_display('A'); + for (int i = 0; i < 26; ++i) + { + r1.set_display(i + 'A'); + TS_ASSERT_EQUALS(r1.get_display(), r2.get_display()); + r2.rotate(); + } + } + } + + void test_ring_setting() + { + rotor r("X", wiring, 0); + for (int n = 0; n < 26; ++n) + { + r.set_ring_setting(n); + TS_ASSERT_EQUALS(n, r.get_ring_setting()); + + r.set_display('A'); + for (int a = 0; a < 26; ++a) + { + TS_ASSERT_EQUALS(a + 'A', r.get_display()); + r.rotate(); + } + } + } +};