changeset 18:f4051bcac8c5

Fix for the Rotor.notch_over_pawl() bug. Added 2 more tests for rotors: test_notches & test_rotate.
author Brian Neal <bgneal@gmail.com>
date Sun, 27 May 2012 21:53:47 -0500
parents ce3840115214
children d46635a9f088
files enigma/rotors/rotor.py enigma/tests/test_rotor.py
diffstat 2 files changed, 51 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/enigma/rotors/rotor.py	Sun May 27 21:20:34 2012 -0500
+++ b/enigma/rotors/rotor.py	Sun May 27 21:53:47 2012 -0500
@@ -125,22 +125,27 @@
         for i, v in enumerate(self.entry_map):
             self.exit_map[v] = i
 
-        # configure ring labels
-        self.ring_labels = ALPHA_LABELS
+        # build a map of display values to positions
+        self.display_map = {}
+        for n in range(26):
+            self.display_map[chr(ord('A') + n)] = (n - self.ring_setting) % 26
 
-        # for mapping window display values to indices
-        self.display_map = dict(zip(self.ring_labels, range(26)))
+        # build a reverse map of position mapped to display values
+        self.pos_map = {v : k for k, v in self.display_map.items()}
 
-        # build step list: this is a list of positions where our notches are in
+        # build step set; this is a set of positions where our notches are in
         # place to allow the pawls to move
         self.step_set = set()
         if stepping is not None:
             for pos in stepping:
                 if pos in self.display_map:
-                    self.step_set.add(self.display_map[pos])
+                    self.step_set.add(pos)
                 else:
                     raise RotorError("stepping: %s" % pos)
 
+        # initialize our position and display value:
+        self.set_display('A')
+
     def set_display(self, val):
         """Spin the rotor such that the string val appears in the operator
         window.
@@ -158,18 +163,15 @@
         """
         s = val.upper()
         if s not in self.display_map:
-            raise RotorError("bad display value %s" % s)
+            raise RotorError("bad display value %s" % val)
 
-        index = self.display_map[s]
-
-        self.pos = (index - self.ring_setting) % 26
+        self.pos = self.display_map[s]
+        self.display_val = s
         self.rotations = 0
 
     def get_display(self):
         """Returns what is currently being displayed in the operator window."""
-
-        index = (self.pos + self.ring_setting) % 26
-        return self.ring_labels[index]
+        return self.display_val
 
     def signal_in(self, n):
         """Simulate a signal entering the rotor from the right at a given pin
@@ -212,10 +214,11 @@
         False otherwise.
 
         """
-        return self.pos in self.step_set
+        return self.display_val in self.step_set
 
     def rotate(self):
         """Rotate the rotor forward due to mechanical stepping action."""
 
         self.pos = (self.pos + 1) % 26
+        self.display_val = self.pos_map[self.pos]
         self.rotations += 1
--- a/enigma/tests/test_rotor.py	Sun May 27 21:20:34 2012 -0500
+++ b/enigma/tests/test_rotor.py	Sun May 27 21:53:47 2012 -0500
@@ -10,6 +10,8 @@
 
 from ..rotors.rotor import Rotor, ALPHA_LABELS
 from ..rotors import RotorError
+from ..rotors.data import ROTORS
+from ..rotors.factory import create_rotor
 
 
 WIRING = 'EKMFLGDQVZNTOWYHXUSPAIBRCJ'
@@ -75,3 +77,35 @@
 
                     output = rotor.signal_out(expected)
                     self.assertEqual(output, i)
+
+    def test_notches(self):
+        """For every rotor we simulate, ensure that the notch setting is correct
+        regardless of the ring setting.
+
+        """
+        rotor_names = ROTORS.keys()
+        for rotor_name in rotor_names:
+            notches = ROTORS[rotor_name]['stepping']
+            if notches is None:
+                continue
+            for r in range(26):
+                rotor = create_rotor(rotor_name, r)
+                rotor.set_display('A')
+
+                for n in range(26):
+                    over_notch = rotor.get_display() in notches
+                    self.assertEqual(rotor.notch_over_pawl(), over_notch)
+                    rotor.rotate()
+
+    def test_rotate(self):
+
+        for r in range(26):
+            rotor1 = Rotor('X', WIRING, ring_setting=r)
+            rotor2 = Rotor('Y', WIRING, ring_setting=r)
+
+            rotor2.set_display('A')
+
+            for i, d in enumerate(ALPHA_LABELS):
+                rotor1.set_display(d)
+                self.assertEqual(rotor1.get_display(), rotor2.get_display())
+                rotor2.rotate()