trackler 2.2.1.52 → 2.2.1.53

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/problem-specifications/exercises/leap/canonical-data.json +2 -2
  4. data/tracks/cfml/tasks/FormatConfig.cfc +6 -4
  5. data/tracks/cfml/tasks/GenerateReadme.cfc +197 -0
  6. data/tracks/cfml/tasks/ScaffoldExercise.cfc +6 -0
  7. data/tracks/csharp/config.json +1 -1
  8. data/tracks/delphi/exercises/leap/uLeapTests.pas +1 -1
  9. data/tracks/fsharp/exercises/clock/Clock.fs +1 -1
  10. data/tracks/fsharp/exercises/clock/ClockTest.fs +239 -61
  11. data/tracks/fsharp/exercises/clock/Example.fs +3 -3
  12. data/tracks/fsharp/exercises/dominoes/DominoesTest.fs +29 -26
  13. data/tracks/fsharp/exercises/largest-series-product/LargestSeriesProductTest.fs +30 -15
  14. data/tracks/fsharp/exercises/leap/LeapTest.fs +2 -2
  15. data/tracks/fsharp/exercises/rectangles/Example.fs +1 -1
  16. data/tracks/fsharp/exercises/rectangles/Rectangles.fs +1 -1
  17. data/tracks/fsharp/exercises/rectangles/RectanglesTest.fs +66 -43
  18. data/tracks/fsharp/generators/Generators.fs +85 -1
  19. data/tracks/java/scripts/canonical_data_check.sh +8 -0
  20. data/tracks/kotlin/.gitignore +1 -0
  21. data/tracks/kotlin/exercises/acronym/.meta/version +1 -0
  22. data/tracks/kotlin/exercises/acronym/src/test/kotlin/AcronymTest.kt +9 -10
  23. data/tracks/kotlin/exercises/all-your-base/.meta/version +1 -1
  24. data/tracks/kotlin/exercises/all-your-base/src/test/kotlin/BaseConverterTest.kt +20 -20
  25. data/tracks/kotlin/exercises/allergies/.meta/version +1 -0
  26. data/tracks/kotlin/exercises/allergies/src/test/kotlin/AllergiesTest.kt +19 -72
  27. data/tracks/kotlin/exercises/anagram/.meta/src/reference/kotlin/Anagram.kt +7 -4
  28. data/tracks/kotlin/exercises/anagram/.meta/version +1 -0
  29. data/tracks/kotlin/exercises/anagram/src/test/kotlin/AnagramTest.kt +76 -29
  30. data/tracks/kotlin/exercises/atbash-cipher/.meta/version +1 -0
  31. data/tracks/kotlin/exercises/atbash-cipher/src/test/kotlin/AtbashTest.kt +6 -3
  32. data/tracks/kotlin/exercises/beer-song/.meta/version +1 -0
  33. data/tracks/kotlin/exercises/beer-song/src/test/kotlin/BeerSongTest.kt +21 -46
  34. data/tracks/kotlin/exercises/binary-search/.meta/version +1 -0
  35. data/tracks/kotlin/exercises/binary-search/src/test/kotlin/BinarySearchTest.kt +30 -19
  36. data/tracks/kotlin/exercises/bob/.meta/src/reference/kotlin/Bob.kt +8 -7
  37. data/tracks/kotlin/exercises/bob/.meta/version +1 -0
  38. data/tracks/kotlin/exercises/bob/src/test/kotlin/BobTest.kt +57 -15
  39. data/tracks/kotlin/exercises/bracket-push/.meta/version +1 -0
  40. data/tracks/kotlin/exercises/bracket-push/src/test/kotlin/BracketPushTest.kt +3 -1
  41. data/tracks/kotlin/exercises/collatz-conjecture/.meta/version +1 -1
  42. data/tracks/kotlin/exercises/difference-of-squares/.meta/version +1 -0
  43. data/tracks/kotlin/exercises/difference-of-squares/src/test/kotlin/SquaresTest.kt +10 -23
  44. data/tracks/kotlin/exercises/etl/.meta/src/reference/kotlin/ETL.kt +7 -1
  45. data/tracks/kotlin/exercises/etl/.meta/version +1 -0
  46. data/tracks/kotlin/exercises/etl/src/test/kotlin/ETLTest.kt +10 -10
  47. data/tracks/kotlin/exercises/flatten-array/.meta/version +1 -0
  48. data/tracks/kotlin/exercises/flatten-array/src/test/kotlin/FlattenerTest.kt +8 -16
  49. data/tracks/kotlin/exercises/gigasecond/.meta/version +1 -0
  50. data/tracks/kotlin/exercises/gigasecond/src/test/kotlin/GigasecondTest.kt +1 -1
  51. data/tracks/kotlin/exercises/hamming/.meta/src/reference/kotlin/Hamming.kt +1 -1
  52. data/tracks/kotlin/exercises/hamming/.meta/version +1 -1
  53. data/tracks/kotlin/exercises/hamming/src/test/kotlin/HammingTest.kt +4 -4
  54. data/tracks/kotlin/exercises/hello-world/.meta/version +1 -0
  55. data/tracks/kotlin/exercises/hello-world/src/test/kotlin/HelloWorldTest.kt +1 -1
  56. data/tracks/kotlin/exercises/isogram/.meta/version +1 -0
  57. data/tracks/kotlin/exercises/isogram/src/test/kotlin/IsogramTest.kt +5 -8
  58. data/tracks/kotlin/exercises/largest-series-product/.meta/src/reference/kotlin/Series.kt +2 -3
  59. data/tracks/kotlin/exercises/largest-series-product/.meta/version +1 -0
  60. data/tracks/kotlin/exercises/largest-series-product/src/test/kotlin/SeriesTest.kt +97 -0
  61. data/tracks/kotlin/exercises/leap/.meta/version +1 -0
  62. data/tracks/kotlin/exercises/leap/src/test/kotlin/LeapTest.kt +8 -26
  63. data/tracks/kotlin/exercises/list-ops/.meta/version +1 -1
  64. data/tracks/kotlin/exercises/luhn/.meta/version +1 -0
  65. data/tracks/kotlin/exercises/luhn/src/test/kotlin/LuhnTest.kt +0 -3
  66. data/tracks/kotlin/exercises/nth-prime/.meta/version +1 -0
  67. data/tracks/kotlin/exercises/nth-prime/src/test/kotlin/PrimeTest.kt +0 -2
  68. data/tracks/kotlin/exercises/nucleotide-count/.meta/src/reference/kotlin/{DNA.kt → Dna.kt} +3 -8
  69. data/tracks/kotlin/exercises/nucleotide-count/.meta/version +1 -0
  70. data/tracks/kotlin/exercises/nucleotide-count/src/test/kotlin/DnaTest.kt +48 -0
  71. data/tracks/kotlin/exercises/pangram/.meta/src/reference/kotlin/{Pangrams.kt → Pangram.kt} +1 -1
  72. data/tracks/kotlin/exercises/pangram/.meta/version +1 -1
  73. data/tracks/kotlin/exercises/pangram/src/test/kotlin/PangramTest.kt +15 -9
  74. data/tracks/kotlin/exercises/pascals-triangle/.meta/version +1 -0
  75. data/tracks/kotlin/exercises/pascals-triangle/src/test/kotlin/PascalsTriangleTest.kt +32 -14
  76. data/tracks/kotlin/exercises/perfect-numbers/.meta/src/reference/kotlin/NaturalNumber.kt +1 -1
  77. data/tracks/kotlin/exercises/perfect-numbers/.meta/version +1 -0
  78. data/tracks/kotlin/exercises/perfect-numbers/src/test/kotlin/{PerfectNumbersTest.kt → NaturalNumberTest.kt} +25 -7
  79. data/tracks/kotlin/exercises/phone-number/.meta/src/reference/kotlin/PhoneNumber.kt +15 -7
  80. data/tracks/kotlin/exercises/phone-number/.meta/version +1 -0
  81. data/tracks/kotlin/exercises/phone-number/src/test/kotlin/PhoneNumberTest.kt +46 -29
  82. data/tracks/kotlin/exercises/pig-latin/.meta/src/reference/kotlin/PigLatin.kt +2 -2
  83. data/tracks/kotlin/exercises/pig-latin/.meta/version +1 -0
  84. data/tracks/kotlin/exercises/pig-latin/src/test/kotlin/PigLatinTest.kt +21 -10
  85. data/tracks/kotlin/exercises/raindrops/.meta/version +1 -0
  86. data/tracks/kotlin/exercises/raindrops/src/test/kotlin/RaindropsTest.kt +19 -26
  87. data/tracks/kotlin/exercises/react/.meta/version +1 -0
  88. data/tracks/kotlin/exercises/react/src/test/kotlin/ReactTest.kt +11 -4
  89. data/tracks/kotlin/exercises/robot-simulator/.meta/version +1 -1
  90. data/tracks/kotlin/exercises/roman-numerals/.meta/version +1 -0
  91. data/tracks/kotlin/exercises/roman-numerals/src/test/kotlin/RomanNumeralTest.kt +1 -2
  92. data/tracks/kotlin/exercises/rotational-cipher/.meta/version +1 -1
  93. data/tracks/kotlin/exercises/rotational-cipher/src/test/kotlin/RotationalCipherTest.kt +7 -7
  94. data/tracks/kotlin/exercises/scrabble-score/.meta/src/reference/kotlin/{Scrabble.kt → ScrabbleScore.kt} +1 -1
  95. data/tracks/kotlin/exercises/scrabble-score/.meta/version +1 -0
  96. data/tracks/kotlin/exercises/scrabble-score/src/test/kotlin/ScrabbleScoreTest.kt +9 -7
  97. data/tracks/kotlin/exercises/sieve/.meta/version +1 -0
  98. data/tracks/kotlin/exercises/sieve/src/test/kotlin/SieveTest.kt +8 -0
  99. data/tracks/kotlin/exercises/space-age/.meta/version +1 -0
  100. data/tracks/kotlin/exercises/space-age/src/test/kotlin/SpaceAgeTest.kt +1 -16
  101. data/tracks/kotlin/exercises/sum-of-multiples/.meta/version +1 -0
  102. data/tracks/kotlin/exercises/sum-of-multiples/src/test/kotlin/SumOfMultiplesTest.kt +7 -7
  103. data/tracks/kotlin/exercises/triangle/.meta/version +1 -0
  104. data/tracks/kotlin/exercises/two-fer/.meta/version +1 -0
  105. data/tracks/kotlin/exercises/two-fer/src/test/kotlin/TwoferTest.kt +0 -1
  106. data/tracks/kotlin/exercises/word-count/.meta/src/reference/kotlin/WordCount.kt +6 -2
  107. data/tracks/kotlin/exercises/word-count/.meta/version +1 -0
  108. data/tracks/kotlin/exercises/word-count/src/test/kotlin/WordCountTest.kt +31 -9
  109. data/tracks/kotlin/scripts/canonical_data_check.sh +8 -0
  110. data/tracks/perl6/exercises/leap/leap.t +2 -2
  111. data/tracks/php/config.json +16 -0
  112. data/tracks/php/exercises/crypto-square/crypto-square_test.php +50 -0
  113. data/tracks/php/exercises/crypto-square/example.php +32 -0
  114. data/tracks/php/exercises/meetup/README.md +21 -0
  115. data/tracks/php/exercises/meetup/example.php +19 -0
  116. data/tracks/php/exercises/meetup/meetup_test.php +577 -0
  117. data/tracks/python/README.md +7 -5
  118. data/tracks/python/config.json +36 -27
  119. data/tracks/python/docs/TESTS.md +36 -12
  120. data/tracks/python/exercises/complex-numbers/complex_numbers_test.py +1 -1
  121. data/tracks/python/exercises/diffie-hellman/.meta/hints.md +16 -0
  122. data/tracks/python/exercises/diffie-hellman/README.md +15 -2
  123. data/tracks/python/exercises/error-handling/README.md +23 -0
  124. data/tracks/python/exercises/error-handling/error_handling.py +14 -0
  125. data/tracks/python/exercises/error-handling/error_handling_test.py +66 -0
  126. data/tracks/python/exercises/error-handling/example.py +21 -0
  127. data/tracks/python/exercises/forth/forth_test.py +1 -1
  128. data/tracks/python/exercises/isogram/isogram_test.py +5 -3
  129. data/tracks/python/exercises/leap/leap_test.py +2 -2
  130. data/tracks/python/exercises/rotational-cipher/rotational_cipher_test.py +4 -4
  131. data/tracks/python/exercises/simple-cipher/.meta/hints.md +16 -0
  132. data/tracks/python/exercises/simple-cipher/README.md +17 -0
  133. data/tracks/python/exercises/sum-of-multiples/sum_of_multiples_test.py +4 -1
  134. data/tracks/python/exercises/twelve-days/example.py +3 -3
  135. data/tracks/python/exercises/twelve-days/twelve_days.py +2 -2
  136. metadata +53 -9
  137. data/tracks/kotlin/exercises/largest-series-product/src/test/kotlin/SeriesInvalidInputTest.kt +0 -30
  138. data/tracks/kotlin/exercises/largest-series-product/src/test/kotlin/SeriesValidInputTest.kt +0 -34
  139. data/tracks/kotlin/exercises/nucleotide-count/src/test/kotlin/NucleotideTest.kt +0 -87
