Created
April 2, 2023 14:28
-
-
Save rkie/62aa1c894d25b8189aa8f01356945ae6 to your computer and use it in GitHub Desktop.
Used to demonstrate test driven refactoring in https://failedtofunction.com/test-driven-refactoring/
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
package com.failedtofunction.examples.numerals | |
class RomanNumeral { | |
private val value: Int | |
private val representation: String | |
private constructor(value: Int, representation: String) { | |
this.value = value | |
this.representation = representation | |
} | |
fun toInt(): Int = value | |
override fun toString(): String = representation | |
inline operator fun plus(another: RomanNumeral): RomanNumeral = fromInt(toInt() + another.toInt()) | |
override fun equals(other: Any?): Boolean { | |
return if (other is RomanNumeral) { | |
value == other.value | |
} else { | |
false | |
} | |
} | |
override fun hashCode(): Int { | |
return value.hashCode() | |
} | |
companion object { | |
private val descendingMap: Map<String, Int> = listOf( | |
"M" to 1000, "CM" to 900, "D" to 500, "CD" to 400, | |
"C" to 100, "XC" to 90, "L" to 50, "XL" to 40, | |
"X" to 10, "IX" to 9, "V" to 5, "IV" to 4, "I" to 1 | |
).toMap() | |
private fun toRomanNumeral(value: Int): String { | |
var num = value | |
var result = "" | |
for ((numeral, value) in descendingMap.entries) { | |
while (num >= value) { | |
num -= value | |
result += numeral | |
} | |
} | |
return result | |
} | |
fun fromString(rep: String): RomanNumeral { | |
val value = rep | |
.toCharArray() | |
.reversed() | |
.map { descendingMap[it.toString()]!! } | |
.fold(Pair(0, 0)) { state, item -> | |
val maxVal = kotlin.math.max(state.first, item) | |
val runningTotal = if (item >= state.first) { | |
state.second + item | |
} else { | |
state.second - item | |
} | |
Pair(maxVal, runningTotal) | |
}.second | |
return RomanNumeral(value, rep) | |
} | |
fun fromInt(value: Int): RomanNumeral = RomanNumeral(value, toRomanNumeral(value)) | |
} | |
} |
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
package com.failedtofunction.examples.numerals | |
import kotlin.test.Test | |
import kotlin.test.assertEquals | |
class RomanNumeralTest { | |
@Test | |
fun `should add two Roman Numerals together showing the result as a Roman Numeral`() { | |
val four = RomanNumeral.fromString("IV") | |
val eleven = RomanNumeral.fromString("XI") | |
val expected = RomanNumeral.fromString("XV") | |
val result = four + eleven | |
assertEquals(expected, result) | |
} | |
@Test | |
fun `should be able to access the Int value of a Roman Numeral created from the String representation`() { | |
val input = RomanNumeral.fromString("IV") | |
val expected = 4 | |
val result = input.toInt() | |
assertEquals(expected, result) | |
} | |
@Test | |
fun `should show the Roman Numeral representation when calling toString()`() { | |
val input = RomanNumeral.fromInt(4) | |
val expected = "IV" | |
val result = input.toString() | |
assertEquals(expected, result) | |
} | |
@Test | |
fun `should verify that equivalent Roman Numerals created from Int and String are equal`() { | |
val input = 4 | |
val expected = RomanNumeral.fromString("IV") | |
val result = RomanNumeral.fromInt(input) | |
assertEquals(expected, result) | |
} | |
@Test | |
fun `should verify that Roman numbers with equivalent values created from either Int or String have the same hash`() { | |
val first = RomanNumeral.fromString("XX") | |
val second = RomanNumeral.fromInt(20) | |
assertEquals(first.hashCode(), second.hashCode()) | |
} | |
@Test | |
fun `should convert integers from 1 to 1000 to Roman Numerals and back`() { | |
for (i in 1..1000) { | |
val asRomanNumeral = RomanNumeral.fromInt(i) | |
val asInteger = RomanNumeral.fromString(asRomanNumeral.toString()) | |
assertEquals(i, asInteger.toInt(), "Incorrect conversion of $i either to Roman Numeral $asRomanNumeral or back to $asInteger") | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment