alex-patterson-webdev /
domino-game
| 1 | <?php |
||||
| 2 | |||||
| 3 | declare(strict_types=1); |
||||
| 4 | |||||
| 5 | namespace ArpTest\DominoGame; |
||||
| 6 | |||||
| 7 | use Arp\DominoGame\DominoGame; |
||||
| 8 | use Arp\DominoGame\Exception\DominoGameException; |
||||
| 9 | use Arp\DominoGame\Value\DominoCollection; |
||||
| 10 | use Arp\DominoGame\Value\Player; |
||||
| 11 | use Arp\DominoGame\Value\PlayerCollection; |
||||
| 12 | use PHPUnit\Framework\MockObject\MockObject; |
||||
| 13 | use PHPUnit\Framework\TestCase; |
||||
| 14 | use Psr\Log\LoggerInterface; |
||||
| 15 | |||||
| 16 | /** |
||||
| 17 | * @author Alex Patterson <[email protected]> |
||||
| 18 | * @package ArpTest\DominoGame |
||||
| 19 | */ |
||||
| 20 | final class DominoGameTest extends TestCase |
||||
| 21 | { |
||||
| 22 | /** |
||||
| 23 | * @var PlayerCollection|MockObject |
||||
| 24 | */ |
||||
| 25 | private $players; |
||||
| 26 | |||||
| 27 | /** |
||||
| 28 | * @var LoggerInterface|MockObject |
||||
| 29 | */ |
||||
| 30 | private $logger; |
||||
| 31 | |||||
| 32 | /** |
||||
| 33 | * Prepare the test case dependencies |
||||
| 34 | */ |
||||
| 35 | public function setUp(): void |
||||
| 36 | { |
||||
| 37 | $this->players = $this->createMock(PlayerCollection::class); |
||||
| 38 | |||||
| 39 | $this->logger = $this->createMock(LoggerInterface::class); |
||||
| 40 | } |
||||
| 41 | |||||
| 42 | /** |
||||
| 43 | * Assert that if we provide a collection with an invalid number of players to the DominoGame class that a |
||||
| 44 | * DominoGameException will be thrown with the correct exception message. |
||||
| 45 | * |
||||
| 46 | * @param int $playerCount |
||||
| 47 | * |
||||
| 48 | * @covers \Arp\DominoGame\DominoGame::__construct |
||||
| 49 | * @covers \Arp\DominoGame\DominoGame::reset |
||||
| 50 | * |
||||
| 51 | * @dataProvider getInvalidPlayerCountWillThrowDominoGameExceptionData |
||||
| 52 | * |
||||
| 53 | * @throws DominoGameException |
||||
| 54 | */ |
||||
| 55 | public function testInvalidPlayerCountWillThrowDominoGameException(int $playerCount): void |
||||
| 56 | { |
||||
| 57 | $this->players->expects($this->once()) |
||||
| 58 | ->method('count') |
||||
| 59 | ->willReturn($playerCount); |
||||
| 60 | |||||
| 61 | $this->expectException(DominoGameException::class); |
||||
| 62 | $this->expectExceptionMessage( |
||||
| 63 | sprintf('There must be a minimum of 1 and a maximum of 4 players; %d provided', $playerCount) |
||||
| 64 | ); |
||||
| 65 | |||||
| 66 | new DominoGame($this->players, $this->logger, 6); |
||||
| 67 | } |
||||
| 68 | |||||
| 69 | /** |
||||
| 70 | * @return array |
||||
| 71 | */ |
||||
| 72 | public function getInvalidPlayerCountWillThrowDominoGameExceptionData(): array |
||||
| 73 | { |
||||
| 74 | return [ |
||||
| 75 | [0], |
||||
| 76 | [1], |
||||
| 77 | [5], |
||||
| 78 | [-12], |
||||
| 79 | [1000], |
||||
| 80 | ]; |
||||
| 81 | } |
||||
| 82 | |||||
| 83 | /** |
||||
| 84 | * Assert that the internal collection of dominoes (the deck) is correctly reset and a new one configured |
||||
| 85 | * when calling reset(). |
||||
| 86 | * |
||||
| 87 | * @param int $expectedCount |
||||
| 88 | * @param int $maxTileSize |
||||
| 89 | * |
||||
| 90 | * @covers \Arp\DominoGame\DominoGame::__construct |
||||
| 91 | * @covers \Arp\DominoGame\DominoGame::reset |
||||
| 92 | * @covers \Arp\DominoGame\DominoGame::createDominoCollection |
||||
| 93 | * |
||||
| 94 | * @dataProvider getPopulationOfNewBoneyardCollectionWithTheCorrectNumberOfDominoesData |
||||
| 95 | * |
||||
| 96 | * @throws DominoGameException |
||||
| 97 | */ |
||||
| 98 | public function testPopulationOfNewDeckCollectionWithTheCorrectNumberOfDominoes( |
||||
| 99 | int $expectedCount, |
||||
| 100 | int $maxTileSize |
||||
| 101 | ): void { |
||||
| 102 | $players = $this->createMockPlayersArray(2); |
||||
| 103 | $playersCollection = $this->createMockPlayersCollection($players); |
||||
| 104 | |||||
| 105 | foreach ($players as $player) { |
||||
| 106 | /** @var DominoCollection|MockObject $dominoCollection */ |
||||
| 107 | $dominoCollection = $this->createMock(DominoCollection::class); |
||||
| 108 | |||||
| 109 | $player->expects($this->once()) |
||||
| 110 | ->method('getHand') |
||||
| 111 | ->willReturn($dominoCollection); |
||||
| 112 | |||||
| 113 | $dominoCollection->expects($this->once()) |
||||
| 114 | ->method('removeElements') |
||||
| 115 | ->with(null); |
||||
| 116 | } |
||||
| 117 | |||||
| 118 | $game = new DominoGame($playersCollection, $this->logger, $maxTileSize); |
||||
| 119 | |||||
| 120 | $this->assertSame($expectedCount, $game->getDeck()->count()); |
||||
| 121 | } |
||||
| 122 | |||||
| 123 | /** |
||||
| 124 | * @return array |
||||
| 125 | */ |
||||
| 126 | public function getPopulationOfNewBoneyardCollectionWithTheCorrectNumberOfDominoesData(): array |
||||
| 127 | { |
||||
| 128 | return [ |
||||
| 129 | [28, 6], |
||||
| 130 | ]; |
||||
| 131 | } |
||||
| 132 | |||||
| 133 | /** |
||||
| 134 | * Assert that a $handSize less than 1 will result in a DominoGameException being thrown when calling deal(). |
||||
| 135 | * |
||||
| 136 | * @param int $handSize The hand size that should be tested. |
||||
| 137 | * |
||||
| 138 | * @covers \Arp\DominoGame\DominoGame::deal |
||||
| 139 | * @dataProvider getDealWillThrowDominoGameExceptionIfProvidedAHandSizeLessThanOneData |
||||
| 140 | * |
||||
| 141 | * @throws DominoGameException |
||||
| 142 | */ |
||||
| 143 | public function testDealWillThrowDominoGameExceptionIfProvidedAHandSizeLessThanOne(int $handSize): void |
||||
| 144 | { |
||||
| 145 | $players = $this->createMockPlayersArray(2); |
||||
| 146 | $playersCollection = $this->createMockPlayersCollection($players); |
||||
| 147 | |||||
| 148 | $game = new DominoGame($playersCollection, $this->logger, 6); |
||||
| 149 | |||||
| 150 | $this->expectException(DominoGameException::class); |
||||
| 151 | $this->expectExceptionMessage('Hand sizes must be a minimum of 1'); |
||||
| 152 | |||||
| 153 | $game->deal($handSize); |
||||
| 154 | } |
||||
| 155 | |||||
| 156 | /** |
||||
| 157 | * @return array |
||||
| 158 | */ |
||||
| 159 | public function getDealWillThrowDominoGameExceptionIfProvidedAHandSizeLessThanOneData(): array |
||||
| 160 | { |
||||
| 161 | return [ |
||||
| 162 | [0], |
||||
| 163 | [-1], |
||||
| 164 | [-100], |
||||
| 165 | [-1212], |
||||
| 166 | ]; |
||||
| 167 | } |
||||
| 168 | |||||
| 169 | /** |
||||
| 170 | * Assert that the deal method will throw a DominoGameException if the provided $handSize exceeds the maximum |
||||
| 171 | * number that is available |
||||
| 172 | * |
||||
| 173 | * @param int $handSize The invalid hand size to test |
||||
| 174 | * |
||||
| 175 | * @dataProvider getDealWillThrowDominoGameExceptionIfProvidedAHandSizeExceedsAvailableDeckSizeData |
||||
| 176 | * |
||||
| 177 | * @throws DominoGameException |
||||
| 178 | */ |
||||
| 179 | public function testDealWillThrowDominoGameExceptionIfProvidedAHandSizeExceedsAvailableDeckSize(int $handSize): void |
||||
| 180 | { |
||||
| 181 | $players = $this->createMockPlayersArray(2); |
||||
| 182 | $collection = $this->createMockPlayersCollection($players); |
||||
| 183 | |||||
| 184 | $game = new DominoGame($collection, $this->logger, 6); |
||||
| 185 | |||||
| 186 | $expectedDeckCount = 28; |
||||
| 187 | |||||
| 188 | $this->expectException(DominoGameException::class); |
||||
| 189 | $this->expectExceptionMessage( |
||||
| 190 | sprintf( |
||||
| 191 | 'The hand size %d exceeds the maximum permissible for current deck size of %d', |
||||
| 192 | $handSize, |
||||
| 193 | $expectedDeckCount |
||||
| 194 | ) |
||||
| 195 | ); |
||||
| 196 | |||||
| 197 | $game->deal($handSize); |
||||
| 198 | } |
||||
| 199 | |||||
| 200 | /** |
||||
| 201 | * @return array |
||||
| 202 | */ |
||||
| 203 | public function getDealWillThrowDominoGameExceptionIfProvidedAHandSizeExceedsAvailableDeckSizeData(): array |
||||
| 204 | { |
||||
| 205 | return [ |
||||
| 206 | [28], |
||||
| 207 | [100], |
||||
| 208 | ]; |
||||
| 209 | } |
||||
| 210 | |||||
| 211 | /** |
||||
| 212 | * Assert that when providing a varied $playerCount we are able to correct deal the number of expected |
||||
| 213 | * dominoes to each one |
||||
| 214 | * |
||||
| 215 | * @covers \Arp\DominoGame\DominoGame::deal |
||||
| 216 | * |
||||
| 217 | * @param int $playerCount The number of players to test |
||||
| 218 | * |
||||
| 219 | * @dataProvider getDealingProvidesTheCorrectNumberOfDominoesToEachPlayerData |
||||
| 220 | * |
||||
| 221 | * @throws DominoGameException |
||||
| 222 | */ |
||||
| 223 | public function testDealingProvidesTheCorrectNumberOfDominoesToEachPlayer(int $playerCount): void |
||||
| 224 | { |
||||
| 225 | $deckSize = 28; |
||||
| 226 | $handSize = 7; |
||||
| 227 | |||||
| 228 | $players = []; |
||||
| 229 | for ($x = 0; $x < $playerCount; $x++) { |
||||
| 230 | $players[] = new Player('Player ' . $x); |
||||
| 231 | } |
||||
| 232 | |||||
| 233 | $game = new DominoGame(new PlayerCollection($players), $this->logger, 6); |
||||
| 234 | |||||
| 235 | $game->deal($handSize); |
||||
| 236 | |||||
| 237 | $deckResult = $game->getDeck(); |
||||
| 238 | $playersResult = $game->getPlayers(); |
||||
| 239 | |||||
| 240 | $expectedDeckCount = $deckSize - ($playerCount * $handSize); |
||||
| 241 | |||||
| 242 | $this->assertSame($expectedDeckCount, $deckResult->count()); |
||||
| 243 | |||||
| 244 | /** @var Player $player */ |
||||
| 245 | foreach ($playersResult as $player) { |
||||
| 246 | $this->assertSame(7, $player->getHandCount()); |
||||
| 247 | } |
||||
| 248 | } |
||||
| 249 | |||||
| 250 | /** |
||||
| 251 | * @return array |
||||
| 252 | */ |
||||
| 253 | public function getDealingProvidesTheCorrectNumberOfDominoesToEachPlayerData(): array |
||||
| 254 | { |
||||
| 255 | return [ |
||||
| 256 | [2], |
||||
| 257 | [3], |
||||
| 258 | [4], |
||||
| 259 | ]; |
||||
| 260 | } |
||||
| 261 | |||||
| 262 | /** |
||||
| 263 | * Create an array of player mock objects. |
||||
| 264 | * |
||||
| 265 | * @param int $numberOfPlayers |
||||
| 266 | * |
||||
| 267 | * @return Player[]|MockObject[] |
||||
| 268 | */ |
||||
| 269 | private function createMockPlayersArray(int $numberOfPlayers): array |
||||
| 270 | { |
||||
| 271 | /** @var Player[]|MockObject $players */ |
||||
| 272 | $players = []; |
||||
| 273 | for ($x = 0; $x < $numberOfPlayers; $x++) { |
||||
| 274 | $players[] = $this->createMock(Player::class); |
||||
| 275 | } |
||||
| 276 | return $players; |
||||
|
0 ignored issues
–
show
Bug
Best Practice
introduced
by
Loading history...
|
|||||
| 277 | } |
||||
| 278 | |||||
| 279 | /** |
||||
| 280 | * Create a new player collection mock object with iterable players. |
||||
| 281 | * |
||||
| 282 | * @param array|iterable $players |
||||
| 283 | * |
||||
| 284 | * @return PlayerCollection|MockObject |
||||
| 285 | */ |
||||
| 286 | private function createMockPlayersCollection(iterable $players = []): object |
||||
| 287 | { |
||||
| 288 | /** @var PlayerCollection|MockObject $collection */ |
||||
| 289 | $collection = $this->createMock(PlayerCollection::class); |
||||
| 290 | |||||
| 291 | $collection->method('getIterator')->willReturn(new \ArrayIterator($players)); |
||||
|
0 ignored issues
–
show
It seems like
$players can also be of type iterable; however, parameter $array of ArrayIterator::__construct() does only seem to accept array, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 292 | $collection->method('count')->willReturn(count($players)); |
||||
| 293 | |||||
| 294 | return $collection; |
||||
| 295 | } |
||||
| 296 | } |
||||
| 297 |