trackler 2.2.1.87 → 2.2.1.88

Sign up to get free protection for your applications and to get access to all the features.
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__':