diff --git a/.idea/php-test-framework.xml b/.idea/php-test-framework.xml new file mode 100644 index 0000000..e47438f --- /dev/null +++ b/.idea/php-test-framework.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/php.xml b/.idea/php.xml index f6159c8..f19075c 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -1,4 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/Bread.php b/src/Bread.php new file mode 100644 index 0000000..674db1e --- /dev/null +++ b/src/Bread.php @@ -0,0 +1,8 @@ +priceListCollection = $priceListCollection; + } + + public function priceFor(Good $good): Pound { - return new Pound(5); + return $this->priceListCollection->currentFor($good); } public function sellTo(Offer $offer): Pound { - return new Pound( - $offer->amount()->amount() * - $this->priceFor($offer->good())->amount() - ); + $cost = $this + ->priceFor($offer->good()) + ->mult($offer->amount()->amount()); + + $this->priceListCollection->moveFor($offer->good(), -$offer->amount()->amount()); + + return $cost; + } + + public function buyFrom(Offer $offer): Pound + { + $cost = $this + ->priceFor($offer->good()) + ->mult($offer->amount()->amount()); + + $this->priceListCollection->moveFor($offer->good(), $offer->amount()->amount()); + + return $cost; } } diff --git a/src/Milk.php b/src/Milk.php index 8689abe..33e7410 100644 --- a/src/Milk.php +++ b/src/Milk.php @@ -3,8 +3,4 @@ final class Milk extends Good { - public function isMilk(): bool - { - return true; - } } diff --git a/src/Pound.php b/src/Pound.php index 1be124e..c1fe52e 100644 --- a/src/Pound.php +++ b/src/Pound.php @@ -17,4 +17,9 @@ public function amount(): int { return $this->amount; } + + public function mult(int $multiplier): Pound + { + return new Pound($this->amount * $multiplier); + } } diff --git a/src/PriceList.php b/src/PriceList.php index 8a6a231..f98e330 100644 --- a/src/PriceList.php +++ b/src/PriceList.php @@ -30,4 +30,25 @@ public function current(): Pound { return $this->prices[$this->position]; } + + public function move(int $positions): Pound + { + $nextPosition = $this->position + $positions; + + if ($nextPosition >= count($this->prices)) { + $this->position = count($this->prices) - 1; + + return $this->current(); + } + + if ($nextPosition < 0) { + $this->position = 0; + + return $this->current(); + } + + $this->position = $nextPosition; + + return $this->current(); + } } diff --git a/src/PriceListBuilder.php b/src/PriceListBuilder.php index bc0da06..1bf3efe 100644 --- a/src/PriceListBuilder.php +++ b/src/PriceListBuilder.php @@ -15,7 +15,87 @@ public function milkPrices(): PriceList new Pound(7), new Pound(7), new Pound(8), - new Pound(8) + new Pound(8), ); } + + public function woolPrices(): PriceList + { + return PriceList::fromList( + new Pound(3), + new Pound(3), + new Pound(4), + new Pound(4), + new Pound(5), + new Pound(5), + new Pound(6), + new Pound(6), + new Pound(7), + new Pound(8), + ); + } + + public function grainPrices(): PriceList + { + return PriceList::fromList( + new Pound(3), + new Pound(3), + new Pound(4), + new Pound(5), + new Pound(6), + new Pound(6), + new Pound(7), + new Pound(7), + new Pound(8), + new Pound(8), + ); + } + + public function breadPrices(): PriceList + { + return PriceList::fromList( + new Pound(7), + new Pound(8), + new Pound(9), + new Pound(10), + new Pound(11), + new Pound(11), + new Pound(12), + new Pound(13), + new Pound(14), + new Pound(15), + ); + } + + public function cheesePrices(): PriceList + { + return PriceList::fromList( + new Pound(7), + new Pound(8), + new Pound(9), + new Pound(10), + new Pound(11), + new Pound(12), + new Pound(13), + new Pound(14), + new Pound(14), + new Pound(15), + ); + } + + public function whiskyPrices(): PriceList + { + return PriceList::fromList( + new Pound(7), + new Pound(8), + new Pound(9), + new Pound(10), + new Pound(11), + new Pound(12), + new Pound(13), + new Pound(14), + new Pound(15), + new Pound(16), + ); + } } diff --git a/src/PriceListCollection.php b/src/PriceListCollection.php new file mode 100644 index 0000000..c4e0707 --- /dev/null +++ b/src/PriceListCollection.php @@ -0,0 +1,44 @@ +priceLists = []; + } + + public function registerPriceListForGood(Good $good, PriceList $priceList): void + { + $this->priceLists[get_class($good)] = $priceList; + } + + public function currentFor(Good $good): Pound + { + $this->ensureGoodHasPriceList($good); + + return $this->priceLists[get_class($good)]->current(); + } + + public function moveFor(Good $good, int $positions): Pound + { + $this->ensureGoodHasPriceList($good); + + return $this->priceLists[get_class($good)]->move($positions); + } + + private function ensureGoodHasPriceList(Good $good): void + { + if (!isset($this->priceLists[get_class($good)])) { + throw new InvalidArgumentException(sprintf("Good: %s is unknown", get_class($good))); + } + } +} \ No newline at end of file diff --git a/src/Whisky.php b/src/Whisky.php new file mode 100644 index 0000000..fd67901 --- /dev/null +++ b/src/Whisky.php @@ -0,0 +1,8 @@ + '/Pound.php', 'clansofcaledonia\\pricelist' => '/PriceList.php', 'clansofcaledonia\\pricelistbuilder' => '/PriceListBuilder.php', - 'clansofcaledonia\\unit' => '/Unit.php' + 'clansofcaledonia\\unit' => '/Unit.php', + 'clansofcaledonia\\pricelistcollection' => '/PriceListCollection.php', + 'clansofcaledonia\\wool' => '/Wool.php' ); } $cn = strtolower($class); diff --git a/tests/GoodTest.php b/tests/GoodTest.php deleted file mode 100644 index f44ff47..0000000 --- a/tests/GoodTest.php +++ /dev/null @@ -1,18 +0,0 @@ -assertTrue($milk->isMilk()); - } -} diff --git a/tests/MarketTest.php b/tests/MarketTest.php index d01128e..22605b3 100644 --- a/tests/MarketTest.php +++ b/tests/MarketTest.php @@ -10,24 +10,41 @@ * @uses \ClansOfCaledonia\Good * @uses \ClansOfCaledonia\Offer * @uses \ClansOfCaledonia\Unit + * @uses \ClansOfCaledonia\PriceList + * @uses \ClansOfCaledonia\PriceListCollection + * @uses \ClansOfCaledonia\PriceListBuilder */ final class MarketTest extends TestCase { public function testMilkCosts5PoundsInitially(): void { - $market = new Market; + $milk = new Milk(); + $priceListBuilder = new PriceListBuilder(); + $milkPrices = $priceListBuilder->milkPrices(); - $this->assertEquals(new Pound(5), $market->priceFor(Good::milk())); + $priceListCollection = new PriceListCollection(); + $priceListCollection->registerPriceListForGood($milk, $milkPrices); + + $market = new Market($priceListCollection); + + $this->assertEquals(new Pound(5), $market->priceFor($milk)); } public function testMilkCanBeSoldToTheMarket(): Market { - $market = new Market; + $milk = new Milk(); + $priceListBuilder = new PriceListBuilder(); + $milkPrices = $priceListBuilder->milkPrices(); + + $priceListCollection = new PriceListCollection(); + $priceListCollection->registerPriceListForGood($milk, $milkPrices); + + $market = new Market($priceListCollection); $payment = $market->sellTo( new Offer( new Unit(2), - Good::milk() + $milk ) ); @@ -36,11 +53,45 @@ public function testMilkCanBeSoldToTheMarket(): Market return $market; } - /** - * @depends testMilkCanBeSoldToTheMarket - */ - public function testSellingMilkToTheMarketReducesMilkPrice(Market $market): void + public function testSellingMilkToTheMarketReducesMilkPrice(): void { - $this->assertEquals(new Pound(4), $market->priceFor(Good::milk())); + $milk = new Milk(); + $priceListBuilder = new PriceListBuilder(); + $milkPrices = $priceListBuilder->milkPrices(); + + $priceListCollection = new PriceListCollection(); + $priceListCollection->registerPriceListForGood($milk, $milkPrices); + + $market = new Market($priceListCollection); + + $offer = new Offer( + new Unit(3), + $milk + ); + + $market->sellTo($offer); + + $this->assertEquals(new Pound(3), $milkPrices->current()); + } + + public function testBuyingMilkFromTheMarketIncresesMilkPrice(): void + { + $milk = new Milk(); + $priceListBuilder = new PriceListBuilder(); + $milkPrices = $priceListBuilder->milkPrices(); + + $priceListCollection = new PriceListCollection(); + $priceListCollection->registerPriceListForGood($milk, $milkPrices); + + $market = new Market($priceListCollection); + + $offer = new Offer( + new Unit(3), + $milk + ); + + $market->buyFrom($offer); + + $this->assertEquals(new Pound(7), $milkPrices->current()); } } diff --git a/tests/OfferTest.php b/tests/OfferTest.php index 9c0e029..0810160 100644 --- a/tests/OfferTest.php +++ b/tests/OfferTest.php @@ -13,8 +13,15 @@ final class OfferTest extends TestCase { public function testHasAmount(): void { - $offer = new Offer(new Unit(1), Good::milk()); + $offer = new Offer(new Unit(1), new Milk()); $this->assertEquals(new Unit(1), $offer->amount()); } + + public function testHasGood(): void + { + $offer = new Offer(new Unit(1), new Milk()); + + $this->assertEquals(new Milk(), $offer->good()); + } } diff --git a/tests/PoundTest.php b/tests/PoundTest.php index 3d3ec6d..37b0425 100644 --- a/tests/PoundTest.php +++ b/tests/PoundTest.php @@ -16,4 +16,14 @@ public function testHasAmount(): void $this->assertSame($amount, $p->amount()); } + + public function testMultiply(): void + { + $amount = 100; + + $p = new Pound($amount); + $newPound = $p->mult(5); + + $this->assertSame(500, $newPound->amount()); + } } diff --git a/tests/PriceListBuilderTest.php b/tests/PriceListBuilderTest.php index 5df7e04..f69b689 100644 --- a/tests/PriceListBuilderTest.php +++ b/tests/PriceListBuilderTest.php @@ -19,4 +19,49 @@ public function testCanBuildMilkPriceList(): void $this->assertEquals(new Pound(5), $milkPrices->current()); } + + public function testCanBuildBreadPriceList(): void + { + $builder = new PriceListBuilder; + + $breadPrices = $builder->breadPrices(); + + $this->assertEquals(new Pound(10), $breadPrices->current()); + } + + public function testCanBuildWoolPriceList(): void + { + $builder = new PriceListBuilder; + + $woolPrices = $builder->woolPrices(); + + $this->assertEquals(new Pound(4), $woolPrices->current()); + } + + public function testCanBuildCheesePriceList(): void + { + $builder = new PriceListBuilder; + + $cheesePrices = $builder->cheesePrices(); + + $this->assertEquals(new Pound(10), $cheesePrices->current()); + } + + public function testCanBuildWhiskyPriceList(): void + { + $builder = new PriceListBuilder; + + $whiskyPrices = $builder->whiskyPrices(); + + $this->assertEquals(new Pound(10), $whiskyPrices->current()); + } + + public function testCanBuildGrainPriceList(): void + { + $builder = new PriceListBuilder; + + $grainPrices = $builder->grainPrices(); + + $this->assertEquals(new Pound(5), $grainPrices->current()); + } } diff --git a/tests/PriceListCollectionTest.php b/tests/PriceListCollectionTest.php new file mode 100644 index 0000000..4de6a0f --- /dev/null +++ b/tests/PriceListCollectionTest.php @@ -0,0 +1,55 @@ +milkPrices(); + $priceListCollection = new PriceListCollection(); + $priceListCollection->registerPriceListForGood(new Milk(), $milkPriceList); + + $this->assertEquals($milkPriceList->current(), $priceListCollection->currentFor($milk)); + } + + public function testMoveForGood(): void + { + $position = 3; + $milk = new Milk(); + $priceListBuilder = new PriceListBuilder; + $milkPriceList = $priceListBuilder->milkPrices(); + $priceListCollection = new PriceListCollection(); + $priceListCollection->registerPriceListForGood(new Milk(), $milkPriceList); + $priceListCollection->moveFor($milk, $position); + + $this->assertEquals($milkPriceList->current(), $priceListCollection->currentFor($milk)); + } + + public function testUnregisteredGood(): void + { + $this->expectException(InvalidArgumentException::class); + + $position = 3; + $wool = new Wool(); + $priceListBuilder = new PriceListBuilder; + $milkPriceList = $priceListBuilder->milkPrices(); + $priceListCollection = new PriceListCollection(); + $priceListCollection->registerPriceListForGood(new Milk(), $milkPriceList); + $priceListCollection->moveFor($wool, $position); + } +} \ No newline at end of file diff --git a/tests/PriceListTest.php b/tests/PriceListTest.php index aba7abb..93f5141 100644 --- a/tests/PriceListTest.php +++ b/tests/PriceListTest.php @@ -27,4 +27,40 @@ public function testHasInitialPrice(): void $this->assertEquals(new Pound(4), $prices->current()); } + + public function dataProviderForMovePostionUp(): array + { + return [ + [6, 2], + [4, 0], + [10, 6], + [10, 100], + [1, -100], + [2, -2], + [1, -4], + ]; + } + + /** + * @param int $expectedPound + * @param int $positionsToMove + * @dataProvider dataProviderForMovePostionUp + */ + public function testMovePostionUp(int $expectedPound, int $positionsToMove): void + { + $prices = PriceList::fromList( + new Pound(1), + new Pound(2), + new Pound(3), + new Pound(4), + new Pound(5), + new Pound(6), + new Pound(7), + new Pound(8), + new Pound(9), + new Pound(10) + ); + + $this->assertEquals(new Pound($expectedPound), $prices->move($positionsToMove)); + } }