forked from exercism/kotlin
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Changes to Luhn tests and sample implementation. Fixes exercism#24
- Loading branch information
Showing
2 changed files
with
58 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,29 @@ | ||
data class Luhn(val number: Long) { | ||
object Luhn { | ||
|
||
val checkDigit: Int by lazy { checkDigit(number) } | ||
fun isValid(candidate: String): Boolean = | ||
isValidCandidate(candidate) && checksum(number(candidate)) == 0 | ||
|
||
val addends: List<Int> by lazy { | ||
digits(number).withIndex().reversed() | ||
.map { if (isOdd(it.index)) dbl(it.value) else it.value } | ||
} | ||
private fun isValidCandidate(candidate: String): Boolean = | ||
candidate.filter(Char::isDigit).length > 1 && | ||
candidate.all { it.isDigit() || Character.isSpaceChar(it) } | ||
|
||
val checksum: Int by lazy { addends.sum() } | ||
private fun number(candidate: String) = candidate.filter(Char::isDigit).toLong() | ||
|
||
val isValid: Boolean by lazy { checksum % 10 == 0 } | ||
private fun checksum(number: Long) = addends(number).sum() % 10 | ||
|
||
val create: Long by lazy { | ||
val zeroCheckDigitNumber = number * 10 | ||
val luhn = Luhn(zeroCheckDigitNumber) | ||
private fun addends(number: Long): List<Int> = digits(number).withIndex().reversed() | ||
.map { if (isOdd(it.index)) dbl(it.value) else it.value } | ||
|
||
if (luhn.isValid) zeroCheckDigitNumber else zeroCheckDigitNumber + (10 - luhn.checksum % 10) | ||
private fun digits(n: Long): List<Int> = when (n) { | ||
0L -> emptyList() | ||
else -> listOf((n % 10).toInt()) + digits(n / 10) | ||
} | ||
|
||
companion object { | ||
private fun checkDigit(n: Long) = (n % 10).toInt() | ||
|
||
private fun digits(n: Long): List<Int> = when (n) { | ||
0L -> emptyList() | ||
else -> listOf(checkDigit(n)) + digits(n / 10) | ||
} | ||
|
||
private fun dbl(n: Int): Int { | ||
val dbled = n * 2 | ||
return if (dbled > 10) dbled - 9 else dbled | ||
} | ||
|
||
private fun isOdd(i: Int) = i % 2 == 1 | ||
private fun dbl(n: Int): Int { | ||
val dbled = n * 2 | ||
return if (dbled > 9) dbled - 9 else dbled | ||
} | ||
|
||
private fun isOdd(i: Int) = i % 2 == 1 | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,86 +1,88 @@ | ||
import org.junit.Test | ||
import org.junit.Ignore | ||
import kotlin.test.assertEquals | ||
import kotlin.test.assertFalse | ||
import kotlin.test.assertTrue | ||
|
||
class LuhnTest { | ||
|
||
|
||
@Test | ||
fun checkDigitIsRightMostDigit() { | ||
val expectedOutput = 7 | ||
|
||
assertEquals(expectedOutput, Luhn(34567).checkDigit) | ||
fun singleDigitStringsCannotBeValid() { | ||
assertFalse(Luhn.isValid("1")) | ||
} | ||
|
||
@Ignore | ||
@Test | ||
fun addendsDoublesEveryOtherNumberFromRight() { | ||
val expectedOutput = listOf(1, 4, 1, 4, 1) | ||
|
||
assertEquals(expectedOutput, Luhn(12121).addends) | ||
fun singleZeroIsInvalid() { | ||
assertFalse(Luhn.isValid("0")) | ||
} | ||
|
||
@Ignore | ||
@Test | ||
fun addendsSubtracts9WhenDoubledNumberIsMoreThan9() { | ||
val expectedOutput = listOf(7, 6, 6, 1) | ||
|
||
assertEquals(expectedOutput, Luhn(8631).addends) | ||
fun simpleValidSINThatRemainsValidIfReversed() { | ||
assertTrue(Luhn.isValid("059")) | ||
assertTrue(Luhn.isValid("950")) | ||
} | ||
|
||
@Ignore | ||
@Test | ||
fun checkSumAddsAddendsTogether1() { | ||
val expectedOutput = 22 | ||
|
||
assertEquals(expectedOutput, Luhn(4913).checksum) | ||
fun simpleValidSINThatBecomesInvalidIfReversed() { | ||
assertTrue(Luhn.isValid("59")) | ||
assertFalse(Luhn.isValid("95")) | ||
} | ||
|
||
@Ignore | ||
@Test | ||
fun checkSumAddsAddendsTogether2() { | ||
val expectedOutput = 21 | ||
|
||
assertEquals(expectedOutput, Luhn(201773).checksum) | ||
fun validCanadianSIN() { | ||
assertTrue(Luhn.isValid("055 444 285")) | ||
} | ||
|
||
@Ignore | ||
@Test | ||
fun numberIsValidWhenChecksumMod10IsZero1() { | ||
val expectedOutput = false | ||
|
||
assertEquals(expectedOutput, Luhn(738).isValid) | ||
fun invalidCanadianSIN() { | ||
assertFalse(Luhn.isValid("055 444 286")) | ||
} | ||
|
||
@Ignore | ||
@Test | ||
fun numberIsValidWhenChecksumMod10IsZero2() { | ||
val expectedOutput = true | ||
|
||
assertEquals(expectedOutput, Luhn(8739567).isValid) | ||
fun invalidCreditCard() { | ||
assertFalse(Luhn.isValid("8273 1232 7352 0569")) | ||
} | ||
|
||
@Ignore | ||
@Test | ||
fun luhnCanCreateSimpleNumbersWithValidCheckDigit() { | ||
val expectedOutput = 1230L | ||
fun validStringsWithNonDigitIncludedBecomeInvalid() { | ||
assertFalse(Luhn.isValid("055a 444 285")) | ||
} | ||
|
||
assertEquals(expectedOutput, Luhn(123).create) | ||
@Ignore | ||
@Test | ||
fun validStringsWithPunctuationIncludedBecomeInvalid() { | ||
assertFalse(Luhn.isValid("055-444-285")) | ||
} | ||
|
||
@Ignore | ||
@Test | ||
fun luhnCanCreateLargeNumbersWithValidCheckDigit() { | ||
val expectedOutput = 8739567L | ||
fun validStringsWithSymbolsIncludedBecomeInvalid() { | ||
assertFalse(Luhn.isValid("055£ 444$ 285")) | ||
} | ||
|
||
assertEquals(expectedOutput, Luhn(873956).create) | ||
@Ignore | ||
@Test | ||
fun singleZeroWithSpaceIsInvalid() { | ||
assertFalse(Luhn.isValid(" 0")) | ||
} | ||
|
||
@Ignore | ||
@Test | ||
fun luhnCanCreateHugeNumbersWithValidCheckDigit() { | ||
val expectedOutput = 8372637564L | ||
fun moreThanSingleZeroIsValid() { | ||
assertTrue(Luhn.isValid("0000 0")) | ||
} | ||
|
||
assertEquals(expectedOutput, Luhn(837263756).create) | ||
@Ignore | ||
@Test | ||
fun inputDigit9IsCorrectlyConvertedToOutputDigit9() { | ||
assertTrue(Luhn.isValid("091")) | ||
} | ||
|
||
} |