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.
- 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__':
|