trackler 2.2.1.87 → 2.2.1.88

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/tracks/bash/.travis.yml +6 -2
  4. data/tracks/bash/bin/validate-exercises +37 -0
  5. data/tracks/bash/exercises/reverse-string/example.sh +1 -1
  6. data/tracks/bash/exercises/reverse-string/reverse_string_test.sh +7 -7
  7. data/tracks/csharp/exercises/bracket-push/BracketPush.cs +2 -15
  8. data/tracks/elisp/.travis.yml +2 -2
  9. data/tracks/elisp/config.json +8 -0
  10. data/tracks/elisp/exercises/pangram/README.md +16 -0
  11. data/tracks/elisp/exercises/pangram/example.el +17 -0
  12. data/tracks/elisp/exercises/pangram/pangram-test.el +41 -0
  13. data/tracks/elisp/exercises/pangram/pangram.el +9 -0
  14. data/tracks/gnu-apl/config.json +6 -6
  15. data/tracks/java/exercises/phone-number/.meta/hints.md +58 -0
  16. data/tracks/java/exercises/phone-number/README.md +62 -0
  17. data/tracks/java/exercises/rna-transcription/.meta/version +1 -1
  18. data/tracks/java/exercises/rna-transcription/src/test/java/RnaTranscriptionTest.java +0 -29
  19. data/tracks/python/.travis.yml +2 -2
  20. data/tracks/python/exercises/complex-numbers/.meta/hints.md +3 -0
  21. data/tracks/python/exercises/complex-numbers/README.md +4 -0
  22. data/tracks/python/exercises/complex-numbers/complex_numbers.py +5 -5
  23. data/tracks/python/exercises/complex-numbers/complex_numbers_test.py +28 -32
  24. data/tracks/python/exercises/complex-numbers/example.py +8 -5
  25. data/tracks/python/exercises/difference-of-squares/difference_of_squares.py +3 -3
  26. data/tracks/python/exercises/difference-of-squares/example.py +6 -6
  27. data/tracks/python/exercises/palindrome-products/example.py +112 -11
  28. data/tracks/python/exercises/palindrome-products/palindrome_products_test.py +55 -14
  29. data/tracks/python/exercises/pangram/pangram_test.py +9 -6
  30. data/tracks/python/exercises/phone-number/phone_number_test.py +2 -2
  31. data/tracks/python/exercises/secret-handshake/example.py +14 -47
  32. data/tracks/python/exercises/secret-handshake/secret_handshake.py +2 -2
  33. data/tracks/python/exercises/secret-handshake/secret_handshake_test.py +56 -25
  34. data/tracks/python/exercises/transpose/example.py +5 -5
  35. data/tracks/python/exercises/transpose/transpose_test.py +37 -74
  36. data/tracks/python/exercises/word-search/example.py +1 -1
  37. data/tracks/python/exercises/word-search/word_search_test.py +63 -63
  38. metadata +9 -2
@@ -1,16 +1,11 @@
1
1
  import org.junit.Before;
2
2
  import org.junit.Ignore;
3
- import org.junit.Rule;
4
3
  import org.junit.Test;
5
- import org.junit.rules.ExpectedException;
6
4
 
7
5
  import static org.junit.Assert.assertEquals;
8
6
 
9
7
  public class RnaTranscriptionTest {
10
8
 
11
- @Rule
12
- public ExpectedException expectedException = ExpectedException.none();
13
-
14
9
  private RnaTranscription rnaTranscription;
15
10
 
16
11
  @Before
@@ -47,28 +42,4 @@ public class RnaTranscriptionTest {
47
42
  assertEquals("UGCACCAGAAUU", rnaTranscription.transcribe("ACGTGGTCTTAA"));
48
43
  }
49
44
 
50
- @Ignore("Remove to run test")
51
- @Test
52
- public void testRnaTranscriptionOfRnaThrowsAnError() {
53
- expectedException.expect(IllegalArgumentException.class);
54
- expectedException.expectMessage("Invalid input");
55
- rnaTranscription.transcribe("U");
56
- }
57
-
58
- @Ignore("Remove to run test")
59
- @Test
60
- public void testRnaTranscriptionOfInvalidInputThrowsAnError() {
61
- expectedException.expect(IllegalArgumentException.class);
62
- expectedException.expectMessage("Invalid input");
63
- rnaTranscription.transcribe("XXX");
64
- }
65
-
66
- @Ignore("Remove to run test")
67
- @Test
68
- public void testRnaTranscriptionOfPartiallyInvalidInput() {
69
- expectedException.expect(IllegalArgumentException.class);
70
- expectedException.expectMessage("Invalid input");
71
- rnaTranscription.transcribe("ACGTXXXCTTAA");
72
- }
73
-
74
45
  }
@@ -19,8 +19,8 @@ install:
19
19
 
20
20
  before_script:
21
21
  - flake8
22
-
23
- script:
24
22
  - ./bin/fetch-configlet
25
23
  - ./bin/configlet lint .
24
+
25
+ script:
26
26
  - ./test/check-exercises.py
@@ -0,0 +1,3 @@
1
+ ## Hints
2
+
3
+ See [Emulating numeric types](https://docs.python.org/2/reference/datamodel.html#emulating-numeric-types) for help on operator overloading.
@@ -31,6 +31,10 @@ Implement the following operations:
31
31
 
32
32
  Assume the programming language you are using does not have an implementation of complex numbers.
33
33
 
34
+ ## Hints
35
+
36
+ See [Emulating numeric types](https://docs.python.org/2/reference/datamodel.html#emulating-numeric-types) for help on operator overloading.
37
+
34
38
  ## Exception messages
35
39
 
36
40
  Sometimes it is necessary to raise an exception. When you do this, you should include a meaningful error message to
@@ -2,19 +2,19 @@ class ComplexNumber(object):
2
2
  def __init__(self, real, imaginary):
3
3
  pass
4
4
 
5
- def add(self, other):
5
+ def __add__(self, other):
6
6
  pass
7
7
 
8
- def mul(self, other):
8
+ def __mul__(self, other):
9
9
  pass
10
10
 
11
- def sub(self, other):
11
+ def __sub__(self, other):
12
12
  pass
13
13
 
14
- def div(self, other):
14
+ def __truediv__(self, other):
15
15
  pass
16
16
 
17
- def abs(self):
17
+ def __abs__(self):
18
18
  pass
19
19
 
20
20
  def conjugate(self):
@@ -1,3 +1,5 @@
1
+ from __future__ import division
2
+
1
3
  import unittest
2
4
 
3
5
  import math
@@ -13,95 +15,89 @@ class ComplexNumbersTest(unittest.TestCase):
13
15
  def test_add_purely_real_numbers(self):
14
16
  first_input = ComplexNumber(1, 0)
15
17
  second_input = ComplexNumber(2, 0)
16
- self.assertEqual(first_input.add(second_input).real, 3)
17
- self.assertEqual(first_input.add(second_input).imaginary, 0)
18
+ expected = ComplexNumber(3, 0)
19
+ self.assertEqual(first_input + second_input, expected)
18
20
 
19
21
  def test_add_purely_imaginary_numbers(self):
20
22
  first_input = ComplexNumber(0, 1)
21
23
  second_input = ComplexNumber(0, 2)
22
- self.assertEqual(first_input.add(second_input).real, 0)
23
- self.assertEqual(first_input.add(second_input).imaginary, 3)
24
+ expected = ComplexNumber(0, 3)
25
+ self.assertEqual(first_input + second_input, expected)
24
26
 
25
27
  def test_add_numbers_with_real_and_imaginary_part(self):
26
28
  first_input = ComplexNumber(1, 2)
27
29
  second_input = ComplexNumber(3, 4)
28
- self.assertEqual(first_input.add(second_input).real, 4)
29
- self.assertEqual(first_input.add(second_input).imaginary, 6)
30
+ expected = ComplexNumber(4, 6)
31
+ self.assertEqual(first_input + second_input, expected)
30
32
 
31
33
  def test_subtract_purely_real_numbers(self):
32
34
  first_input = ComplexNumber(1, 0)
33
35
  second_input = ComplexNumber(2, 0)
34
- self.assertEqual(first_input.sub(second_input).real, -1)
35
- self.assertEqual(first_input.sub(second_input).imaginary, 0)
36
+ expected = ComplexNumber(-1, 0)
37
+ self.assertEqual(first_input - second_input, expected)
36
38
 
37
39
  def test_subtract_purely_imaginary_numbers(self):
38
40
  first_input = ComplexNumber(0, 1)
39
41
  second_input = ComplexNumber(0, 2)
40
- self.assertEqual(first_input.sub(second_input).real, 0)
41
- self.assertEqual(first_input.sub(second_input).imaginary, -1)
42
+ expected = ComplexNumber(0, -1)
43
+ self.assertEqual(first_input - second_input, expected)
42
44
 
43
45
  def test_subtract_numbers_with_real_and_imaginary_part(self):
44
46
  first_input = ComplexNumber(1, 2)
45
47
  second_input = ComplexNumber(3, 4)
46
- self.assertEqual(first_input.sub(second_input).real, -2)
47
- self.assertEqual(first_input.sub(second_input).imaginary, -2)
48
+ expected = ComplexNumber(-2, -2)
49
+ self.assertEqual(first_input - second_input, expected)
48
50
 
49
51
  def test_multiply_purely_real_numbers(self):
50
52
  first_input = ComplexNumber(1, 0)
51
53
  second_input = ComplexNumber(2, 0)
52
- self.assertEqual(first_input.mul(second_input).real, 2)
53
- self.assertEqual(first_input.mul(second_input).imaginary, 0)
54
+ expected = ComplexNumber(2, 0)
55
+ self.assertEqual(first_input * second_input, expected)
54
56
 
55
57
  def test_multiply_purely_imaginary_numbers(self):
56
58
  first_input = ComplexNumber(0, 1)
57
59
  second_input = ComplexNumber(0, 2)
58
- self.assertEqual(first_input.mul(second_input).real, -2)
59
- self.assertEqual(first_input.mul(second_input).imaginary, 0)
60
+ expected = ComplexNumber(-2, 0)
61
+ self.assertEqual(first_input * second_input, expected)
60
62
 
61
63
  def test_multiply_numbers_with_real_and_imaginary_part(self):
62
64
  first_input = ComplexNumber(1, 2)
63
65
  second_input = ComplexNumber(3, 4)
64
- self.assertEqual(first_input.mul(second_input).real, -5)
65
- self.assertEqual(first_input.mul(second_input).imaginary, 10)
66
+ expected = ComplexNumber(-5, 10)
67
+ self.assertEqual(first_input * second_input, expected)
66
68
 
67
69
  def test_divide_purely_real_numbers(self):
68
70
  input_number = ComplexNumber(1.0, 0.0)
69
71
  expected = ComplexNumber(0.5, 0.0)
70
72
  divider = ComplexNumber(2.0, 0.0)
71
- self.assertEqual(input_number.div(divider).real, expected.real)
72
- self.assertEqual(input_number.div(divider).imaginary,
73
- expected.imaginary)
73
+ self.assertEqual(input_number / divider, expected)
74
74
 
75
75
  def test_divide_purely_imaginary_numbers(self):
76
76
  input_number = ComplexNumber(0, 1)
77
77
  expected = ComplexNumber(0.5, 0)
78
78
  divider = ComplexNumber(0, 2)
79
- self.assertEqual(input_number.div(divider).real, expected.real)
80
- self.assertEqual(input_number.div(divider).imaginary,
81
- expected.imaginary)
79
+ self.assertEqual(input_number / divider, expected)
82
80
 
83
81
  def test_divide_numbers_with_real_and_imaginary_part(self):
84
82
  input_number = ComplexNumber(1, 2)
85
83
  expected = ComplexNumber(0.44, 0.08)
86
84
  divider = ComplexNumber(3, 4)
87
- self.assertEqual(input_number.div(divider).real, expected.real)
88
- self.assertEqual(input_number.div(divider).imaginary,
89
- expected.imaginary)
85
+ self.assertEqual(input_number / divider, expected)
90
86
 
91
87
  def test_absolute_value_of_a_positive_purely_real_number(self):
92
- self.assertEqual(ComplexNumber(5, 0).abs(), 5)
88
+ self.assertEqual(abs(ComplexNumber(5, 0)), 5)
93
89
 
94
90
  def test_absolute_value_of_a_negative_purely_real_number(self):
95
- self.assertEqual(ComplexNumber(-5, 0).abs(), 5)
91
+ self.assertEqual(abs(ComplexNumber(-5, 0)), 5)
96
92
 
97
93
  def test_absolute_value_of_imaginary_number_positive_imaginary_part(self):
98
- self.assertEqual(ComplexNumber(0, 5).abs(), 5)
94
+ self.assertEqual(abs(ComplexNumber(0, 5)), 5)
99
95
 
100
96
  def test_absolute_value_of_imaginary_number_negative_imaginary_part(self):
101
- self.assertEqual(ComplexNumber(0, -5).abs(), 5)
97
+ self.assertEqual(abs(ComplexNumber(0, -5)), 5)
102
98
 
103
99
  def test_absolute_value_of_a_number_with_real_and_imaginary_part(self):
104
- self.assertEqual(ComplexNumber(3, 4).abs(), 5)
100
+ self.assertEqual(abs(ComplexNumber(3, 4)), 5)
105
101
 
106
102
  def test_conjugate_a_purely_real_number(self):
107
103
  input_number = ComplexNumber(5, 0)
@@ -6,22 +6,25 @@ class ComplexNumber(object):
6
6
  self.real = real
7
7
  self.imaginary = imaginary
8
8
 
9
- def add(self, other):
9
+ def __eq__(self, other):
10
+ return self.real == other.real and self.imaginary == other.imaginary
11
+
12
+ def __add__(self, other):
10
13
  r = self.real + other.real
11
14
  i = self.imaginary + other.imaginary
12
15
  return ComplexNumber(r, i)
13
16
 
14
- def mul(self, other):
17
+ def __mul__(self, other):
15
18
  r = self.real * other.real - self.imaginary * other.imaginary
16
19
  i = self.real * other.imaginary + self.imaginary * other.real
17
20
  return ComplexNumber(r, i)
18
21
 
19
- def sub(self, other):
22
+ def __sub__(self, other):
20
23
  r = self.real - other.real
21
24
  i = self.imaginary - other.imaginary
22
25
  return ComplexNumber(r, i)
23
26
 
24
- def div(self, other):
27
+ def __truediv__(self, other):
25
28
  d = other.real * other.real + other.imaginary * other.imaginary
26
29
  r = (self.real * other.real + self.imaginary *
27
30
  other.imaginary) / float(d)
@@ -29,7 +32,7 @@ class ComplexNumber(object):
29
32
  self.real * other.imaginary) / float(d)
30
33
  return ComplexNumber(r, i)
31
34
 
32
- def abs(self):
35
+ def __abs__(self):
33
36
  square_sum = self.real * self.real + self.imaginary * self.imaginary
34
37
  return math.sqrt(square_sum)
35
38
 
@@ -1,10 +1,10 @@
1
- def square_of_sum():
1
+ def square_of_sum(count):
2
2
  pass
3
3
 
4
4
 
5
- def sum_of_squares():
5
+ def sum_of_squares(count):
6
6
  pass
7
7
 
8
8
 
9
- def difference():
9
+ def difference(count):
10
10
  pass
@@ -1,11 +1,11 @@
1
- def square_of_sum(n):
2
- sum_ = n * (n + 1) / 2
1
+ def square_of_sum(count):
2
+ sum_ = count * (count + 1) / 2
3
3
  return sum_ * sum_
4
4
 
5
5
 
6
- def sum_of_squares(n):
7
- return sum(m * m for m in range(n + 1))
6
+ def sum_of_squares(count):
7
+ return sum(m * m for m in range(count + 1))
8
8
 
9
9
 
10
- def difference(n):
11
- return square_of_sum(n) - sum_of_squares(n)
10
+ def difference(count):
11
+ return square_of_sum(count) - sum_of_squares(count)
@@ -1,18 +1,119 @@
1
- def largest_palindrome(max_factor, min_factor=0):
2
- return max(palindromes(max_factor, min_factor), key=lambda tup: tup[0])
1
+ from __future__ import division
2
+ from itertools import chain
3
+ from math import log10, floor, ceil
4
+
5
+
6
+ def largest_palindrome(max_factor, min_factor):
7
+ return get_extreme_palindrome_with_factors(max_factor, min_factor,
8
+ "largest")
3
9
 
4
10
 
5
11
  def smallest_palindrome(max_factor, min_factor):
6
- return min(palindromes(max_factor, min_factor), key=lambda tup: tup[0])
12
+ return get_extreme_palindrome_with_factors(max_factor, min_factor,
13
+ "smallest")
14
+
15
+
16
+ def get_extreme_palindrome_with_factors(max_factor, min_factor, extreme):
17
+ palindromes_found = palindromes(max_factor, min_factor,
18
+ reverse=(extreme == "largest"))
19
+ factor_pairs = None
20
+ for palin in palindromes_found:
21
+ factor_pairs = ((fact, palin // fact)
22
+ for fact in range(min_factor, max_factor + 1)
23
+ if palin % fact == 0)
24
+ factor_pairs = list(pair for pair in factor_pairs
25
+ if min_factor <= pair[1] <= max_factor)
26
+ if len(factor_pairs) > 0:
27
+ break
28
+
29
+ if factor_pairs is None or len(factor_pairs) == 0:
30
+ raise ValueError("no palindrome with factors in the "
31
+ "range {min_factor} to {max_factor}"
32
+ .format(min_factor=min_factor,
33
+ max_factor=max_factor))
34
+
35
+ return (palin, factor_pairs)
36
+
37
+
38
+ def reverse_num(n):
39
+ rev = 0
40
+ while n > 0:
41
+ rev *= 10
42
+ rev += (n % 10)
43
+ n //= 10
44
+ return rev
45
+
46
+
47
+ def num_digits(n):
48
+ return int(floor(log10(n) + 1))
49
+
50
+
51
+ def palindromes(max_factor, min_factor, reverse=False):
52
+ """Generates all palindromes between `min_factor`**2 and max_factor`**2
53
+
54
+ If `reverse` is True, will produce the palindromes in decreasing order,
55
+ from `max_factor`**2 down to `min_factor`**2. This is needed for
56
+ `largest_palindrome`, since it won't have to iterate through a
57
+ most of the palindromes just to find the one it needs.
58
+ """
59
+ if max_factor < min_factor:
60
+ raise ValueError("invalid input: min is {min_factor} "
61
+ "and max is {max_factor}"
62
+ .format(min_factor=min_factor,
63
+ max_factor=max_factor))
64
+
65
+ minimum = min_factor ** 2
66
+ maximum = max_factor ** 2
67
+
68
+ def gen_palins_of_length(nd, reverse=reverse):
69
+ """Generates all palindromes with `nd` number of digits that are
70
+ within the desired range.
71
+
72
+ Again, if `reverse` is True, the palindromes are generated in
73
+ reverse order.
74
+ """
75
+ even_nd = (nd % 2 == 0)
76
+
77
+ min_left_half = max(10 ** (int(ceil(nd / 2)) - 1),
78
+ minimum // (10 ** (nd // 2)))
79
+ max_left_half = min((10 ** int(ceil(nd / 2))) - 1,
80
+ maximum // (10 ** (nd // 2)))
81
+
82
+ current_left_half = min_left_half if not reverse else max_left_half
83
+
84
+ def make_palindrome(left_half, even_nd=False):
85
+ right_half = (reverse_num(left_half)
86
+ if even_nd
87
+ else reverse_num(left_half // 10))
88
+ return (left_half * (10 ** (nd // 2))) + right_half
7
89
 
90
+ if not reverse:
91
+ while current_left_half <= max_left_half:
92
+ palin = make_palindrome(current_left_half, even_nd)
93
+ if minimum <= palin <= maximum:
94
+ yield palin
95
+ elif palin > maximum:
96
+ # since palindromes are generated in increasing order,
97
+ # we break out of the loop once we've exceeded the
98
+ # maximum value
99
+ break
100
+ current_left_half += 1
101
+ else:
102
+ while current_left_half >= min_left_half:
103
+ palin = make_palindrome(current_left_half, even_nd)
104
+ if minimum <= palin <= maximum:
105
+ yield palin
106
+ elif palin < minimum:
107
+ # since palindromes are generated in decreasing order,
108
+ # we break out of the loop once we've gone below the
109
+ # minimum value
110
+ break
111
+ current_left_half -= 1
8
112
 
9
- def palindromes(max_factor, min_factor):
10
- return ((a * b, (a, b))
11
- for a in range(min_factor, max_factor + 1)
12
- for b in range(min_factor, a + 1)
13
- if is_palindrome(a * b))
113
+ min_nd, max_nd = num_digits(minimum), num_digits(maximum)
14
114
 
115
+ lengths = (range(min_nd, max_nd + 1)
116
+ if not reverse
117
+ else range(max_nd, min_nd - 1, -1))
15
118
 
16
- def is_palindrome(n):
17
- s = str(n)
18
- return s == s[::-1]
119
+ return chain(*map(gen_palins_of_length, lengths))
@@ -16,31 +16,72 @@ import unittest
16
16
  from palindrome_products import smallest_palindrome, largest_palindrome
17
17
 
18
18
 
19
+ # Tests adapted from `problem-specifications//canonical-data.json` @ v1.0.0
20
+
19
21
  class PalindromesTests(unittest.TestCase):
22
+ def test_smallest_palindrome_from_single_digit_factors(self):
23
+ value, factors = smallest_palindrome(min_factor=1, max_factor=9)
24
+ self.assertEqual(value, 1)
25
+ self.assertFactorsEqual(factors, {(1, 1)})
26
+
20
27
  def test_largest_palindrome_from_single_digit_factors(self):
21
- value, factors = largest_palindrome(max_factor=9)
28
+ value, factors = largest_palindrome(min_factor=1, max_factor=9)
22
29
  self.assertEqual(value, 9)
23
- self.assertIn(set(factors), [{1, 9}, {3, 3}])
30
+ self.assertFactorsEqual(factors, {(1, 9), (3, 3)})
31
+
32
+ def test_smallest_palindrome_from_double_digit_factors(self):
33
+ value, factors = smallest_palindrome(min_factor=10, max_factor=99)
34
+ self.assertEqual(value, 121)
35
+ self.assertFactorsEqual(factors, {(11, 11)})
24
36
 
25
37
  def test_largest_palindrome_from_double_digit_factors(self):
26
- value, factors = largest_palindrome(max_factor=99, min_factor=10)
38
+ value, factors = largest_palindrome(min_factor=10, max_factor=99)
27
39
  self.assertEqual(value, 9009)
28
- self.assertEqual(set(factors), {91, 99})
40
+ self.assertFactorsEqual(factors, {(91, 99)})
29
41
 
30
- def test_smallest_palindrome_from_double_digit_factors(self):
31
- value, factors = smallest_palindrome(max_factor=99, min_factor=10)
32
- self.assertEqual(value, 121)
33
- self.assertEqual(set(factors), {11})
42
+ def test_smallest_palindrome_from_triple_digit_factors(self):
43
+ value, factors = smallest_palindrome(min_factor=100, max_factor=999)
44
+ self.assertEqual(value, 10201)
45
+ self.assertFactorsEqual(factors, {(101, 101)})
34
46
 
35
47
  def test_largest_palindrome_from_triple_digit_factors(self):
36
- value, factors = largest_palindrome(max_factor=999, min_factor=100)
48
+ value, factors = largest_palindrome(min_factor=100, max_factor=999)
37
49
  self.assertEqual(value, 906609)
38
- self.assertEqual(set(factors), {913, 993})
50
+ self.assertFactorsEqual(factors, {(913, 993)})
39
51
 
40
- def test_smallest_palindrome_from_triple_digit_factors(self):
41
- value, factors = smallest_palindrome(max_factor=999, min_factor=100)
42
- self.assertEqual(value, 10201)
43
- self.assertEqual(set(factors), {101, 101})
52
+ def test_smallest_palindrome_from_four_digit_factors(self):
53
+ value, factors = smallest_palindrome(min_factor=1000, max_factor=9999)
54
+ self.assertEqual(value, 1002001)
55
+ self.assertFactorsEqual(factors, {(1001, 1001)})
56
+
57
+ def test_largest_palindrome_from_four_digit_factors(self):
58
+ value, factors = largest_palindrome(min_factor=1000, max_factor=9999)
59
+ self.assertEqual(value, 99000099)
60
+ self.assertFactorsEqual(factors, {(9901, 9999)})
61
+
62
+ def test_empty_for_smallest_palindrome_if_none_in_range(self):
63
+ with self.assertRaises(ValueError):
64
+ value, factors = smallest_palindrome(min_factor=1002,
65
+ max_factor=1003)
66
+
67
+ def test_empty_for_largest_palindrome_if_none_in_range(self):
68
+ with self.assertRaises(ValueError):
69
+ value, factors = largest_palindrome(min_factor=15, max_factor=15)
70
+
71
+ def test_error_for_smallest_if_min_is_more_than_max(self):
72
+ with self.assertRaises(ValueError):
73
+ value, factors = smallest_palindrome(min_factor=10000,
74
+ max_factor=1)
75
+
76
+ def test_error_for_largest_if_min_is_more_than_max(self):
77
+ with self.assertRaises(ValueError):
78
+ value, factors = largest_palindrome(min_factor=2, max_factor=1)
79
+
80
+ # Utility methods
81
+
82
+ def assertFactorsEqual(self, actual, expected):
83
+ self.assertEqual(set(map(frozenset, actual)),
84
+ set(map(frozenset, expected)))
44
85
 
45
86
 
46
87
  if __name__ == '__main__':