Advertisement
Guest User

Untitled

a guest
Feb 13th, 2016
65
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.87 KB | None | 0 0
  1. import unittest
  2. import re
  3.  
  4. class RomanToNumberConverter:
  5. # Validate that the input may even be processed.
  6. def validate(self, roman):
  7. if type(roman) is not str:
  8. raise ValueError("You must provide a string.")
  9. if roman == '':
  10. raise ValueError("An empty string was provided.")
  11. if len(roman) > 25:
  12. raise ValueError("Input string is over 25 characters.")
  13.  
  14. roman = roman.upper()
  15. if not re.match('[IVXLCDM]+', roman):
  16. raise ValueError("Invalid roman numerals: " + roman)
  17.  
  18. # Convert roman numerals to individual numbers to be summed up, like:
  19. # "DLXXXIX" -> [500, 50, 10, 10, 10, 9]
  20. # Subtract elements are grouped together into one number like "IX" -> 9.
  21. def split_roman_to_numbers(self, roman):
  22. numerals = {'I': 1, 'V': 5, 'X': 10, 'L': 50,
  23. 'C': 100, 'D': 500, 'M': 1000}
  24. parts = []
  25. i = 0
  26. while i < len(roman):
  27. # Subtractions can only go back one character, be careful not to go
  28. # beyond the end when looking for double letter combination.
  29. a, b = numerals[roman[i]], 0
  30. if i < len(roman) - 1:
  31. b = numerals[roman[i + 1]]
  32.  
  33. # A subtraction uses two characters so we should skip then next one.
  34. this = a
  35. if a < b:
  36. this = b - a
  37. i += 1
  38.  
  39. parts.append(this)
  40.  
  41. i += 1
  42.  
  43. return parts
  44.  
  45. # Roman numbers must have the hundreds, tens and ones grouped separately.
  46. # Make sure the numerals are in this sequence and that the total is in an
  47. # acceptable range.
  48. def validated_total(self, roman, numbers):
  49. if numbers != sorted(numbers, reverse=True):
  50. raise ValueError('Invalid roman numerals: ' + roman)
  51.  
  52. total = sum(numbers)
  53. if total > 1000:
  54. raise ValueError("Number is larger than 1000.")
  55.  
  56. return total
  57.  
  58. # Convert roman numbers to a number.
  59. def roman_to_number(self, roman):
  60. self.validate(roman)
  61. roman = roman.upper()
  62. numbers = self.split_roman_to_numbers(roman)
  63.  
  64. return self.validated_total(roman, numbers)
  65.  
  66. class TestRomanToNumber(unittest.TestCase):
  67. def assertError(self, msg, *args, **kwargs):
  68. try:
  69. converter = RomanToNumberConverter()
  70. converter.roman_to_number(*args, **kwargs)
  71. self.assertFail()
  72. except ValueError as e:
  73. self.assertEqual(e.message, msg)
  74.  
  75. def test_P_is_invalid(self):
  76. self.assertError('Invalid roman numerals: P', 'P')
  77.  
  78. def test_blank_string(self):
  79. self.assertError('An empty string was provided.', '')
  80.  
  81. def test_invalid_type(self):
  82. self.assertError('You must provide a string.', 123)
  83.  
  84. def test_string_too_long(self):
  85. self.assertError('Input string is over 25 characters.', 'I' * 26)
  86.  
  87. def test_Z_is_invalid(self):
  88. self.assertError('Invalid roman numerals: Z', 'Z')
  89.  
  90. def test_always_convert_to_upper_case(self):
  91. self.assertError('Invalid roman numerals: U', 'u')
  92.  
  93. def assertResult(self, roman, number):
  94. converter = RomanToNumberConverter()
  95. result = converter.roman_to_number(roman)
  96. self.assertEquals(result, number)
  97.  
  98. def test_I_is_1(self):
  99. self.assertResult('I', 1)
  100.  
  101. def test_II_is_2(self):
  102. self.assertResult('II', 2)
  103.  
  104. def test_V_is_5(self):
  105. self.assertResult('V', 5)
  106.  
  107. def test_v_is_5(self):
  108. self.assertResult('v', 5)
  109.  
  110. def test_VI_is_6(self):
  111. self.assertResult('VI', 6)
  112.  
  113. def test_VII_is_7(self):
  114. self.assertResult('VII', 7)
  115.  
  116. def test_X_is_10(self):
  117. self.assertResult('X', 10)
  118.  
  119. def test_L_is_50(self):
  120. self.assertResult('L', 50)
  121.  
  122. def test_C_is_100(self):
  123. self.assertResult('C', 100)
  124.  
  125. def test_D_is_500(self):
  126. self.assertResult('D', 500)
  127.  
  128. def test_M_is_1000(self):
  129. self.assertResult('M', 1000)
  130.  
  131. def test_IV_is_4(self):
  132. self.assertResult('IV', 4)
  133.  
  134. def test_IX_is_9(self):
  135. self.assertResult('IX', 9)
  136.  
  137. def test_XL_is_40(self):
  138. self.assertResult('XL', 40)
  139.  
  140. def test_XIX_is_19(self):
  141. self.assertResult('XIX', 19)
  142.  
  143. def test_MI_is_to_large(self):
  144. self.assertError('Number is larger than 1000.', 'MI')
  145.  
  146. def test_IXL_is_invalid(self):
  147. self.assertError('Invalid roman numerals: IXL', 'IXL')
  148.  
  149. def test_all(self):
  150. ones = ('', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX')
  151. tens = ('', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC')
  152. huns = ('', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM')
  153. i = 0
  154. for h in huns:
  155. for t in tens:
  156. for o in ones:
  157. if i > 0:
  158. self.assertResult(h + t + o, i)
  159. i += 1
  160.  
  161. # This will run the unit tests
  162. unittest.main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement