diff --git a/php/fixtures/texttest_fixture.php b/php/fixtures/texttest_fixture.php index 7363c773..98f1bd9f 100644 --- a/php/fixtures/texttest_fixture.php +++ b/php/fixtures/texttest_fixture.php @@ -6,6 +6,7 @@ require_once __DIR__ . '/../vendor/autoload.php'; use GildedRose\GildedRose; use GildedRose\Item; +use GildedRose\StrategyResolver; echo 'OMGHAI!' . PHP_EOL; @@ -22,7 +23,7 @@ $items = [ new Item('Conjured Mana Cake', 3, 6), ]; -$app = new GildedRose($items); +$app = new GildedRose($items, new StrategyResolver()); $days = 2; if (count($argv) > 1) { diff --git a/php/src/GildedRose.php b/php/src/GildedRose.php index cfb7f78a..21a29d9a 100644 --- a/php/src/GildedRose.php +++ b/php/src/GildedRose.php @@ -11,59 +11,25 @@ final class GildedRose */ private $items; - public function __construct(array $items) + /** + * @var StrategyResolverInterface + */ + private $strategyResolver; + + public function __construct(array $items, StrategyResolverInterface $strategyResolver) { $this->items = $items; + $this->strategyResolver = $strategyResolver; } public function updateQuality(): void { foreach ($this->items as $item) { - if ($item->name != 'Aged Brie' and $item->name != 'Backstage passes to a TAFKAL80ETC concert') { - if ($item->quality > 0) { - if ($item->name != 'Sulfuras, Hand of Ragnaros') { - $item->quality = $item->quality - 1; - } - } - } else { - if ($item->quality < 50) { - $item->quality = $item->quality + 1; - if ($item->name == 'Backstage passes to a TAFKAL80ETC concert') { - if ($item->sell_in < 11) { - if ($item->quality < 50) { - $item->quality = $item->quality + 1; - } - } - if ($item->sell_in < 6) { - if ($item->quality < 50) { - $item->quality = $item->quality + 1; - } - } - } - } - } + $sellInStrategy = $this->strategyResolver->getSellInStrategy($item); + $sellInStrategy->updateSellIn($item); - if ($item->name != 'Sulfuras, Hand of Ragnaros') { - $item->sell_in = $item->sell_in - 1; - } - - if ($item->sell_in < 0) { - if ($item->name != 'Aged Brie') { - if ($item->name != 'Backstage passes to a TAFKAL80ETC concert') { - if ($item->quality > 0) { - if ($item->name != 'Sulfuras, Hand of Ragnaros') { - $item->quality = $item->quality - 1; - } - } - } else { - $item->quality = $item->quality - $item->quality; - } - } else { - if ($item->quality < 50) { - $item->quality = $item->quality + 1; - } - } - } + $qualityStrategy = $this->strategyResolver->getQualityStrategy($item); + $qualityStrategy->updateQuality($item); } } } diff --git a/php/src/QualityStrategy/AgedBrieQualityStrategy.php b/php/src/QualityStrategy/AgedBrieQualityStrategy.php new file mode 100644 index 00000000..c38932cb --- /dev/null +++ b/php/src/QualityStrategy/AgedBrieQualityStrategy.php @@ -0,0 +1,11 @@ +sell_in <= self::SELL_IN_LAST_5_DAYS) { + $decreasingSpeed = self::DECREASING_SPEED_AT_LAST_5_DAYS; + } elseif ($item->sell_in <= self::SELL_IN_LAST_10_DAYS) { + $decreasingSpeed = self::DECREASING_SPEED_AT_LAST_10_DAYS; + } + + return $decreasingSpeed; + } + + protected function setMinAndMaxQuality(Item $item): Item + { + if ($item->sell_in < 0) { + $item->quality = 0; + + return $item; + } + + return parent::setMinAndMaxQuality($item); + } +} diff --git a/php/src/QualityStrategy/BasicQualityStrategy.php b/php/src/QualityStrategy/BasicQualityStrategy.php new file mode 100644 index 00000000..2ff8da75 --- /dev/null +++ b/php/src/QualityStrategy/BasicQualityStrategy.php @@ -0,0 +1,54 @@ +decreasingSpeed = $decreasingSpeed; + } + + public function updateQuality(Item $item): Item + { + $item = $this->setInitialQuality($item); + + $decreasingSpeed = $this->getCurrentDecreasingSpeed($item); + + $item->quality -= $decreasingSpeed; + + return $this->setFinalQuality($item); + } + + protected function getCurrentDecreasingSpeed(Item $item): int + { + return $item->sell_in >= 0 + ? $this->decreasingSpeed + : $this->decreasingSpeed * 2; + } + + protected function setInitialQuality(Item $item): Item + { + return $this->setMinAndMaxQuality($item); + } + + protected function setFinalQuality(Item $item): Item + { + return $this->setMinAndMaxQuality($item); + } + + protected function setMinAndMaxQuality(Item $item): Item + { + $item->quality = $item->quality > 0 ? $item->quality : 0; + $item->quality = $item->quality < self::QUALITY_MAX_LEVEL ? $item->quality : self::QUALITY_MAX_LEVEL; + + return $item; + } +} diff --git a/php/src/QualityStrategy/ConjuredQualityStrategy.php b/php/src/QualityStrategy/ConjuredQualityStrategy.php new file mode 100644 index 00000000..265cf8fb --- /dev/null +++ b/php/src/QualityStrategy/ConjuredQualityStrategy.php @@ -0,0 +1,11 @@ +sell_in--; + + return $item; + } +} diff --git a/php/src/SellInStrategy/SellInStrategyInterface.php b/php/src/SellInStrategy/SellInStrategyInterface.php new file mode 100644 index 00000000..bdfe1a68 --- /dev/null +++ b/php/src/SellInStrategy/SellInStrategyInterface.php @@ -0,0 +1,10 @@ +name) { + case self::ITEM_NAME_SULFURAS: + return new SulfurasSellInStrategy(); + default: + break; + } + + return new BasicSellInStrategy(); + } + + public function getQualityStrategy(Item $item): QualityStrategyInterface + { + switch ($item->name) { + case self::ITEM_NAME_AGED_BRIE: + return new AgedBrieQualityStrategy(); + case self::ITEM_NAME_SULFURAS: + return new SulfurasQualityStrategy(); + case self::ITEM_NAME_BACKSTAGE_PASSES: + return new BackstagePassesQualityStrategy(); + case self::ITEM_NAME_CONJURED: + return new ConjuredQualityStrategy(); + default: + break; + } + + return new BasicQualityStrategy(); + } +} diff --git a/php/src/StrategyResolverInterface.php b/php/src/StrategyResolverInterface.php new file mode 100644 index 00000000..09b36c5b --- /dev/null +++ b/php/src/StrategyResolverInterface.php @@ -0,0 +1,21 @@ +initializeGlidedRose($items); + + $gildedRose->updateQuality(); + + $this->assertSameItems($expectedItems, $items); + } + + public function sellInAndQualityIsCorrectAfterUpdatedQualityDataProvider(): array + { + return [ + 'si: 0->-1, qty decrease x2: 10->12' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 0, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, -1, 12), + + ], + ], + 'si: 1->0, qty: 10->11' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 1, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 0, 11), + + ], + ], + 'si: 10->9, min qty: -100->1' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 10, -100), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 9, 1), + + ], + ], + 'si: -10->-11, max qty: 49->50' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, -10, 49), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, -11, 50), + + ], + ], + 'si: 1->0, max qty: 50->50' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 1, 50), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 0, 50), + + ], + ], + 'si: 10->9, max qty: 105->50' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 10, 105), + ], + 'expected' +=> [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 9, 50), + +], + ], + ]; + } + + /** + * @group AgedBrie + * @dataProvider sellInAndQualityIsCorrectAfterUpdatedQualityThreeTimesDataProvider + * + * @param Item[] $items + * @param Item[] $expectedItems + */ + public function testSellInAndQualityIsCorrectAfterUpdatedQualityThreeTimes( + array $items, + array $expectedItems + ): void { + $gildedRose = $this->initializeGlidedRose($items); + + $gildedRose->updateQuality(); + $gildedRose->updateQuality(); + $gildedRose->updateQuality(); + + $this->assertSameItems($expectedItems, $items); + } + + public function sellInAndQualityIsCorrectAfterUpdatedQualityThreeTimesDataProvider(): array + { + return [ + 'si: 0->-3, qty decrease x2: 10->16' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 0, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, -3, 16), + + ], + ], + 'si: 1->-2, qty: 10->15' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 1, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, -2, 15), + + ], + ], + 'si: 10->7, min qty: -100->3' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 10, -100), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 7, 3), + + ], + ], + 'si: -10->-13, max qty: 45->50' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, -10, 45), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, -13, 50), + + ], + ], + 'si: 1->-2, max qty: 50->50' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 1, 50), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, -2, 50), + + ], + ], + 'si: 10->7, max qty: 105->50' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 10, 105), + ], + 'expected' +=> [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 7, 50), + +], + ], + ]; + } +} diff --git a/php/tests/GildedRose/BackstagePassesItemTest.php b/php/tests/GildedRose/BackstagePassesItemTest.php new file mode 100644 index 00000000..5e785a02 --- /dev/null +++ b/php/tests/GildedRose/BackstagePassesItemTest.php @@ -0,0 +1,197 @@ +initializeGlidedRose($items); + + $gildedRose->updateQuality(); + + $this->assertSameItems($expectedItems, $items); + } + + public function sellInAndQualityIsCorrectAfterUpdatedQualityDataProvider(): array + { + return [ + 'si: 100->99, qty: 10->11' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 100, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 99, 11), + + ], + ], + 'si: 10->9, qty increase +2: 10->12' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 10, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 9, 12), + + ], + ], + 'si: 5->4, qty increase +3: 10->13' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 5, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 4, 13), + + ], + ], + 'si: 10->9, min qty: -100->2' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 10, -100), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 9, 2), + + ], + ], + 'concert is finished, si: 0->-1, min qty: 100->0' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 0, 100), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, -1, 0), + + ], + ], + 'si: 1->0, max qty: 50->50' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 1, 50), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 0, 50), + + ], + ], + 'si: 10->9, max qty: 105->50' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 10, 105), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 9, 50), + + ], + ], + ]; + } + + /** + * @group BackstagePasses + * @dataProvider sellInAndQualityIsCorrectAfterUpdatedQualityThreeTimesDataProvider + * + * @param Item[] $items + * @param Item[] $expectedItems + */ + public function testSellInAndQualityIsCorrectAfterUpdatedQualityThreeTimes( + array $items, + array $expectedItems + ): void { + $gildedRose = $this->initializeGlidedRose($items); + + $gildedRose->updateQuality(); + $gildedRose->updateQuality(); + $gildedRose->updateQuality(); + + $this->assertSameItems($expectedItems, $items); + } + + public function sellInAndQualityIsCorrectAfterUpdatedQualityThreeTimesDataProvider(): array + { + return [ + 'si: 100->97, qty: 10->13' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 100, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 97, 13), + + ], + ], + 'si: 10->7, qty increase +2: 10->16' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 10, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 7, 16), + + ], + ], + 'si: 5->2, qty increase +3: 10->19' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 5, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 2, 19), + + ], + ], + 'si: 7->4, qty increase +2 and +3: 10->18' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 7, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 4, 18), + + ], + ], + 'si: 10->7, min qty: -100->6' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 10, -100), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 7, 6), + + ], + ], + 'concert is finished, si: 2->-1, min qty: 100->0' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 2, 100), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, -1, 0), + + ], + ], + 'si: 3->0, max qty: 50->50' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 3, 50), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 0, 50), + + ], + ], + 'si: 10->7, max qty: 105->50' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 10, 105), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 7, 50), + + ], + ], + ]; + } +} diff --git a/php/tests/GildedRose/ConjuredItemTest.php b/php/tests/GildedRose/ConjuredItemTest.php new file mode 100644 index 00000000..9c7f694e --- /dev/null +++ b/php/tests/GildedRose/ConjuredItemTest.php @@ -0,0 +1,181 @@ +initializeGlidedRose($items); + + $gildedRose->updateQuality(); + + $this->assertSameItems($expectedItems, $items); + } + + public function sellInAndQualityIsCorrectAfterUpdatedQualityDataProvider(): array + { + return [ + 'si: 0->-1, qty decrease x4: 10->8' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 0, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, -1, 6), + + ], + ], + 'si: 1->0, qty decrease x2: 10->9' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 1, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 0, 8), + + ], + ], + 'si: 10->9, min qty: 0->0' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 10, 0), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 9, 0), + + ], + ], + 'si: -10->-11, min qty: 3->0' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, -10, 3), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, -11, 0), + + ], + ], + 'si: 10->9, min qty: -50->0' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 10, -50), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 9, 0), + + ], + ], + 'si: 10->9, max qty: 105->48' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 10, 105), + ], + 'expected' +=> [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 9, 48), + +], + ], + ]; + } + + /** + * @skip + * @group ConjuredItem + * @dataProvider sellInAndQualityIsCorrectAfterUpdatedQualityThreeTimesDataProvider + * + * @param Item[] $items + * @param Item[] $expectedItems + */ + public function testSellInAndQualityIsCorrectAfterUpdatedQualityThreeTimes( + array $items, + array $expectedItems + ): void { + $gildedRose = $this->initializeGlidedRose($items); + + $gildedRose->updateQuality(); + $gildedRose->updateQuality(); + $gildedRose->updateQuality(); + + $this->assertSameItems($expectedItems, $items); + } + + public function sellInAndQualityIsCorrectAfterUpdatedQualityThreeTimesDataProvider(): array + { + return [ + 'si: 0->-3, qty decrease x4: 20->8' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 0, 20), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, -3, 8), + + ], + ], + 'si: 3->0, qty decrease x2: 10->4' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 3, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 0, 4), + + ], + ], + 'si: 1->-2, qty decrease x2 and x4: 20->10' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 1, 20), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, -2, 10), + + ], + ], + 'si: 10->7, min qty: 0->0' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 10, 0), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 7, 0), + + ], + ], + 'si: -10->-13, qty: 11->0' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, -10, 11), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, -13, 0), + + ], + ], + 'si: 10->7, min qty: -50->0' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 10, -50), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 7, 0), + + ], + ], + 'si: 10->7, max qty: 105->44' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 10, 105), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 7, 44), + + ], + ], + ]; + } +} diff --git a/php/tests/GildedRose/FooItemTest.php b/php/tests/GildedRose/FooItemTest.php new file mode 100644 index 00000000..8f9fddc7 --- /dev/null +++ b/php/tests/GildedRose/FooItemTest.php @@ -0,0 +1,169 @@ +initializeGlidedRose($items); + + $gildedRose->updateQuality(); + + $this->assertSameItems($expectedItems, $items); + } + + public function sellInAndQualityIsCorrectAfterUpdatedQualityDataProvider(): array + { + return [ + 'si: 0->-1, qty decrease x2: 10->8' => [ + 'items' => [ + 'foo' => new Item('foo', 0, 10), + ], + 'expected' => [ + 'foo' => new Item('foo', -1, 8), + + ], + ], + 'si: 1->0, qty: 10->9' => [ + 'items' => [ + 'foo' => new Item('foo', 1, 10), + ], + 'expected' => [ + 'foo' => new Item('foo', 0, 9), + + ], + ], + 'si: 10->9, min qty: 0->0' => [ + 'items' => [ + 'foo' => new Item('foo', 10, 0), + ], + 'expected' => [ + 'foo' => new Item('foo', 9, 0), + + ], + ], + 'si: -10->-11, qty: 1->0' => [ + 'items' => [ + 'foo' => new Item('foo', -10, 1), + ], + 'expected' => [ + 'foo' => new Item('foo', -11, 0), + + ], + ], + 'si: 10->9, min qty: -50->0' => [ + 'items' => [ + 'foo' => new Item('foo', 10, -50), + ], + 'expected' => [ + 'foo' => new Item('foo', 9, 0), + + ], + ], + 'si: 10->9, max qty: 105->49' => [ + 'items' => [ + 'foo' => new Item('foo', 10, 105), + ], + 'expected' => [ + 'foo' => new Item('foo', 9, 49), + + ], + ], + ]; + } + + /** + * @group FooItem + * @dataProvider sellInAndQualityIsCorrectAfterUpdatedQualityThreeTimesDataProvider + * + * @param Item[] $items + * @param Item[] $expectedItems + */ + public function testSellInAndQualityIsCorrectAfterUpdatedQualityThreeTimes( + array $items, + array $expectedItems + ): void { + $gildedRose = $this->initializeGlidedRose($items); + + $gildedRose->updateQuality(); + $gildedRose->updateQuality(); + $gildedRose->updateQuality(); + + $this->assertSameItems($expectedItems, $items); + } + + public function sellInAndQualityIsCorrectAfterUpdatedQualityThreeTimesDataProvider(): array + { + return [ + 'si: 0->-3, qty decrease x2: 10->4' => [ + 'items' => [ + 'foo' => new Item('foo', 0, 10), + ], + 'expected' => [ + 'foo' => new Item('foo', -3, 4), + + ], + ], + 'si: 3->0, qty: 10->7' => [ + 'items' => [ + 'foo' => new Item('foo', 3, 10), + ], + 'expected' => [ + 'foo' => new Item('foo', 0, 7), + + ], + ], + 'si: 1->-2, qty decrease x1 and x2: 10->5' => [ + 'items' => [ + 'foo' => new Item('foo', 1, 10), + ], + 'expected' => [ + 'foo' => new Item('foo', -2, 5), + + ], + ], + 'si: 10->7, min qty: 0->0' => [ + 'items' => [ + 'foo' => new Item('foo', 10, 0), + ], + 'expected' => [ + 'foo' => new Item('foo', 7, 0), + + ], + ], + 'si: -10->-13, qty: 1->0' => [ + 'items' => [ + 'foo' => new Item('foo', -10, 1), + ], + 'expected' => [ + 'foo' => new Item('foo', -13, 0), + + ], + ], + 'si: 10->7, max qty: 105->47' => [ + 'items' => [ + 'foo' => new Item('foo', 10, 105), + ], + 'expected' => [ + 'foo' => new Item('foo', 7, 47), + + ], + ], + ]; + } +} diff --git a/php/tests/GildedRose/SulfurasItemTest.php b/php/tests/GildedRose/SulfurasItemTest.php new file mode 100644 index 00000000..34252257 --- /dev/null +++ b/php/tests/GildedRose/SulfurasItemTest.php @@ -0,0 +1,116 @@ +initializeGlidedRose($items); + + $gildedRose->updateQuality(); + + $this->assertSameItems($expectedItems, $items); + } + + public function sellInAndQualityIsCorrectAfterUpdatedQualityDataProvider(): array + { + return [ + 'sell-in const: -1->-1, qty const: 10->10' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, -1, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, -1, 10), + + ], + ], + 'sell-in const: 0->0, min qty: -100->-100' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, 0, -100), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, 0, -100), + + ], + ], + 'sell-in const: 1->1, max qty: 105->105' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, 1, 105), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, 1, 105), + + ], + ], + ]; + } + + /** + * @group Sulfuras + * @dataProvider sellInAndQualityIsCorrectAfterUpdatedQualityThreeTimesDataProvider + * + * @param Item[] $items + * @param Item[] $expectedItems + */ + public function testSellInAndQualityIsCorrectAfterUpdatedQualityThreeTimes( + array $items, + array $expectedItems + ): void { + $gildedRose = $this->initializeGlidedRose($items); + + $gildedRose->updateQuality(); + $gildedRose->updateQuality(); + $gildedRose->updateQuality(); + + $this->assertSameItems($expectedItems, $items); + } + + public function sellInAndQualityIsCorrectAfterUpdatedQualityThreeTimesDataProvider(): array + { + return [ + 'sell-in const: -1->-1, qty const: 10->10' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, -1, 10), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, -1, 10), + + ], + ], + 'sell-in const: 0->0, min qty: -100->-100' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, 0, -100), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, 0, -100), + + ], + ], + 'sell-in const: 1->1, max qty: 105->105' => [ + 'items' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, 1, 105), + ], + 'expected' => [ + 'foo' => new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, 1, 105), + + ], + ], + ]; + } +} diff --git a/php/tests/GildedRoseTest.php b/php/tests/GildedRoseTest.php index 52e7ddc6..4979afa8 100644 --- a/php/tests/GildedRoseTest.php +++ b/php/tests/GildedRoseTest.php @@ -4,17 +4,92 @@ declare(strict_types=1); namespace Tests; -use GildedRose\GildedRose; use GildedRose\Item; -use PHPUnit\Framework\TestCase; +use GildedRose\StrategyResolverInterface; class GildedRoseTest extends TestCase { - public function testFoo(): void + /** + * @group GildedRose + */ + public function testFooItemNameIsTheSameAfterUpdatedQuality(): void { $items = [new Item('foo', 0, 0)]; - $gildedRose = new GildedRose($items); + $gildedRose = $this->initializeGlidedRose($items); + $gildedRose->updateQuality(); - $this->assertSame('fixme', $items[0]->name); + + $this->assertSame('foo', $items[0]->name); + } + + /** + * @group GildedRose + */ + public function testDifferentMultiItemsDataIsCorrectAfterUpdatedQuality(): void + { + $items = [ + new Item('another foo', 1, 10), + new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 0, 10), + new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, 777, 777), + new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 5, 10), + new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 1, 10), + ]; + $gildedRose = $this->initializeGlidedRose($items); + + $gildedRose->updateQuality(); + + $this->assertSameItem(new Item('another foo', 0, 9), $items[0]); + $this->assertSameItem(new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, -1, 12), $items[1]); + $this->assertSameItem(new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, 777, 777), $items[2]); + $this->assertSameItem(new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 4, 13), $items[3]); + $this->assertSameItem(new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 0, 8), $items[4]); + } + + /** + * @group GildedRose + */ + public function testSameMultiItemsDataIsCorrectAfterUpdatedQuality(): void + { + $items = [ + new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 0, 10), + new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 1, 10), + new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 5, 10), + new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 10, 10), + new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 100, 10), + ]; + $gildedRose = $this->initializeGlidedRose($items); + + $gildedRose->updateQuality(); + + $this->assertSameItem(new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, -1, 0), $items[0]); + $this->assertSameItem(new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 0, 13), $items[1]); + $this->assertSameItem(new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 4, 13), $items[2]); + $this->assertSameItem(new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 9, 12), $items[3]); + $this->assertSameItem(new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 99, 11), $items[4]); + } + + /** + * @group GildedRose + */ + public function testDifferentMultiItemsDataIsCorrectAfterUpdatedQualityThirtyTimes(): void + { + $items = [ + new Item('another super foo', 20, 60), + new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, 20, 0), + new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, 777, 777), + new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 31, 0), + new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, 28, 777), + ]; + $gildedRose = $this->initializeGlidedRose($items); + + for ($i = 0; $i < 30; $i++) { + $gildedRose->updateQuality(); + } + + $this->assertSameItem(new Item('another super foo', -10, 10), $items[0]); + $this->assertSameItem(new Item(StrategyResolverInterface::ITEM_NAME_AGED_BRIE, -10, 40), $items[1]); + $this->assertSameItem(new Item(StrategyResolverInterface::ITEM_NAME_SULFURAS, 777, 777), $items[2]); + $this->assertSameItem(new Item(StrategyResolverInterface::ITEM_NAME_BACKSTAGE_PASSES, 1, 45), $items[3]); + $this->assertSameItem(new Item(StrategyResolverInterface::ITEM_NAME_CONJURED, -2, 0), $items[4]); } } diff --git a/php/tests/ItemTest.php b/php/tests/ItemTest.php new file mode 100644 index 00000000..e0ade306 --- /dev/null +++ b/php/tests/ItemTest.php @@ -0,0 +1,33 @@ +assertSame('foo', $item->name); + $this->assertSame(1, $item->sell_in); + $this->assertSame(2, $item->quality); + } + + /** + * @group Item + */ + public function testItemToStringIsCorrect(): void + { + $item = new Item('foo', 1, 2); + + $this->assertSame('foo, 1, 2', (string) $item); + } +} diff --git a/php/tests/TestCase.php b/php/tests/TestCase.php new file mode 100644 index 00000000..25bc5a40 --- /dev/null +++ b/php/tests/TestCase.php @@ -0,0 +1,41 @@ +name; + + $this->assertSame($expected->name, $actual->name, sprintf('Item\'s "name" is not equal to expected; expected: %s, actual: %s', $expected->name, $actual->name)); + $this->assertSame($expected->sell_in, $actual->sell_in, sprintf('Item\'s "sell in" is not equal to expected; expected: %d, actual: %d, key: %s', $expected->sell_in, $actual->sell_in, $actualKey)); + $this->assertSame($expected->quality, $actual->quality, sprintf('Item\'s "quality" is not equal to expected; expected: %d, actual: %d, key: %s', $expected->quality, $actual->quality, $actualKey)); + } + + /** + * @param Item[] $expected + * @param Item[] $actual + */ + public function assertSameItems(array $expected, array $actual): void + { + foreach ($actual as $key => $actualItem) { + $this->assertSameItem($expected[$key], $actualItem, $key); + } + } + + /** + * @param Item[] $items + */ + protected function initializeGlidedRose(array $items): GildedRose + { + return new GildedRose($items, new StrategyResolver()); + } +} diff --git a/texttests/config.gr b/texttests/config.gr index 7183e174..e61c4a07 100755 --- a/texttests/config.gr +++ b/texttests/config.gr @@ -1,8 +1,8 @@ full_name:Gilded Rose Refactoring Kata # set your preferred editor and diff tool. -view_program:subl -diff_program:meld +view_program:nano +diff_program:diff # Settings for the Python version #executable:${TEXTTEST_HOME}/python/texttest_fixture.py @@ -31,4 +31,8 @@ diff_program:meld #executable:${TEXTTEST_HOME}/TypeScript/test/golden-master-text-test.js #interpreter:node +# Settings for the PHP version +executable:${TEXTTEST_HOME}/php/texttest_fixture.php +interpreter:php + filename_convention_scheme:standard