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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/common/exercises/simple-cipher/description.md +1 -1
  3. data/common/exercises/triangle/description.md +12 -23
  4. data/lib/trackler/version.rb +1 -1
  5. data/tracks/kotlin/config.json +5 -0
  6. data/tracks/kotlin/exercises/bank-account/build.gradle +32 -0
  7. data/tracks/kotlin/exercises/bank-account/src/example/kotlin/BankAccount.kt +27 -0
  8. data/tracks/kotlin/exercises/bank-account/src/main/kotlin/.keep +0 -0
  9. data/tracks/kotlin/exercises/bank-account/src/test/kotlin/BankAccountTest.kt +73 -0
  10. data/tracks/kotlin/exercises/settings.gradle +1 -0
  11. data/tracks/python/config.json +11 -11
  12. data/tracks/python/exercises/accumulate/accumulate_test.py +16 -14
  13. data/tracks/python/exercises/acronym/acronym_test.py +8 -7
  14. data/tracks/python/exercises/allergies/allergies_test.py +5 -6
  15. data/tracks/python/exercises/atbash-cipher/atbash_cipher_test.py +16 -22
  16. data/tracks/python/exercises/binary-search/binary_search_test.py +12 -10
  17. data/tracks/python/exercises/binary/binary_test.py +7 -8
  18. data/tracks/python/exercises/circular-buffer/circular_buffer_test.py +16 -17
  19. data/tracks/python/exercises/clock/clock_test.py +35 -35
  20. data/tracks/python/exercises/crypto-square/crypto_square_test.py +5 -6
  21. data/tracks/python/exercises/diamond/diamond_test.py +3 -4
  22. data/tracks/python/exercises/etl/etl_test.py +4 -4
  23. data/tracks/python/exercises/gigasecond/gigasecond_test.py +11 -19
  24. data/tracks/python/exercises/grade-school/grade_school_test.py +17 -19
  25. data/tracks/python/exercises/grains/grains_test.py +14 -14
  26. data/tracks/python/exercises/grep/grep_test.py +51 -64
  27. data/tracks/python/exercises/hamming/hamming_test.py +13 -13
  28. data/tracks/python/exercises/hello-world/hello_world_test.py +1 -2
  29. data/tracks/python/exercises/hexadecimal/hexadecimal_test.py +9 -10
  30. data/tracks/python/exercises/house/house_test.py +6 -6
  31. data/tracks/python/exercises/kindergarten-garden/kindergarten_garden_test.py +22 -19
  32. data/tracks/python/exercises/largest-series-product/largest_series_product_test.py +29 -28
  33. data/tracks/python/exercises/linked-list/linked_list_test.py +18 -19
  34. data/tracks/python/exercises/list-ops/list_ops_test.py +44 -39
  35. data/tracks/python/exercises/matrix/matrix_test.py +6 -6
  36. data/tracks/python/exercises/meetup/meetup_test.py +27 -27
  37. data/tracks/python/exercises/minesweeper/example.py +4 -2
  38. data/tracks/python/exercises/minesweeper/minesweeper_test.py +9 -9
  39. data/tracks/python/exercises/nucleotide-count/nucleotide_count_test.py +6 -6
  40. data/tracks/python/exercises/ocr-numbers/ocr_numbers_test.py +63 -49
  41. data/tracks/python/exercises/octal/octal_test.py +7 -7
  42. data/tracks/python/exercises/palindrome-products/palindrome_products_test.py +9 -9
  43. data/tracks/python/exercises/pascals-triangle/pascals_triangle_test.py +7 -7
  44. data/tracks/python/exercises/phone-number/phone_number_test.py +8 -8
  45. data/tracks/python/exercises/pig-latin/pig_latin_test.py +15 -15
  46. data/tracks/python/exercises/point-mutations/point_mutations_test.py +11 -11
  47. data/tracks/python/exercises/poker/poker_test.py +32 -30
  48. data/tracks/python/exercises/prime-factors/prime_factors_test.py +11 -11
  49. data/tracks/python/exercises/proverb/proverb_test.py +16 -9
  50. data/tracks/python/exercises/pythagorean-triplet/pythagorean_triplet_test.py +14 -12
  51. data/tracks/python/exercises/queen-attack/queen_attack_test.py +10 -10
  52. data/tracks/python/exercises/rail-fence-cipher/example.py +2 -1
  53. data/tracks/python/exercises/rail-fence-cipher/rail_fence_cipher_test.py +14 -13
  54. data/tracks/python/exercises/raindrops/raindrops_test.py +16 -16
  55. data/tracks/python/exercises/rectangles/rectangles_test.py +9 -9
  56. data/tracks/python/exercises/rna-transcription/rna_transcription_test.py +8 -8
  57. data/tracks/python/exercises/robot-name/robot_name_test.py +1 -1
  58. data/tracks/python/exercises/robot-simulator/robot_simulator_test.py +18 -19
  59. data/tracks/python/exercises/roman-numerals/roman_numerals_test.py +1 -1
  60. data/tracks/python/exercises/run-length-encoding/run_length_encoding_test.py +15 -16
  61. data/tracks/python/exercises/saddle-points/saddle_points_test.py +4 -4
  62. data/tracks/python/exercises/say/say_test.py +21 -23
  63. data/tracks/python/exercises/scrabble-score/scrabble_score_test.py +9 -9
  64. data/tracks/python/exercises/secret-handshake/secret_handshake_test.py +14 -13
  65. data/tracks/python/exercises/series/example.py +3 -3
  66. data/tracks/python/exercises/series/series_test.py +16 -12
  67. data/tracks/python/exercises/simple-cipher/simple_cipher_test.py +21 -19
  68. data/tracks/python/exercises/space-age/space_age_test.py +16 -16
  69. data/tracks/python/exercises/strain/strain_test.py +9 -8
  70. data/tracks/python/exercises/sublist/sublist_test.py +19 -20
  71. data/tracks/python/exercises/sum-of-multiples/example.py +1 -4
  72. data/tracks/python/exercises/sum-of-multiples/sum_of_multiples_test.py +31 -26
  73. data/tracks/python/exercises/triangle/triangle_test.py +15 -30
  74. data/tracks/python/exercises/trinary/trinary_test.py +7 -7
  75. data/tracks/python/exercises/twelve-days/twelve_days_test.py +13 -14
  76. data/tracks/python/exercises/word-count/example.py +1 -9
  77. data/tracks/python/exercises/word-count/word_count_test.py +0 -15
  78. data/tracks/python/exercises/wordy/wordy_test.py +17 -18
  79. data/tracks/python/exercises/zebra-puzzle/example.py +20 -23
  80. data/tracks/python/exercises/zebra-puzzle/zebra_puzzle_test.py +3 -3
  81. data/tracks/python/test/check-exercises.py +1 -1
  82. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b5c894b894e9f0f3d11e47d960d538044a4863cd
