diff --git a/scala/build.sbt b/scala/build.sbt index d628c9f4..687c7de4 100644 --- a/scala/build.sbt +++ b/scala/build.sbt @@ -5,4 +5,4 @@ version := "1.0" scalaVersion := "2.13.1" resolvers += DefaultMavenRepository -libraryDependencies += "org.scalatest" %% "scalatest" % "3.1.1" % "test" +libraryDependencies += "org.scalatest" %% "scalatest" % "3.1.1" % Test diff --git a/scala/src/test/scala/com/gildedrose/GildedRoseTest.scala b/scala/src/test/scala/com/gildedrose/GildedRoseTest.scala index c0ce6b23..41dc98ec 100644 --- a/scala/src/test/scala/com/gildedrose/GildedRoseTest.scala +++ b/scala/src/test/scala/com/gildedrose/GildedRoseTest.scala @@ -1,13 +1,175 @@ package com.gildedrose -import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.BeforeAndAfter import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec -class GildedRoseTest extends AnyFlatSpec with Matchers { - it should "foo" in { - val items = Array[Item](new Item("foo", 0, 0)) - val app = new GildedRose(items) - app.updateQuality() - app.items(0).name should equal ("fixme") +class GildedRoseTest extends AnyWordSpec with Matchers with BeforeAndAfter { + + private var itemCreator: ItemCreator = _ + + private var app: GildedRose = _ + before { + itemCreator = new ItemCreator() + } + + "quality of item is never negative" in { + val sellIn = 10 + val quality = 1 + app = createApp(createItemsOfAllTypes(sellIn, quality)) + verifyQualityIsPositive(sellIn + 2) + } + + private def createItemsOfAllTypes(sellIn: Int, quality: Int) = { + Array[Item]( + itemCreator.backstagePassItem(sellIn, quality), + itemCreator.agedBrieItem(sellIn, quality), + itemCreator.dexterityItem(sellIn, quality), + itemCreator.elixirItem(sellIn, quality), + itemCreator.sulfurasItem() + ) + } + + private def verifyQualityIsPositive(sellIn: Int): Unit = { + for (i <- 1 to sellIn) { + app.updateQuality() + for (j <- app.items) + assert(j.quality >= 0) + } + } + + "quality is never more than 50 except for Sulfuras" in { + val sellIn = 10 + val quality = 48 + app = createApp(createItemsWithoutSulfuras(sellIn, quality)) + verifyQualityLessThanOrEqualTo50(sellIn + 2) + } + + private def createItemsWithoutSulfuras(sellIn: Int, quality: Int) = { + Array[Item]( + itemCreator.backstagePassItem(sellIn, quality), + itemCreator.agedBrieItem(sellIn, quality), + itemCreator.dexterityItem(sellIn, quality), + itemCreator.elixirItem(sellIn, quality), + ) + } + + private def verifyQualityLessThanOrEqualTo50(sellIn: Int): Unit = { + for (i <- 1 to sellIn) { + app.updateQuality() + for (j <- app.items) + assert(j.quality <= 50) + } + } + + "quality decreases twice as fast after sell date has passed" in { + val sellIn = 1 + val quality = 10 + app = createApp(createItemsOfDecreasingQuality(sellIn, quality)) + verifyQualityDroppedTwiceAsFast(quality) + } + + private def createItemsOfDecreasingQuality(sellIn: Int, quality: Int) = { + Array[Item]( + itemCreator.dexterityItem(sellIn, quality), + itemCreator.elixirItem(sellIn, quality), + ) + } + + private def verifyQualityDroppedTwiceAsFast(quality: Int): Unit = { + verifyQualityDecreasedByDiff(quality, 1) + verifyQualityDecreasedByDiff(quality, 3) + verifyQualityDecreasedByDiff(quality, 5) + } + + private def verifyQualityDecreasedByDiff(quality: Int, diff: Int): Unit = { + app.updateQuality() + for (i <- app.items) + assert(i.quality == quality - diff) + } + + "quality of Aged Brie increases with time and stays below 50" in { + app = createApp(createItemsWithOnlyAgedBrie()) + verifyQualityForAgedBrie() + } + + private def createItemsWithOnlyAgedBrie() = { + Array[Item](itemCreator.agedBrieItem(5, 48)) + } + + private def verifyQualityForAgedBrie(): Unit = { + var quality = app.items(0).quality + for (i <- 1 to 40) { + app.updateQuality() + assert(app.items(0).quality <= 50) + if (quality < 50) { + assert(app.items(0).quality > quality) + quality = app.items(0).quality } + } + } + + "sulfuras never has to be sold and quality stays at 80" in { + app = createApp(createItemsWithOnlySulfuras()) + val sellIn = app.items(0).sellIn + verifyQualityForSulfuras(sellIn) + } + + private def createItemsWithOnlySulfuras() = { + Array[Item](itemCreator.sulfurasItem()) + } + + private def verifyQualityForSulfuras(sellIn: Int): Unit = { + for (i <- 1 to sellIn) { + app.updateQuality() + verifyIfQualityAndSellInFixed(sellIn) + } + } + + private def verifyIfQualityAndSellInFixed(sellIn: Int): Unit = { + for (j <- app.items) { + assert(j.quality == 80) + assert(j.sellIn == sellIn) + } + } + + "quality for backstage passes" in { + val quality = 20 + app = createApp(createItemsWithOnlyBackstagePass(quality)) + verifyQualityForBackstagePasses(quality) + } + + private def createItemsWithOnlyBackstagePass(quality: Int) = { + Array[Item](itemCreator.backstagePassItem(10, quality)) + } + + private def verifyQualityForBackstagePasses(quality: Int) = { + verifyIfQualityDecreasedBy2WhenSellInBetween5and10(quality) + verifyIfQualityDecreasedBy3WhenSellInLessThan5(quality) + verifyIfQualityDroppedTo0() + } + + private def verifyIfQualityDecreasedBy2WhenSellInBetween5and10(quality: Int): Unit = { + for (i <- 1 to 5) { + app.updateQuality() + assert(app.items(0).quality == quality + 2 * i) + } + } + + private def verifyIfQualityDecreasedBy3WhenSellInLessThan5(quality: Int): Unit = { + for (i <- 1 to 5) { + app.updateQuality() + assert(app.items(0).quality == quality + 10 + 3 * i) + } + } + + private def verifyIfQualityDroppedTo0() = { + app.updateQuality() + assert(app.items(0).quality == 0) + } + + private def createApp(items: Array[Item]) = { + app = new GildedRose(items) + app + } } \ No newline at end of file diff --git a/scala/src/test/scala/com/gildedrose/ItemCreator.scala b/scala/src/test/scala/com/gildedrose/ItemCreator.scala new file mode 100644 index 00000000..5e434eb2 --- /dev/null +++ b/scala/src/test/scala/com/gildedrose/ItemCreator.scala @@ -0,0 +1,33 @@ +package com.gildedrose + +class ItemCreator { + + private def item(name: String, sellIn: Int, quality: Int): Item = { + new Item(name, sellIn, quality) + } + + def agedBrieItem(sellIn: Int, quality: Int): Item = { + item("Aged Brie", sellIn, quality) + } + + def sulfurasItem(): Item = { + item("Sulfuras, Hand of Ragnaros", 1, 80) + } + + def backstagePassItem(sellIn: Int, quality: Int): Item = { + item("Backstage passes to a TAFKAL80ETC concert", sellIn, quality) + } + + def elixirItem(sellIn: Int, quality: Int): Item = { + item("Elixir of the Mongoose", sellIn, quality) + } + + def dexterityItem(sellIn: Int, quality: Int): Item = { + item("+5 Dexterity Vest", sellIn, quality) + } + + def conjuredItem(sellIn: Int, quality: Int): Item = { + item("Conjured Mana Cake", sellIn, quality) + } + +}