trackler 2.0.8.27 → 2.0.8.28
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/common/exercises/simple-cipher/description.md +1 -1
- data/common/exercises/triangle/description.md +12 -23
- data/lib/trackler/version.rb +1 -1
- data/tracks/kotlin/config.json +5 -0
- data/tracks/kotlin/exercises/bank-account/build.gradle +32 -0
- data/tracks/kotlin/exercises/bank-account/src/example/kotlin/BankAccount.kt +27 -0
- data/tracks/kotlin/exercises/bank-account/src/main/kotlin/.keep +0 -0
- data/tracks/kotlin/exercises/bank-account/src/test/kotlin/BankAccountTest.kt +73 -0
- data/tracks/kotlin/exercises/settings.gradle +1 -0
- data/tracks/python/config.json +11 -11
- data/tracks/python/exercises/accumulate/accumulate_test.py +16 -14
- data/tracks/python/exercises/acronym/acronym_test.py +8 -7
- data/tracks/python/exercises/allergies/allergies_test.py +5 -6
- data/tracks/python/exercises/atbash-cipher/atbash_cipher_test.py +16 -22
- data/tracks/python/exercises/binary-search/binary_search_test.py +12 -10
- data/tracks/python/exercises/binary/binary_test.py +7 -8
- data/tracks/python/exercises/circular-buffer/circular_buffer_test.py +16 -17
- data/tracks/python/exercises/clock/clock_test.py +35 -35
- data/tracks/python/exercises/crypto-square/crypto_square_test.py +5 -6
- data/tracks/python/exercises/diamond/diamond_test.py +3 -4
- data/tracks/python/exercises/etl/etl_test.py +4 -4
- data/tracks/python/exercises/gigasecond/gigasecond_test.py +11 -19
- data/tracks/python/exercises/grade-school/grade_school_test.py +17 -19
- data/tracks/python/exercises/grains/grains_test.py +14 -14
- data/tracks/python/exercises/grep/grep_test.py +51 -64
- data/tracks/python/exercises/hamming/hamming_test.py +13 -13
- data/tracks/python/exercises/hello-world/hello_world_test.py +1 -2
- data/tracks/python/exercises/hexadecimal/hexadecimal_test.py +9 -10
- data/tracks/python/exercises/house/house_test.py +6 -6
- data/tracks/python/exercises/kindergarten-garden/kindergarten_garden_test.py +22 -19
- data/tracks/python/exercises/largest-series-product/largest_series_product_test.py +29 -28
- data/tracks/python/exercises/linked-list/linked_list_test.py +18 -19
- data/tracks/python/exercises/list-ops/list_ops_test.py +44 -39
- data/tracks/python/exercises/matrix/matrix_test.py +6 -6
- data/tracks/python/exercises/meetup/meetup_test.py +27 -27
- data/tracks/python/exercises/minesweeper/example.py +4 -2
- data/tracks/python/exercises/minesweeper/minesweeper_test.py +9 -9
- data/tracks/python/exercises/nucleotide-count/nucleotide_count_test.py +6 -6
- data/tracks/python/exercises/ocr-numbers/ocr_numbers_test.py +63 -49
- data/tracks/python/exercises/octal/octal_test.py +7 -7
- data/tracks/python/exercises/palindrome-products/palindrome_products_test.py +9 -9
- data/tracks/python/exercises/pascals-triangle/pascals_triangle_test.py +7 -7
- data/tracks/python/exercises/phone-number/phone_number_test.py +8 -8
- data/tracks/python/exercises/pig-latin/pig_latin_test.py +15 -15
- data/tracks/python/exercises/point-mutations/point_mutations_test.py +11 -11
- data/tracks/python/exercises/poker/poker_test.py +32 -30
- data/tracks/python/exercises/prime-factors/prime_factors_test.py +11 -11
- data/tracks/python/exercises/proverb/proverb_test.py +16 -9
- data/tracks/python/exercises/pythagorean-triplet/pythagorean_triplet_test.py +14 -12
- data/tracks/python/exercises/queen-attack/queen_attack_test.py +10 -10
- data/tracks/python/exercises/rail-fence-cipher/example.py +2 -1
- data/tracks/python/exercises/rail-fence-cipher/rail_fence_cipher_test.py +14 -13
- data/tracks/python/exercises/raindrops/raindrops_test.py +16 -16
- data/tracks/python/exercises/rectangles/rectangles_test.py +9 -9
- data/tracks/python/exercises/rna-transcription/rna_transcription_test.py +8 -8
- data/tracks/python/exercises/robot-name/robot_name_test.py +1 -1
- data/tracks/python/exercises/robot-simulator/robot_simulator_test.py +18 -19
- data/tracks/python/exercises/roman-numerals/roman_numerals_test.py +1 -1
- data/tracks/python/exercises/run-length-encoding/run_length_encoding_test.py +15 -16
- data/tracks/python/exercises/saddle-points/saddle_points_test.py +4 -4
- data/tracks/python/exercises/say/say_test.py +21 -23
- data/tracks/python/exercises/scrabble-score/scrabble_score_test.py +9 -9
- data/tracks/python/exercises/secret-handshake/secret_handshake_test.py +14 -13
- data/tracks/python/exercises/series/example.py +3 -3
- data/tracks/python/exercises/series/series_test.py +16 -12
- data/tracks/python/exercises/simple-cipher/simple_cipher_test.py +21 -19
- data/tracks/python/exercises/space-age/space_age_test.py +16 -16
- data/tracks/python/exercises/strain/strain_test.py +9 -8
- data/tracks/python/exercises/sublist/sublist_test.py +19 -20
- data/tracks/python/exercises/sum-of-multiples/example.py +1 -4
- data/tracks/python/exercises/sum-of-multiples/sum_of_multiples_test.py +31 -26
- data/tracks/python/exercises/triangle/triangle_test.py +15 -30
- data/tracks/python/exercises/trinary/trinary_test.py +7 -7
- data/tracks/python/exercises/twelve-days/twelve_days_test.py +13 -14
- data/tracks/python/exercises/word-count/example.py +1 -9
- data/tracks/python/exercises/word-count/word_count_test.py +0 -15
- data/tracks/python/exercises/wordy/wordy_test.py +17 -18
- data/tracks/python/exercises/zebra-puzzle/example.py +20 -23
- data/tracks/python/exercises/zebra-puzzle/zebra_puzzle_test.py +3 -3
- data/tracks/python/test/check-exercises.py +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88860310ccc044c6401cd6578337ddc2b13bcbf1
|
4
|
+
data.tar.gz: 2b09ed02e5926183697dafc3d13f8402cf7ee95f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 778a87faf57b3b14f0260da2c758dbb284d88e6b7d4e0befc81426e6724f6147129c19037398b21d85824efe1ab4d7aaa8d8f071695b8f29fda71f8c0a3d99f4
|
7
|
+
data.tar.gz: 0d89dad5d10d0087386d7704eaf9e80255642b039aa0590ac9d61de0e4aca0674f5aecaa2c3934fab785012bdda26fde53bb11eb94ce9d21d02b4c950f9979c1
|
@@ -54,7 +54,7 @@ would get the same thing as the Caesar Cipher.
|
|
54
54
|
|
55
55
|
The weakest link in any cipher is the human being. Let's make your
|
56
56
|
substitution cipher a little more fault tolerant by providing a source
|
57
|
-
of randomness and ensuring that
|
57
|
+
of randomness and ensuring that the key is not composed of numbers or
|
58
58
|
capital letters.
|
59
59
|
|
60
60
|
If someone doesn't submit a key at all, generate a truly random key of
|
@@ -1,28 +1,17 @@
|
|
1
|
-
|
1
|
+
An _equilateral_ triangle has all three sides the same length.<br/>
|
2
|
+
An _isoceles_ triangle has at least two sides the same length. (It is sometimes
|
3
|
+
specified as having exactly two sides the same length, but for the purposes of
|
4
|
+
this exercise we'll say at least two.)<br/>
|
5
|
+
A _scalene_ triangle has all sides of different lengths.
|
2
6
|
|
3
|
-
##
|
7
|
+
## Note
|
4
8
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
sum of the lengths of any two sides of a triangle always exceeds or is equal to
|
9
|
-
the length of the third side.
|
10
|
-
|
11
|
-
A corollary to the triangle inequality theorem is there are two classes of
|
12
|
-
triangles--degenerate and non-degenerate. If the sum of the lengths of any two
|
13
|
-
sides of a triangle is greater than the length of the third side, that triangle
|
14
|
-
is two dimensional, has area, and belongs to the non-degenerate class. In
|
15
|
-
mathematics, a degenerate case is a limiting case in which an element of a class
|
16
|
-
of objects is qualitatively different from the rest of the class and hence
|
17
|
-
belongs to another, usually simpler, class. The degenerate case of the triangle
|
18
|
-
inequality theorem is when the sum of the lengths of any two sides of a triangle
|
19
|
-
is equal to the length of the third side. A triangle with such qualities is
|
20
|
-
qualitatively different from all the triangles in the non-degenerate class since
|
21
|
-
it is one dimensional, looks like a straight line, and has no area. Such
|
22
|
-
triangles are called degenerate triangles and they belong to the degenerate
|
23
|
-
class.
|
9
|
+
For a shape to be a triangle at all, all sides have to be of length > 0, and
|
10
|
+
the sum of the lengths of any two sides must be greater than or equal to the
|
11
|
+
length of the third side. See [Triangle Inequality](https://en.wikipedia.org/wiki/Triangle_inequality).
|
24
12
|
|
25
13
|
## Dig Deeper
|
26
14
|
|
27
|
-
|
28
|
-
|
15
|
+
The case where the sum of the lengths of two sides _equals_ that of the
|
16
|
+
third is known as a _degenerate_ triangle - it has zero area and looks like
|
17
|
+
a single line. Feel free to add your own code/tests to check for degenerate triangles.
|
data/lib/trackler/version.rb
CHANGED
data/tracks/kotlin/config.json
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
buildscript {
|
2
|
+
ext.kotlin_version = '1.1.1'
|
3
|
+
repositories {
|
4
|
+
mavenCentral()
|
5
|
+
}
|
6
|
+
dependencies {
|
7
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
8
|
+
}
|
9
|
+
}
|
10
|
+
|
11
|
+
apply plugin: 'kotlin'
|
12
|
+
|
13
|
+
kotlin.experimental.coroutines = 'enable'
|
14
|
+
|
15
|
+
repositories {
|
16
|
+
mavenCentral()
|
17
|
+
jcenter()
|
18
|
+
}
|
19
|
+
|
20
|
+
dependencies {
|
21
|
+
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
22
|
+
|
23
|
+
testCompile 'junit:junit:4.12'
|
24
|
+
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
|
25
|
+
testCompile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.13'
|
26
|
+
}
|
27
|
+
test {
|
28
|
+
testLogging {
|
29
|
+
exceptionFormat = 'full'
|
30
|
+
events = ["passed", "failed", "skipped"]
|
31
|
+
}
|
32
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class BankAccount {
|
2
|
+
var balance: Long = 0
|
3
|
+
get() {
|
4
|
+
synchronized(lock) {
|
5
|
+
if (!isOpen) throw IllegalStateException("Account is closed")
|
6
|
+
return field
|
7
|
+
}
|
8
|
+
}
|
9
|
+
private set
|
10
|
+
|
11
|
+
var isOpen = true
|
12
|
+
private set
|
13
|
+
|
14
|
+
fun adjustBalance(amount: Long) {
|
15
|
+
synchronized(lock) {
|
16
|
+
balance += amount
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
fun close() {
|
21
|
+
synchronized(lock) {
|
22
|
+
isOpen = false
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
private val lock = Any()
|
27
|
+
}
|
File without changes
|
@@ -0,0 +1,73 @@
|
|
1
|
+
import org.junit.Ignore
|
2
|
+
import org.junit.Test
|
3
|
+
import java.util.*
|
4
|
+
import kotlin.test.assertEquals
|
5
|
+
import kotlin.test.assertFailsWith
|
6
|
+
import kotlinx.coroutines.experimental.*
|
7
|
+
|
8
|
+
class BankAccountTest {
|
9
|
+
|
10
|
+
@Test
|
11
|
+
fun zeroBalanceWhenOpened() {
|
12
|
+
val account = BankAccount()
|
13
|
+
assertEquals(0, account.balance)
|
14
|
+
}
|
15
|
+
|
16
|
+
@Ignore
|
17
|
+
@Test
|
18
|
+
fun sequentialBalanceAdjustments() {
|
19
|
+
val account = BankAccount()
|
20
|
+
|
21
|
+
account.adjustBalance(1000)
|
22
|
+
assertEquals(1000, account.balance)
|
23
|
+
|
24
|
+
account.adjustBalance(-958)
|
25
|
+
assertEquals(42, account.balance)
|
26
|
+
}
|
27
|
+
|
28
|
+
@Ignore
|
29
|
+
@Test
|
30
|
+
fun closedAccountHasNoBalance() {
|
31
|
+
val account = BankAccount()
|
32
|
+
account.close()
|
33
|
+
|
34
|
+
assertFailsWith(IllegalStateException::class, { account.balance })
|
35
|
+
}
|
36
|
+
|
37
|
+
@Ignore
|
38
|
+
@Test
|
39
|
+
fun closedAccountCannotBeAdjusted() {
|
40
|
+
val account = BankAccount()
|
41
|
+
account.close()
|
42
|
+
|
43
|
+
assertFailsWith(IllegalStateException::class, { account.adjustBalance(1000) })
|
44
|
+
}
|
45
|
+
|
46
|
+
@Ignore
|
47
|
+
@Test
|
48
|
+
fun concurrentBalanceAdjustments() {
|
49
|
+
val threads = 1000
|
50
|
+
val iterations = 500
|
51
|
+
val random = Random()
|
52
|
+
|
53
|
+
val account = BankAccount()
|
54
|
+
|
55
|
+
val jobs = List(threads) {
|
56
|
+
launch(CommonPool) {
|
57
|
+
repeat(iterations) {
|
58
|
+
account.adjustBalance(1)
|
59
|
+
delay(random.nextInt(10).toLong())
|
60
|
+
account.adjustBalance(-1)
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
runBlocking {
|
66
|
+
jobs.forEach { it.join() }
|
67
|
+
}
|
68
|
+
|
69
|
+
assertEquals(0, account.balance)
|
70
|
+
}
|
71
|
+
|
72
|
+
}
|
73
|
+
|
data/tracks/python/config.json
CHANGED
@@ -22,17 +22,6 @@
|
|
22
22
|
"logic"
|
23
23
|
]
|
24
24
|
},
|
25
|
-
{
|
26
|
-
"slug": "clock",
|
27
|
-
"difficulty": 2,
|
28
|
-
"topics": [
|
29
|
-
"classes",
|
30
|
-
"time",
|
31
|
-
"mathematics",
|
32
|
-
"logic",
|
33
|
-
"text formatting"
|
34
|
-
]
|
35
|
-
},
|
36
25
|
{
|
37
26
|
"slug": "isogram",
|
38
27
|
"difficulty": 1,
|
@@ -432,6 +421,17 @@
|
|
432
421
|
"transforming"
|
433
422
|
]
|
434
423
|
},
|
424
|
+
{
|
425
|
+
"slug": "clock",
|
426
|
+
"difficulty": 2,
|
427
|
+
"topics": [
|
428
|
+
"classes",
|
429
|
+
"time",
|
430
|
+
"mathematics",
|
431
|
+
"logic",
|
432
|
+
"text formatting"
|
433
|
+
]
|
434
|
+
},
|
435
435
|
{
|
436
436
|
"slug": "grep",
|
437
437
|
"difficulty": 4,
|
@@ -5,32 +5,34 @@ from accumulate import accumulate
|
|
5
5
|
|
6
6
|
class AccumulateTest(unittest.TestCase):
|
7
7
|
def test_empty_sequence(self):
|
8
|
-
self.assertEqual(
|
8
|
+
self.assertEqual(accumulate([], lambda x: x / 2), [])
|
9
9
|
|
10
10
|
def test_pow(self):
|
11
|
-
self.assertEqual(
|
12
|
-
|
11
|
+
self.assertEqual(
|
12
|
+
accumulate([1, 2, 3, 4, 5], lambda x: x * x), [1, 4, 9, 16, 25])
|
13
13
|
|
14
14
|
def test_divmod(self):
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
self.assertEqual(
|
16
|
+
accumulate([10, 17, 23], lambda x: divmod(x, 7)),
|
17
|
+
[(1, 3), (2, 3), (3, 2)])
|
18
18
|
|
19
19
|
def test_composition(self):
|
20
20
|
inp = [10, 17, 23]
|
21
|
-
self.assertEqual(
|
22
|
-
|
21
|
+
self.assertEqual(
|
22
|
+
accumulate(
|
23
|
+
accumulate(inp, lambda x: divmod(x, 7)),
|
24
|
+
lambda x: 7 * x[0] + x[1]), inp)
|
23
25
|
|
24
26
|
def test_capitalize(self):
|
25
|
-
|
26
|
-
|
27
|
-
self.assertEqual(out, accumulate(inp, str.upper))
|
27
|
+
self.assertEqual(
|
28
|
+
accumulate(['hello', 'world'], str.upper), ['HELLO', 'WORLD'])
|
28
29
|
|
29
30
|
def test_recursive(self):
|
30
|
-
inp =
|
31
|
+
inp = ['a', 'b', 'c']
|
31
32
|
out = [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3']]
|
32
|
-
self.assertEqual(
|
33
|
-
|
33
|
+
self.assertEqual(
|
34
|
+
accumulate(
|
35
|
+
inp, lambda x: accumulate(list('123'), lambda y: x + y)), out)
|
34
36
|
|
35
37
|
|
36
38
|
if __name__ == '__main__':
|
@@ -7,25 +7,26 @@ from acronym import abbreviate
|
|
7
7
|
|
8
8
|
class AcronymTest(unittest.TestCase):
|
9
9
|
def test_basic(self):
|
10
|
-
self.assertEqual(
|
10
|
+
self.assertEqual(abbreviate('Portable Network Graphics'), 'PNG')
|
11
11
|
|
12
12
|
def test_lowercase_words(self):
|
13
|
-
self.assertEqual(
|
13
|
+
self.assertEqual(abbreviate('Ruby on Rails'), 'ROR')
|
14
14
|
|
15
15
|
def test_camelcase(self):
|
16
|
-
self.assertEqual(
|
16
|
+
self.assertEqual(abbreviate('HyperText Markup Language'), 'HTML')
|
17
17
|
|
18
18
|
def test_punctuation(self):
|
19
|
-
self.assertEqual(
|
19
|
+
self.assertEqual(abbreviate('First In, First Out'), 'FIFO')
|
20
20
|
|
21
21
|
def test_all_caps_words(self):
|
22
|
-
self.assertEqual(
|
22
|
+
self.assertEqual(abbreviate('PHP: Hypertext Preprocessor'), 'PHP')
|
23
23
|
|
24
24
|
def test_non_acronym_all_caps_word(self):
|
25
|
-
self.assertEqual(
|
25
|
+
self.assertEqual(abbreviate('GNU Image Manipulation Program'), 'GIMP')
|
26
26
|
|
27
27
|
def test_hyphenated(self):
|
28
|
-
self.assertEqual(
|
28
|
+
self.assertEqual(
|
29
|
+
abbreviate('Complementary metal-oxide semiconductor'), 'CMOS')
|
29
30
|
|
30
31
|
|
31
32
|
if __name__ == '__main__':
|
@@ -4,7 +4,6 @@ from allergies import Allergies
|
|
4
4
|
|
5
5
|
|
6
6
|
class AllergiesTests(unittest.TestCase):
|
7
|
-
|
8
7
|
def test_no_allergies_means_not_allergic(self):
|
9
8
|
allergies = Allergies(0)
|
10
9
|
self.assertFalse(allergies.is_allergic_to('peanuts'))
|
@@ -21,20 +20,20 @@ class AllergiesTests(unittest.TestCase):
|
|
21
20
|
self.assertFalse(allergies.is_allergic_to('strawberries'))
|
22
21
|
|
23
22
|
def test_no_allergies_at_all(self):
|
24
|
-
self.assertEqual(
|
23
|
+
self.assertEqual(Allergies(0).lst, [])
|
25
24
|
|
26
25
|
def test_allergic_to_just_peanuts(self):
|
27
|
-
self.assertEqual(
|
26
|
+
self.assertEqual(Allergies(2).lst, ['peanuts'])
|
28
27
|
|
29
28
|
def test_allergic_to_everything(self):
|
30
29
|
self.assertEqual(
|
30
|
+
sorted(Allergies(255).lst),
|
31
31
|
sorted(('eggs peanuts shellfish strawberries tomatoes '
|
32
|
-
'chocolate pollen cats').split())
|
33
|
-
sorted(Allergies(255).lst))
|
32
|
+
'chocolate pollen cats').split()))
|
34
33
|
|
35
34
|
@unittest.skip('Extra Credit: Passes with a specific type of solution')
|
36
35
|
def test_ignore_non_allergen_score_parts(self):
|
37
|
-
self.assertEqual(
|
36
|
+
self.assertEqual(Allergies(257).lst, ['eggs'])
|
38
37
|
|
39
38
|
|
40
39
|
if __name__ == '__main__':
|
@@ -6,61 +6,55 @@ from atbash_cipher import decode, encode
|
|
6
6
|
# test cases adapted from `x-common//canonical-data.json` @ version: 1.0.0
|
7
7
|
|
8
8
|
class AtbashCipherTest(unittest.TestCase):
|
9
|
-
|
10
9
|
def test_encode_no(self):
|
11
|
-
self.assertMultiLineEqual("
|
10
|
+
self.assertMultiLineEqual(encode("no"), "ml")
|
12
11
|
|
13
12
|
def test_encode_yes(self):
|
14
|
-
self.assertMultiLineEqual("
|
13
|
+
self.assertMultiLineEqual(encode("yes"), "bvh")
|
15
14
|
|
16
15
|
def test_encode_OMG(self):
|
17
|
-
self.assertMultiLineEqual("
|
16
|
+
self.assertMultiLineEqual(encode("OMG"), "lnt")
|
18
17
|
|
19
18
|
def test_encode_O_M_G(self):
|
20
|
-
self.assertMultiLineEqual(
|
19
|
+
self.assertMultiLineEqual(encode("O M G"), "lnt")
|
21
20
|
|
22
21
|
def test_encode_long_word(self):
|
23
|
-
self.assertMultiLineEqual("nrmwy oldrm tob"
|
22
|
+
self.assertMultiLineEqual(encode("mindblowingly"), "nrmwy oldrm tob")
|
24
23
|
|
25
24
|
def test_encode_numbers(self):
|
26
|
-
self.assertMultiLineEqual(
|
27
|
-
|
25
|
+
self.assertMultiLineEqual(
|
26
|
+
encode("Testing, 1 2 3, testing."), "gvhgr mt123 gvhgr mt")
|
28
27
|
|
29
28
|
def test_encode_sentence(self):
|
30
|
-
self.assertMultiLineEqual(
|
31
|
-
|
29
|
+
self.assertMultiLineEqual(
|
30
|
+
encode("Truth is fiction."), "gifgs rhurx grlm")
|
32
31
|
|
33
32
|
def test_encode_all_things(self):
|
34
33
|
plaintext = "The quick brown fox jumps over the lazy dog."
|
35
34
|
ciphertext = "gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt"
|
36
|
-
self.assertMultiLineEqual(
|
35
|
+
self.assertMultiLineEqual(encode(plaintext), ciphertext)
|
37
36
|
|
38
37
|
def test_decode_word(self):
|
39
|
-
self.assertMultiLineEqual(
|
38
|
+
self.assertMultiLineEqual(decode("vcvix rhn"), "exercism")
|
40
39
|
|
41
40
|
def test_decode_sentence(self):
|
42
41
|
self.assertMultiLineEqual(
|
43
|
-
"
|
44
|
-
|
45
|
-
)
|
42
|
+
decode("zmlyh gzxov rhlug vmzhg vkkrm thglm v"),
|
43
|
+
"anobstacleisoftenasteppingstone")
|
46
44
|
|
47
45
|
def test_decode_numbers(self):
|
48
46
|
self.assertMultiLineEqual(
|
49
|
-
"testing123testing"
|
50
|
-
decode("gvhgr mt123 gvhgr mt")
|
51
|
-
)
|
47
|
+
decode("gvhgr mt123 gvhgr mt"), "testing123testing")
|
52
48
|
|
53
49
|
def test_decode_all_the_letters(self):
|
54
50
|
ciphertext = "gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt"
|
55
51
|
plaintext = "thequickbrownfoxjumpsoverthelazydog"
|
56
|
-
self.assertMultiLineEqual(
|
52
|
+
self.assertMultiLineEqual(decode(ciphertext), plaintext)
|
57
53
|
|
58
54
|
# additional track specific test
|
59
55
|
def test_encode_decode(self):
|
60
56
|
self.assertMultiLineEqual(
|
61
|
-
"testing123testing"
|
62
|
-
decode(encode("Testing, 1 2 3, testing."))
|
63
|
-
)
|
57
|
+
decode(encode("Testing, 1 2 3, testing.")), "testing123testing")
|
64
58
|
|
65
59
|
|
66
60
|
if __name__ == '__main__':
|