4
- data.tar.gz: f0150355935cc408bc6fe6cfb8922fb32bd32267
3
+ metadata.gz: 88860310ccc044c6401cd6578337ddc2b13bcbf1
4
+ data.tar.gz: 2b09ed02e5926183697dafc3d13f8402cf7ee95f
5
5
  SHA512:
6
- metadata.gz: 7c70f073bbd990f0d6dbbe5734a19016bc18435f151a009e7c6cd48dda5b2101d5096cc993a749c167a228d97ed29588478d4ace4d0c63ced64976b9234f88b6
7
- data.tar.gz: af5c762cba7ea0dc69d25c8e8b05c7108754597a869cf7a5c20ea071a4d6a937c98a5be02d46530a0c8298aba7b7fe59c9ef4a7458e86fa126a949bcb4f6acda
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 they key is not composed of numbers or
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
- The program should raise an error if the triangle cannot exist.
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
- ## Hint
7
+ ## Note
4
8
 
5
- The triangle inequality theorem states:
6
- z x + y
7
- where x,y, and z are the lengths of the sides of a triangle. In other words, the
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
- This exercise does not test for degenerate triangles. Feel free to add your own
28
- tests to check for degenerate triangles.
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.
@@ -1,3 +1,3 @@
1
1
  module Trackler
2
- VERSION = "2.0.8.27"
2
+ VERSION = "2.0.8.28"
3
3
  end
@@ -233,6 +233,11 @@
233
233
  "slug": "triangle",
234
234
  "topics": []
235
235
  },
236
+ {
237
+ "difficulty": 2,
238
+ "slug": "bank-account",
239
+ "topics": ["Concurrency"]
240
+ },
236
241
  {
237
242
  "difficulty": 10,
238
243
  "slug": "react",
@@ -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
+ }
@@ -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
+
@@ -42,3 +42,4 @@ include 'largest-series-product'
42
42
  include 'change'
43
43
  include 'binary-search'
44
44
  include 'triangle'
45
+ include 'bank-account'
@@ -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([], accumulate([], lambda x: x / 2))
8
+ self.assertEqual(accumulate([], lambda x: x / 2), [])
9
9
 
10
10
  def test_pow(self):
11
- self.assertEqual([1, 4, 9, 16, 25], accumulate([1, 2, 3, 4, 5],
12
- lambda x: x * x))
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
- inp = [10, 17, 23]
16
- out = [(1, 3), (2, 3), (3, 2)]
17
- self.assertEqual(out, accumulate(inp, lambda x: divmod(x, 7)))
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(inp, accumulate(accumulate(inp, lambda x: divmod(x, 7)),
22
- lambda x: 7 * x[0] + x[1]))
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
- inp = ['hello', 'world']
26
- out = ['HELLO', 'WORLD']
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 = list('abc')
31
+ inp = ['a', 'b', 'c']
31
32
  out = [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3']]
32
- self.assertEqual(out, accumulate(inp, lambda x: accumulate(list('123'),
33
- lambda y: x + y)))
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('PNG', abbreviate('Portable Network Graphics'))
10
+ self.assertEqual(abbreviate('Portable Network Graphics'), 'PNG')
11
11
 
12
12
  def test_lowercase_words(self):
13
- self.assertEqual('ROR', abbreviate('Ruby on Rails'))
13
+ self.assertEqual(abbreviate('Ruby on Rails'), 'ROR')
14
14
 
15
15
  def test_camelcase(self):
16
- self.assertEqual('HTML', abbreviate('HyperText Markup Language'))
16
+ self.assertEqual(abbreviate('HyperText Markup Language'), 'HTML')
17
17
 
18
18
  def test_punctuation(self):
19
- self.assertEqual('FIFO', abbreviate('First In, First Out'))
19
+ self.assertEqual(abbreviate('First In, First Out'), 'FIFO')
20
20
 
21
21
  def test_all_caps_words(self):
22
- self.assertEqual('PHP', abbreviate('PHP: Hypertext Preprocessor'))
22
+ self.assertEqual(abbreviate('PHP: Hypertext Preprocessor'), 'PHP')
23
23
 
24
24
  def test_non_acronym_all_caps_word(self):
25
- self.assertEqual('GIMP', abbreviate('GNU Image Manipulation Program'))
25
+ self.assertEqual(abbreviate('GNU Image Manipulation Program'), 'GIMP')
26
26
 
27
27
  def test_hyphenated(self):
28
- self.assertEqual('CMOS', abbreviate('Complementary metal-oxide semiconductor'))
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([], Allergies(0).lst)
23
+ self.assertEqual(Allergies(0).lst, [])
25
24
 
26
25
  def test_allergic_to_just_peanuts(self):
27
- self.assertEqual(['peanuts'], Allergies(2).lst)
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(['eggs'], Allergies(257).lst)
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("ml", encode("no"))
10
+ self.assertMultiLineEqual(encode("no"), "ml")
12
11
 
13
12
  def test_encode_yes(self):
14
- self.assertMultiLineEqual("bvh", encode("yes"))
13
+ self.assertMultiLineEqual(encode("yes"), "bvh")
15
14
 
16
15
  def test_encode_OMG(self):
17
- self.assertMultiLineEqual("lnt", encode("OMG"))
16
+ self.assertMultiLineEqual(encode("OMG"), "lnt")
18
17
 
19
18
  def test_encode_O_M_G(self):
20
- self.assertMultiLineEqual("lnt", encode("O M G"))
19
+ self.assertMultiLineEqual(encode("O M G"), "lnt")
21
20
 
22
21
  def test_encode_long_word(self):
23
- self.assertMultiLineEqual("nrmwy oldrm tob", encode("mindblowingly"))
22
+ self.assertMultiLineEqual(encode("mindblowingly"), "nrmwy oldrm tob")
24
23
 
25
24
  def test_encode_numbers(self):
26
- self.assertMultiLineEqual("gvhgr mt123 gvhgr mt",
27
- encode("Testing, 1 2 3, testing."))
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("gifgs rhurx grlm",
31
- encode("Truth is fiction."))
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(ciphertext, encode(plaintext))
35
+ self.assertMultiLineEqual(encode(plaintext), ciphertext)
37
36
 
38
37
  def test_decode_word(self):
39
- self.assertMultiLineEqual("exercism", decode("vcvix rhn"))
38
+ self.assertMultiLineEqual(decode("vcvix rhn"), "exercism")
40
39
 
41
40
  def test_decode_sentence(self):
42
41
  self.assertMultiLineEqual(
43
- "anobstacleisoftenasteppingstone",
44
- decode("zmlyh gzxov rhlug vmzhg vkkrm thglm v")
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(plaintext, decode(ciphertext))
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__':