@@ -1,11 +1,9 @@
1
1
  import org.junit.Test
2
2
  import org.junit.Ignore
3
3
  import kotlin.test.assertEquals
4
- import kotlin.test.fail
5
4
 
6
5
  class PrimeTest {
7
6
 
8
-
9
7
  @Test
10
8
  fun firstPrime() {
11
9
  assertEquals(2, Prime.nth(1))
@@ -1,9 +1,10 @@
1
- class DNA(strand: String) {
1
+ class Dna(strand: String) {
2
+
2
3
  init {
3
4
  require(strand.matches(Regex("^[$nucleotides]*$")), { "DNA sequence contains invalid nucleotides sequence." })
4
5
  }
5
6
 
6
- companion object DNA {
7
+ companion object Dna {
7
8
  val nucleotides = "ATCG"
8
9
  val emptyNucleotideCounts = nucleotides.map { it to 0 }.toMap()
9
10
  }
@@ -12,10 +13,4 @@ class DNA(strand: String) {
12
13
  emptyNucleotideCounts + strand.groupBy { it }.mapValues { it.value.size }
13
14
  }
14
15
 
15
- fun count(nucleotide: Char): Int {
16
- require(nucleotide in nucleotides, { "$nucleotide is not a nucleotide" })
17
-
18
- return nucleotideCounts[nucleotide] ?: 0
19
- }
20
16
  }
21
-
@@ -0,0 +1,48 @@
1
+ import org.junit.Test
2
+ import org.junit.Ignore
3
+ import kotlin.test.assertEquals
4
+
5
+ class DnaTest {
6
+
7
+ @Test
8
+ fun emptyDnaStringHasNoNucleotides() {
9
+ val dna = Dna("")
10
+ val expected = mapOf('A' to 0, 'C' to 0, 'G' to 0, 'T' to 0)
11
+
12
+ assertEquals(expected, dna.nucleotideCounts)
13
+ }
14
+
15
+ @Ignore
16
+ @Test
17
+ fun canCountOneNucleotideInSingleCharacterInput() {
18
+ val dna = Dna("G")
19
+ val expected = mapOf('A' to 0, 'C' to 0, 'G' to 1, 'T' to 0)
20
+
21
+ assertEquals(expected, dna.nucleotideCounts)
22
+ }
23
+
24
+ @Ignore
25
+ @Test
26
+ fun canCountRepeatedNucleotide() {
27
+ val dna = Dna("GGGGGGG")
28
+ val expected = mapOf('A' to 0, 'C' to 0, 'G' to 7, 'T' to 0)
29
+
30
+ assertEquals(expected, dna.nucleotideCounts)
31
+ }
32
+
33
+ @Ignore
34
+ @Test
35
+ fun canCountMultipleNucleotides() {
36
+ val dna = Dna("AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC")
37
+ val expected = mapOf('A' to 20, 'C' to 12, 'G' to 17, 'T' to 21)
38
+
39
+ assertEquals(expected, dna.nucleotideCounts)
40
+ }
41
+
42
+ @Ignore
43
+ @Test(expected = IllegalArgumentException::class)
44
+ fun validatesNucleotides() {
45
+ Dna("AGXXACT")
46
+ }
47
+
48
+ }
@@ -1,4 +1,4 @@
1
- object Pangrams {
1
+ object Pangram {
2
2
  val alphaLength = 26
3
3
  fun isPangram(input: String) = input.toLowerCase().replace(Regex("[^a-z]"), "").toSet().size == alphaLength
4
4
  }
@@ -1 +1 @@
1
- 1.1.0
1
+ 1.3.0
@@ -7,55 +7,61 @@ class PangramTest {
7
7
 
8
8
  @Test
9
9
  fun emptySentence() {
10
- assertFalse(Pangrams.isPangram(""))
10
+ assertFalse(Pangram.isPangram(""))
11
+ }
12
+
13
+ @Ignore
14
+ @Test
15
+ fun perfectLowercasePangram() {
16
+ assertTrue(Pangram.isPangram("abcdefghijklmnopqrstuvwxyz"))
11
17
  }
12
18
 
13
19
  @Ignore
14
20
  @Test
15
21
  fun lowercasePangram() {
16
- assertTrue(Pangrams.isPangram("the quick brown fox jumps over the lazy dog"))
22
+ assertTrue(Pangram.isPangram("the quick brown fox jumps over the lazy dog"))
17
23
  }
18
24
 
19
25
  @Ignore
20
26
  @Test
21
27
  fun missingCharacterX() {
22
- assertFalse(Pangrams.isPangram("a quick movement of the enemy will jeopardize five gunboats"))
28
+ assertFalse(Pangram.isPangram("a quick movement of the enemy will jeopardize five gunboats"))
23
29
  }
24
30
 
25
31
  @Ignore
26
32
  @Test
27
33
  fun anotherMissingCharacterX() {
28
- assertFalse(Pangrams.isPangram("the quick brown fish jumps over the lazy dog"))
34
+ assertFalse(Pangram.isPangram("five boxing wizards jump quickly at it"))
29
35
  }
30
36
 
31
37
  @Ignore
32
38
  @Test
33
39
  fun withUnderscores() {
34
- assertTrue(Pangrams.isPangram("the_quick_brown_fox_jumps_over_the_lazy_dog"))
40
+ assertTrue(Pangram.isPangram("the_quick_brown_fox_jumps_over_the_lazy_dog"))
35
41
  }
36
42
 
37
43
  @Ignore
38
44
  @Test
39
45
  fun withNumbers() {
40
- assertTrue(Pangrams.isPangram("the 1 quick brown fox jumps over the 2 lazy dogs"))
46
+ assertTrue(Pangram.isPangram("the 1 quick brown fox jumps over the 2 lazy dogs"))
41
47
  }
42
48
 
43
49
  @Ignore
44
50
  @Test
45
51
  fun missingLettersReplacedByNumbers() {
46
- assertFalse(Pangrams.isPangram("7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog"))
52
+ assertFalse(Pangram.isPangram("7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog"))
47
53
  }
48
54
 
49
55
  @Ignore
50
56
  @Test
51
57
  fun mixedCaseAndPunctuation() {
52
- assertTrue(Pangrams.isPangram("\"Five quacking Zephyrs jolt my wax bed.\""))
58
+ assertTrue(Pangram.isPangram("\"Five quacking Zephyrs jolt my wax bed.\""))
53
59
  }
54
60
 
55
61
  @Ignore
56
62
  @Test
57
63
  fun mixedCaseDuplicatedCharacters() {
58
- assertFalse(Pangrams.isPangram("the quick brown fox jumps over with lazy FX"))
64
+ assertFalse(Pangram.isPangram("the quick brown fox jumps over with lazy FX"))
59
65
  }
60
66
 
61
67
  }
@@ -4,40 +4,57 @@ import kotlin.test.assertEquals
4
4
 
5
5
  class PascalsTriangleTest {
6
6
 
7
+ @Test
8
+ fun zeroRows() {
9
+ val expectedOutput = emptyList<List<Int>>()
10
+
11
+ assertEquals(expectedOutput, PascalsTriangle.computeTriangle(0))
12
+ }
13
+
14
+ @Ignore
15
+ @Test
16
+ fun oneRow() {
17
+ val expectedOutput = listOf(
18
+ listOf(1)
19
+ )
7
20
 
21
+ assertEquals(expectedOutput, PascalsTriangle.computeTriangle(1))
22
+ }
23
+
24
+ @Ignore
8
25
  @Test
9
- fun triangleWithFourRows() {
26
+ fun twoRows() {
10
27
  val expectedOutput = listOf(
11
28
  listOf(1),
12
- listOf(1, 1),
13
- listOf(1, 2, 1),
14
- listOf(1, 3, 3, 1)
29
+ listOf(1, 1)
15
30
  )
16
31
 
17
- assertEquals(expectedOutput, PascalsTriangle.computeTriangle(4))
32
+ assertEquals(expectedOutput, PascalsTriangle.computeTriangle(2))
18
33
  }
19
34
 
20
35
  @Ignore
21
36
  @Test
22
- fun triangleWithSixRows() {
37
+ fun threeRows() {
23
38
  val expectedOutput = listOf(
24
39
  listOf(1),
25
40
  listOf(1, 1),
26
- listOf(1, 2, 1),
27
- listOf(1, 3, 3, 1),
28
- listOf(1, 4, 6, 4, 1),
29
- listOf(1, 5, 10, 10, 5, 1)
41
+ listOf(1, 2, 1)
30
42
  )
31
43
 
32
- assertEquals(expectedOutput, PascalsTriangle.computeTriangle(6))
44
+ assertEquals(expectedOutput, PascalsTriangle.computeTriangle(3))
33
45
  }
34
46
 
35
47
  @Ignore
36
48
  @Test
37
- fun expectEmptyTriangle() {
38
- val expectedOutput = emptyList<List<Int>>()
49
+ fun fourRows() {
50
+ val expectedOutput = listOf(
51
+ listOf(1),
52
+ listOf(1, 1),
53
+ listOf(1, 2, 1),
54
+ listOf(1, 3, 3, 1)
55
+ )
39
56
 
40
- assertEquals(expectedOutput, PascalsTriangle.computeTriangle(0))
57
+ assertEquals(expectedOutput, PascalsTriangle.computeTriangle(4))
41
58
  }
42
59
 
43
60
  @Ignore
@@ -45,4 +62,5 @@ class PascalsTriangleTest {
45
62
  fun validatesNotNegativeRows() {
46
63
  PascalsTriangle.computeTriangle(-1)
47
64
  }
65
+
48
66
  }
@@ -4,7 +4,7 @@ enum class Classification {
4
4
  }
5
5
 
6
6
  fun classify(naturalNumber: Int): Classification {
7
- require(naturalNumber >= 0, { "$naturalNumber is not a natural number" })
7
+ require(naturalNumber > 0, { "$naturalNumber is not a natural number" })
8
8
 
9
9
  val aliquotSum = naturalNumber.aliquotSum()
10
10
  return when {
@@ -31,7 +31,7 @@ class NaturalNumberTest {
31
31
  @Ignore
32
32
  @Test
33
33
  fun mediumAbundantNumberIsClassifiedCorrectly() {
34
- assertEquals(Classification.ABUNDANT, classify(24))
34
+ assertEquals(Classification.ABUNDANT, classify(30))
35
35
  }
36
36
 
37
37
  @Ignore
@@ -42,14 +42,20 @@ class NaturalNumberTest {
42
42
 
43
43
  @Ignore
44
44
  @Test
45
- fun smallDeficientNumberIsClassifiedCorrectly() {
46
- assertEquals(Classification.DEFICIENT, classify(8))
45
+ fun smallestPrimeDeficientNumberIsClassifiedCorrectly() {
46
+ assertEquals(Classification.DEFICIENT, classify(2))
47
+ }
48
+
49
+ @Ignore
50
+ @Test
51
+ fun smallestNonPrimeDeficientNumberIsClassifiedCorrectly() {
52
+ assertEquals(Classification.DEFICIENT, classify(4))
47
53
  }
48
54
 
49
55
  @Ignore
50
56
  @Test
51
57
  fun mediumNumberIsClassifiedCorrectly() {
52
- assertEquals(Classification.DEFICIENT, classify(31))
58
+ assertEquals(Classification.DEFICIENT, classify(32))
53
59
  }
54
60
 
55
61
  @Ignore
@@ -58,10 +64,22 @@ class NaturalNumberTest {
58
64
  assertEquals(Classification.DEFICIENT, classify(33550337))
59
65
  }
60
66
 
67
+ @Ignore
68
+ @Test
69
+ fun edgeCaseWithNoFactorsOtherThanItselfIsClassifiedCorrectly() {
70
+ assertEquals(Classification.DEFICIENT, classify(1))
71
+ }
72
+
73
+ @Ignore
74
+ @Test(expected = RuntimeException::class)
75
+ fun zeroIsNotANaturalNumber() {
76
+ classify(0)
77
+ }
78
+
61
79
  @Ignore
62
80
  @Test(expected = RuntimeException::class)
63
- fun mustProvideNaturalNumber() {
64
- assertEquals(Classification.DEFICIENT, classify(-1))
81
+ fun negativeNumberIsNotANaturalNumber() {
82
+ classify(-1)
65
83
  }
66
84
 
67
- }
85
+ }
@@ -1,13 +1,21 @@
1
1
  data class PhoneNumber(private val rawNumber: String) {
2
+
2
3
  companion object {
3
- private val validationRegex = Regex("^1?([2-9]\\d{2}[2-9]\\d{6})$")
4
+ private val invalidChars = Regex("[^\\d() -.]")
5
+ private val digitsValidationRegex = Regex("^1?([2-9]\\d{2}[2-9]\\d{6})$")
4
6
  }
5
- private val cleanedNumber = rawNumber.replace(Regex("[^\\d]"), "")
6
7
 
7
- val number = validationRegex.matchEntire(cleanedNumber)?.groupValues?.last() ?: throw IllegalArgumentException()
8
- val areaCode = number.substring(0, 3)
9
- val exchangeCode = number.substring(3, 6)
10
- val subscriberNumber = number.substring(6, 10)
8
+ val number: String?
9
+
10
+ init {
11
+ val containsInvalidChar = invalidChars.containsMatchIn(rawNumber)
12
+
13
+ if (containsInvalidChar) {
14
+ number = null
15
+ } else {
16
+ val digits = rawNumber.replace(Regex("[^\\d]"), "")
17
+ number = digitsValidationRegex.matchEntire(digits)?.groupValues?.last()
18
+ }
19
+ }
11
20
 
12
- override fun toString() = "($areaCode) $exchangeCode-$subscriberNumber"
13
21
  }
@@ -1,11 +1,10 @@
1
- import org.junit.Test
2
1
  import org.junit.Ignore
2
+ import org.junit.Test
3
3
  import kotlin.test.assertEquals
4
- import kotlin.test.fail
4
+ import kotlin.test.assertNull
5
5
 
6
6
  class PhoneNumberTest {
7
7
 
8
-
9
8
  @Test
10
9
  fun cleansNumber() {
11
10
  val expectedNumber = "2234567890"
@@ -25,62 +24,80 @@ class PhoneNumberTest {
25
24
 
26
25
  @Ignore
27
26
  @Test
28
- fun validWhen11DigitsAndFirstIs1() {
27
+ fun cleansNumberWithMultipleSpaces() {
29
28
  val expectedNumber = "2234567890"
30
- val actualNumber = PhoneNumber("12234567890").number
29
+ val actualNumber = PhoneNumber("223 456 7890 ").number
31
30
 
32
31
  assertEquals(expectedNumber, actualNumber)
33
32
  }
34
33
 
35
34
  @Ignore
36
- @Test(expected = IllegalArgumentException::class)
37
- fun invalidWhen10DigitsAndFirstIs1() {
38
- val actualNumber = PhoneNumber("1234567890")
35
+ @Test
36
+ fun invalidWhen9Digits() {
37
+ assertNull(PhoneNumber("123456789").number)
38
+ }
39
+
40
+ @Ignore
41
+ @Test
42
+ fun invalidWhen11DigitsAndFirstIsNot1() {
43
+ assertNull(PhoneNumber("22234567890").number)
44
+ }
45
+
46
+ @Ignore
47
+ @Test
48
+ fun validWhen11DigitsAndFirstIs1() {
49
+ val expectedNumber = "2234567890"
50
+ val actualNumber = PhoneNumber("12234567890").number
39
51
 
40
- fail("IllegalArgumentException should have been thrown")
52
+ assertEquals(expectedNumber, actualNumber)
41
53
  }
42
54
 
43
55
  @Ignore
44
- @Test(expected = IllegalArgumentException::class)
45
- fun invalidWhenOnly11Digits() {
46
- val actualNumber = PhoneNumber("21234567890")
56
+ @Test
57
+ fun validWhen11DigitsAndFirstIs1WithPunctuation() {
58
+ val expectedNumber = "2234567890"
59
+ val actualNumber = PhoneNumber("+1 (223) 456-7890").number
47
60
 
48
- fail("IllegalArgumentException should have been thrown")
61
+ assertEquals(expectedNumber, actualNumber)
49
62
  }
50
63
 
51
64
  @Ignore
52
- @Test(expected = IllegalArgumentException::class)
53
- fun invalidWhen9Digits() {
54
- val actualNumber = PhoneNumber("223456789")
65
+ @Test
66
+ fun invalidWhenMoreThan11Digits() {
67
+ val expectedNumber = null
68
+ val actualNumber = PhoneNumber("321234567890").number
55
69
 
56
- fail("IllegalArgumentException should have been thrown")
70
+ assertEquals(expectedNumber, actualNumber)
57
71
  }
58
72
 
59
73
  @Ignore
60
74
  @Test
61
- fun areaCode() {
62
- val expectedAreaCode = "223"
63
- val actualAreaCode = PhoneNumber("2234567890").areaCode
75
+ fun invalidWithLetters() {
76
+ val expectedNumber = null
77
+ val actualNumber = PhoneNumber("123-abc-7890").number
64
78
 
65
- assertEquals(expectedAreaCode, actualAreaCode)
79
+ assertEquals(expectedNumber, actualNumber)
66
80
  }
67
81
 
68
82
  @Ignore
69
83
  @Test
70
- fun toStringPrint() {
71
- val expectedtoStringNumber = "(223) 456-7890"
72
- val actualtoStringNumber = PhoneNumber("2234567890").toString()
84
+ fun invalidWithInvalidPunctuation() {
85
+ val expectedNumber = null
86
+ val actualNumber = PhoneNumber("123-@:!-7890").number
73
87
 
74
- assertEquals(expectedtoStringNumber, actualtoStringNumber)
88
+ assertEquals(expectedNumber, actualNumber)
75
89
  }
76
90
 
77
91
  @Ignore
78
92
  @Test
79
- fun toStringPrintWithFullUSPhoneNumber() {
80
- val expectedtoStringNumber = "(223) 456-7890"
81
- val actualtoStringNumber = PhoneNumber("12234567890").toString()
93
+ fun invalidWhenAreaCodeStartsWith0or1() {
94
+ assertNull(PhoneNumber("(123) 456-7890").number)
95
+ }
82
96
 
83
- assertEquals(expectedtoStringNumber, actualtoStringNumber)
97
+ @Ignore
98
+ @Test
99
+ fun invalidWhenExchangeCodeStartsWith0or1() {
100
+ assertNull(PhoneNumber("(223) 056-7890").number)
84
101
  }
85
102
 
86
103
  }