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.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/tracks/bash/.travis.yml +6 -2
- data/tracks/bash/bin/validate-exercises +37 -0
- data/tracks/bash/exercises/reverse-string/example.sh +1 -1
- data/tracks/bash/exercises/reverse-string/reverse_string_test.sh +7 -7
- data/tracks/csharp/exercises/bracket-push/BracketPush.cs +2 -15
- data/tracks/elisp/.travis.yml +2 -2
- data/tracks/elisp/config.json +8 -0
- data/tracks/elisp/exercises/pangram/README.md +16 -0
- data/tracks/elisp/exercises/pangram/example.el +17 -0
- data/tracks/elisp/exercises/pangram/pangram-test.el +41 -0
- data/tracks/elisp/exercises/pangram/pangram.el +9 -0
- data/tracks/gnu-apl/config.json +6 -6
- data/tracks/java/exercises/phone-number/.meta/hints.md +58 -0
- data/tracks/java/exercises/phone-number/README.md +62 -0
- data/tracks/java/exercises/rna-transcription/.meta/version +1 -1
- data/tracks/java/exercises/rna-transcription/src/test/java/RnaTranscriptionTest.java +0 -29
- data/tracks/python/.travis.yml +2 -2
- data/tracks/python/exercises/complex-numbers/.meta/hints.md +3 -0
- data/tracks/python/exercises/complex-numbers/README.md +4 -0
- data/tracks/python/exercises/complex-numbers/complex_numbers.py +5 -5
- data/tracks/python/exercises/complex-numbers/complex_numbers_test.py +28 -32
- data/tracks/python/exercises/complex-numbers/example.py +8 -5
- data/tracks/python/exercises/difference-of-squares/difference_of_squares.py +3 -3
- data/tracks/python/exercises/difference-of-squares/example.py +6 -6
- data/tracks/python/exercises/palindrome-products/example.py +112 -11
- data/tracks/python/exercises/palindrome-products/palindrome_products_test.py +55 -14
- data/tracks/python/exercises/pangram/pangram_test.py +9 -6
- data/tracks/python/exercises/phone-number/phone_number_test.py +2 -2
- data/tracks/python/exercises/secret-handshake/example.py +14 -47
- data/tracks/python/exercises/secret-handshake/secret_handshake.py +2 -2
- data/tracks/python/exercises/secret-handshake/secret_handshake_test.py +56 -25
- data/tracks/python/exercises/transpose/example.py +5 -5
- data/tracks/python/exercises/transpose/transpose_test.py +37 -74
- data/tracks/python/exercises/word-search/example.py +1 -1
- data/tracks/python/exercises/word-search/word_search_test.py +63 -63
- 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
|
}
|
data/tracks/python/.travis.yml
CHANGED
@@ -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
|
5
|
+
def __add__(self, other):
|
6
6
|
pass
|
7
7
|
|
8
|
-
def
|
8
|
+
def __mul__(self, other):
|
9
9
|
pass
|
10
10
|
|
11
|
-
def
|
11
|
+
def __sub__(self, other):
|
12
12
|
pass
|
13
13
|
|
14
|
-
def
|
14
|
+
def __truediv__(self, other):
|
15
15
|
pass
|
16
16
|
|
17
|
-
def
|
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
|
-
|
17
|
-
self.assertEqual(first_input
|
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
|
-
|
23
|
-
self.assertEqual(first_input
|
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
|
-
|
29
|
-
self.assertEqual(first_input
|
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
|
-
|
35
|
-
self.assertEqual(first_input
|
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
|
-
|
41
|
-
self.assertEqual(first_input
|
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
|
-
|
47
|
-
self.assertEqual(first_input
|
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
|
-
|
53
|
-
self.assertEqual(first_input
|
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
|
-
|
59
|
-
self.assertEqual(first_input
|
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
|
-
|
65
|
-
self.assertEqual(first_input
|
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
|
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
|
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
|
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)
|
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)
|
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)
|
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)
|
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)
|
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
|
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
|
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
|
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
|
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
|
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,11 +1,11 @@
|
|
1
|
-
def square_of_sum(
|
2
|
-
sum_ =
|
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(
|
7
|
-
return sum(m * m for m in range(
|
6
|
+
def sum_of_squares(count):
|
7
|
+
return sum(m * m for m in range(count + 1))
|
8
8
|
|
9
9
|
|
10
|
-
def difference(
|
11
|
-
return square_of_sum(
|
10
|
+
def difference(count):
|
11
|
+
return square_of_sum(count) - sum_of_squares(count)
|
@@ -1,18 +1,119 @@
|
|
1
|
-
|
2
|
-
|
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
|
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
|
-
|
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
|
-
|
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.
|
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(
|
38
|
+
value, factors = largest_palindrome(min_factor=10, max_factor=99)
|
27
39
|
self.assertEqual(value, 9009)
|
28
|
-
self.
|
40
|
+
self.assertFactorsEqual(factors, {(91, 99)})
|
29
41
|
|
30
|
-
def
|
31
|
-
value, factors = smallest_palindrome(
|
32
|
-
self.assertEqual(value,
|
33
|
-
self.
|
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(
|
48
|
+
value, factors = largest_palindrome(min_factor=100, max_factor=999)
|
37
49
|
self.assertEqual(value, 906609)
|
38
|
-
self.
|
50
|
+
self.assertFactorsEqual(factors, {(913, 993)})
|
39
51
|
|
40
|
-
def
|
41
|
-
value, factors = smallest_palindrome(
|
42
|
-
self.assertEqual(value,
|
43
|
-
self.
|
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__':
|