diff --git a/exercises/luhn/example.py b/exercises/luhn/example.py index f6981cee5a..4c062c0431 100644 --- a/exercises/luhn/example.py +++ b/exercises/luhn/example.py @@ -1,11 +1,11 @@ class Luhn(object): - def __init__(self, number): - self.number = number + def __init__(self, string): + self.string = string.replace(" ", "") def addends(self): def luhn_transform(n): return (2 * n - 9) if (n > 4) else (2 * n) - old_digits = [int(d) for d in str(self.number)] + old_digits = [int(d) for d in str(self.string)] return [(luhn_transform(n) if (i % 2 == 0) else n) for i, n in enumerate(old_digits, start=len(old_digits) % 2)] @@ -13,9 +13,6 @@ def checksum(self): return sum(self.addends()) def is_valid(self): + if len(self.string) <= 1 or not self.string.isdigit(): + return False return self.checksum() % 10 == 0 - - @staticmethod - def create(n): - diff = (10 - Luhn(n * 10).checksum()) % 10 - return 10 * n + diff diff --git a/exercises/luhn/luhn_test.py b/exercises/luhn/luhn_test.py index 630b1c8ca1..42bfe36848 100644 --- a/exercises/luhn/luhn_test.py +++ b/exercises/luhn/luhn_test.py @@ -1,46 +1,56 @@ -from collections import Counter +# -*- coding: utf-8 -*- + import unittest from luhn import Luhn class LuhnTests(unittest.TestCase): - def test_addends(self): - # uses a Counter to avoid specifying order of return value - self.assertEqual(Counter([1, 4, 1, 4, 1]), - Counter(Luhn(12121).addends())) + def test_single_digit_strings_can_not_be_valid(self): + self.assertFalse(Luhn("1").is_valid()) + + def test_a_single_zero_is_invalid(self): + self.assertFalse(Luhn("0").is_valid()) + + def test_a_simple_valid_SIN_that_remains_valid_if_reversed(self): + self.assertTrue(Luhn("059").is_valid()) + + def test_a_simple_valid_SIN_that_becomes_invalid_if_reversed(self): + self.assertTrue(Luhn("59").is_valid()) + + def test_a_valid_Canadian_SIN(self): + self.assertTrue(Luhn("055 444 285").is_valid()) - def test_addends_large(self): - # uses a Counter to avoid specifying order of return value - self.assertEqual(Counter([7, 6, 6, 1]), - Counter(Luhn(8631).addends())) + def test_invalid_Canadian_SIN(self): + self.assertFalse(Luhn("055 444 286").is_valid()) - def test_checksum1(self): - self.assertEqual(22, Luhn(4913).checksum()) + def test_invalid_credit_card(self): + self.assertFalse(Luhn("8273 1232 7352 0569").is_valid()) - def test_ckecksum2(self): - self.assertEqual(21, Luhn(201773).checksum()) + def test_valid_strings_with_a_non_digit_included_become_invalid(self): + self.assertFalse(Luhn("055a 444 285").is_valid()) - def test_invalid_number(self): - self.assertFalse(Luhn(738).is_valid()) + def test_valid_strings_with_punctuation_included_become_invalid(self): + self.assertFalse(Luhn("055-444-285").is_valid()) - def test_valid_number(self): - self.assertTrue(Luhn(8739567).is_valid()) + def test_valid_strings_with_symbols_included_become_invalid(self): + self.assertFalse(Luhn("055£ 444$ 285").is_valid()) - def test_create_valid_number1(self): - self.assertEqual(1230, Luhn.create(123)) + def test_single_zero_with_space_is_invalid(self): + self.assertFalse(Luhn("0").is_valid()) - def test_create_valid_number2(self): - self.assertEqual(8739567, Luhn.create(873956)) + def test_more_than_a_single_zero_is_valid(self): + self.assertTrue(Luhn("0000 0").is_valid()) - def test_create_valid_number3(self): - self.assertEqual(8372637564, Luhn.create(837263756)) + def test_input_digit_9_is_correctly_converted_to_output_digit_9(self): + self.assertTrue(Luhn("091").is_valid()) def test_is_valid_can_be_called_repeatedly(self): + # Additional track specific test case # This test was added, because we saw many implementations # in which the first call to is_valid() worked, but the # second call failed(). - number = Luhn(8739567) + number = Luhn("055 444 285") self.assertTrue(number.is_valid()) self.assertTrue(number.is_valid())