changeset 26:425981f27876

More work on generating a key list. Added some tests. TODO: need to account for not all wheels having all the letters.
author Brian Neal <bgneal@gmail.com>
date Fri, 14 Jun 2013 21:46:42 -0500
parents b6b52d63cd50
children 941590d946c0
files m209/keylist/generate.py m209/keylist/tests/test_generate.py
diffstat 2 files changed, 124 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/m209/keylist/generate.py	Fri Jun 14 20:11:41 2013 -0500
+++ b/m209/keylist/generate.py	Fri Jun 14 21:46:42 2013 -0500
@@ -95,10 +95,27 @@
     if not (0.4 <= ratio <= 0.6):
         return False
 
-    # Check for more than 6 consecutive effective pins
-    # TODO
+    # Check for more than 6 consecutive effective pins on a wheel
+    # TODO: not all letters are on every wheel
 
-    # Check for more than 6 consecutive ineffective pins
-    # TODO
+    for pins in pin_list:
+        run = 0
+        for i in range(len(pins) - 1):
+            if ord(pins[i]) + 1 == ord(pins[i + 1]):
+                run = 2 if run == 0 else run + 1
+            else:
+                run = 0
+            if run >= 7:
+                return False
+
+    # Check for more than 6 consecutive ineffective pins on a wheel
+    # TODO: not all letters are on every wheel
+
+    for pins in pin_list:
+        x = 'A'
+        for y in pins:
+            if ord(y) - ord(x) >= 8:
+                return False
+            x = y
 
     return True
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m209/keylist/tests/test_generate.py	Fri Jun 14 21:46:42 2013 -0500
@@ -0,0 +1,103 @@
+# Copyright (C) 2013 by Brian Neal.
+# This file is part of m209, the M-209 simulation.
+# m209 is released under the MIT License (see LICENSE.txt).
+
+"""Tests for the key list generator functions."""
+
+import collections
+import random
+import unittest
+
+from ..generate import generate_key_list, pin_list_check
+from m209.converter import M209
+from m209.data import KEY_WHEEL_DATA
+
+
+def make_pin_list(eff_cnt):
+    """Generates a pin list with an effect pin count given by eff_cnt."""
+    cards = [1] * eff_cnt
+    cards.extend([0] * (131 - len(cards)))
+    random.shuffle(cards)
+    deck = collections.deque(cards)
+    pin_list = []
+    for letters, _ in KEY_WHEEL_DATA:
+        pins = [c for c in letters if deck.pop()]
+        pin_list.append(''.join(pins))
+
+    return pin_list
+
+
+class GenerateTestCase(unittest.TestCase):
+
+    def setUp(self):
+
+        self.valid_pin_list = [
+            'FGIKOPRSUVWYZ',
+            'DFGKLMOTUY',
+            'ADEFGIORTUVX',
+            'ACFGHILMRSU',
+            'BCDEFJKLPS',
+            'EFGHIJLMNP'
+        ]
+
+    def test_generate_key_list(self):
+
+        key_list = generate_key_list('BN')
+        self.assertEqual(key_list.indicator, 'BN')
+        self.assertTrue(isinstance(key_list.pin_list, list))
+        self.assertEqual(len(key_list.pin_list), 6)
+
+        for i, pins in enumerate(key_list.pin_list):
+            self.assertTrue(all(c in KEY_WHEEL_DATA[i][0] for c in pins))
+
+        # TODO: add some lug asserts
+
+        m_209 = M209(lugs=key_list.lugs, pin_list=key_list.pin_list)
+        m_209.set_key_wheels('AAAAAA')
+        s = m_209.encrypt('A' * 26)
+        self.assertEqual(s, key_list.letter_check)
+
+    def test_pin_list_check(self):
+
+        # Effective pin ratio too high (100%)
+        all_pins = [t[0] for t in KEY_WHEEL_DATA]
+        self.assertEqual(False, pin_list_check(all_pins))
+
+        # Effective pin ratio too low (0%)
+        no_pins = ['' for i in range(6)]
+        self.assertEqual(False, pin_list_check(no_pins))
+
+        # Effective pin ratio too low (< 40%)
+        self.assertFalse(pin_list_check(make_pin_list(10)))
+        self.assertFalse(pin_list_check(make_pin_list(20)))
+        self.assertFalse(pin_list_check(make_pin_list(30)))
+        self.assertFalse(pin_list_check(make_pin_list(40)))
+        self.assertFalse(pin_list_check(make_pin_list(50)))
+
+        # Effective pin ratio too high (< 60%)
+        self.assertFalse(pin_list_check(make_pin_list(79)))
+        self.assertFalse(pin_list_check(make_pin_list(85)))
+        self.assertFalse(pin_list_check(make_pin_list(95)))
+        self.assertFalse(pin_list_check(make_pin_list(100)))
+        self.assertFalse(pin_list_check(make_pin_list(125)))
+
+    def test_consecutive_effective_pins(self):
+
+        pin_list = self.valid_pin_list
+        pin_list[0] = 'ABEGHIJKLNOSUZ'
+        self.assertTrue(pin_list_check(pin_list))
+        pin_list[0] = 'ABEGHIJKLM'
+        self.assertFalse(pin_list_check(pin_list))
+        pin_list[0] = 'ABEGHIJKLMN'
+        self.assertFalse(pin_list_check(pin_list))
+        pin_list[0] = 'ABCDEFGHIJ'
+        self.assertFalse(pin_list_check(pin_list))
+        pin_list[0] = 'BDJKLMNOPTW'
+        self.assertFalse(pin_list_check(pin_list))
+        pin_list[0] = 'BEFGHIJKSUX'
+        self.assertFalse(pin_list_check(pin_list))
+
+    def test_consecutive_noneffective_pins(self):
+        pass
+
+