Test Failed
Push — main ( 99efcd...df6632 )
by Alex
14:53
created

GameTest   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 269
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 116
c 2
b 0
f 0
dl 0
loc 269
rs 10
wmc 16
1
<?php
2
3
namespace App\Tests\Adventure;
4
5
use App\Adventure\Game;
6
use App\Adventure\Location;
7
use App\Adventure\Inventory;
8
use App\Adventure\Item;
9
use App\Adventure\InputActions\InputActionInterface;
10
use PHPUnit\Framework\TestCase;
11
12
/**
13
 * Unit tests for Game class.
14
 */
15
class GameTest extends TestCase
16
{
17
    /**
18
     * @var Game
19
     */
20
    private $game;
21
22
    protected function setUp(): void
23
    {
24
        $this->game = new Game();
25
    }
26
27
    /**
28
     * Test case for setCurrentLocation and getCurrentLocation methods.
29
     */
30
    public function testSetAndGetCurrentLocation(): void
31
    {
32
        $location = $this->createStub(Location::class);
33
        $this->game->setCurrentLocation($location);
34
        $this->assertSame($location, $this->game->getCurrentLocation());
35
    }
36
37
    /**
38
     * Test case for setInventory and getInventory methods.
39
     */
40
    public function testSetAndGetInventory(): void
41
    {
42
        $inventory = $this->createStub(Inventory::class);
43
        $this->game->setInventory($inventory);
44
        $this->assertSame($inventory, $this->game->getInventory());
45
    }
46
47
    /**
48
     * Test case for procesAction method with invalid action.
49
     */
50
    public function testProcessActionWithInvalidAction(): void
51
    {
52
        $response = $this->game->processAction('invalid', 'target');
53
        $this->assertSame(
54
            "That action is not recognized. Try using the 'help' action for assistance.",
55
            $response
56
        );
57
    }
58
59
    /**
60
     * Test case for processAction method with input action 'where'.
61
     */
62
    public function testProcessActionWhere(): void
63
    {
64
        // Create and configure location mock
65
        $location = $this->createMock(Location::class);
66
        $location
67
            ->method('getLocationDetails')
68
            ->willReturn('This is a test location');
69
        $this->game->setCurrentLocation($location);
70
71
        // Assert 'where' action returns the current location's description
72
        $response = $this->game->processAction('where', '');
73
        $this->assertStringContainsString("This is a test location", $response);
74
    }
75
76
    /**
77
     * Test case for processAction method with input action 'inventory', no items.
78
     */
79
    public function testProcessActionInventoryEmpty(): void
80
    {
81
        // Configure mock to return an empty inventory
82
        $inventory = $this->createMock(Inventory::class);
83
        $inventory
84
            ->method('lookInInventory')
85
            ->willReturn([]);
86
        $this->game->setInventory($inventory);
87
88
        // Assert correct message is returned
89
        $response = $this->game->processAction('inventory', '');
90
        $this->assertSame("You look in your inventory:\n(empty)", $response);
91
    }
92
93
    /**
94
     * Test case for processAction method with input action 'inventory', with items.
95
     */
96
    public function testProcessActionInventoryWithItems(): void
97
    {
98
        $inventory = $this->createMock(Inventory::class);
99
        $inventory
100
            ->method('lookInInventory')
101
            ->willReturn(['Sword', 'Shield']);
102
        $this->game->setInventory($inventory);
103
104
        // Asssert message contains both items' names
105
        $response = $this->game->processAction('inventory', '');
106
        $expected = "You look in your inventory:\nSword\nShield";
107
        $this->assertSame($expected, $response);
108
    }
109
110
    /**
111
     * Test case for processAction method with input action 'help'.
112
     */
113
    public function testProcessActionHelp(): void
114
    {
115
        $response = $this->game->processAction('help', '');
116
117
        // Assert the response contains information about all available actions
118
        $this->assertStringContainsString('where', $response);
119
        $this->assertStringContainsString('inventory', $response);
120
        $this->assertStringContainsString('help', $response);
121
        $this->assertStringContainsString('go', $response);
122
        $this->assertStringContainsString('examine', $response);
123
        $this->assertStringContainsString('take', $response);
124
        $this->assertStringContainsString('use', $response);
125
    }
126
127
    /**
128
     * Test case for processAction with input action 'help', with target.
129
     * @dataProvider helpWithTargetProvider
130
     */
131
    public function testProcessActionHelpWithTarget(string $target, string $expected): void
132
    {
133
        $response = $this->game->processAction('help', $target);
134
        $this->assertStringContainsString($expected, $response);
135
    }
136
137
    /**
138
     * Provides target actions for help and their expected outputs.
139
     * As the exact message might change, simply expect the output will contain the name of the target action.
140
     *
141
     * @return array<int, array<int, string>> The inputs and expected outputs.
142
     */
143
    public function helpWithTargetProvider(): array
144
    {
145
        return [
146
            ['where', 'where'],
147
            ['inventory', 'inventory'],
148
            ['help', 'help'],
149
            ['go', 'go'],
150
            ['examine', 'examine'],
151
            ['take', 'take'],
152
            ['use', 'use'],
153
            ['invalid', 'The invalid action is not recognized'], // Not likely to change
154
        ];
155
    }
156
157
    /**
158
     * Test case for processAction with input action 'go' in valid direction.
159
     */
160
    public function testProcessActionGoValidDirection(): void
161
    {
162
        // Create and configure mock locations
163
        $location1 = $this->createMock(Location::class);
164
        $location2 = $this->createMock(Location::class);
165
        $location1
166
            ->method('hasConnection')
167
            ->with('north')
168
            ->willReturn(true);
169
        $location1
170
            ->method('getConnectedLocation')
171
            ->with('north')
172
            ->willReturn($location2);
173
        $location2
174
            ->method('getLocationDetails')
175
            ->willReturn('This is the second test location.');
176
        $this->game->setCurrentLocation($location1);
177
178
        // Assert message contains the second location's details,
179
        // also make sure location actually changes
180
        $response = $this->game->processAction('go', 'north');
181
        $this->assertStringContainsString('This is the second test location.', $response);
182
        $this->assertSame($location2, $this->game->getCurrentLocation());
183
    }
184
185
    /**
186
     * Test case for processAction with input action 'go' with invalid direction.
187
     */
188
    public function testProcessActionGoInvalidDirection(): void
189
    {
190
        // Create and configure mock location
191
        $location = $this->createMock(Location::class);
192
        $location
193
            ->method('hasConnection')
194
            ->with('north')
195
            ->willReturn(false);
196
        $this->game->setCurrentLocation($location);
197
198
        // Assert error mesage is returned, also make sure location doesn't change
199
        $response = $this->game->processAction('go', 'north');
200
        $this->assertSame('You cannot go that way.', $response);
201
        $this->assertSame($location, $this->game->getCurrentLocation());
202
    }
203
204
    /**
205
     * Provides item related actions.
206
     *
207
     * @return array<int, array<int, string>> The inputs.
208
     */
209
    public function itemActionProvider(): array
210
    {
211
        return [['examine'], ['take'], ['use']];
212
    }
213
214
    /**
215
     * Test case for processAction method with no target.
216
     * @dataProvider itemActionProvider
217
     */
218
    public function testProcessItemActionEmptyTarget(string $action): void
219
    {
220
        // Assert error message is returned
221
        $response = $this->game->processAction($action, '');
222
        $this->assertSame("You must specify a target to {$action}.", $response);
223
    }
224
225
    /**
226
     * Test case for processAction method with item not found.
227
     * @dataProvider itemActionProvider
228
     */
229
    public function testProcessItemActionItemNotFound(string $action): void
230
    {
231
        // Configure location and inventory mocks to NOT find the item
232
        $location = $this->createMock(Location::class);
233
        $location
234
            ->expects($this->once())
235
            ->method('hasItem')
236
            ->willReturn(false);
237
238
        $inventory = $this->createMock(Inventory::class);
239
        $inventory
240
            ->expects($this->once())
241
            ->method('hasItem')
242
            ->willReturn(false);
243
244
        $target = 'key';
245
        $this->game->setCurrentLocation($location);
246
        $this->game->setInventory($inventory);
247
248
        // Assert error message is returned
249
        $response = $this->game->processAction($action, $target);
250
        $this->assertSame("There is no {$target} to {$action}.", $response);
251
    }
252
253
    /**
254
     * Test case for processAction method with item with no action object.
255
     * @dataProvider itemActionProvider
256
     */
257
    public function testProcessItemActionNoActionObject(string $action): void
258
    {
259
        // Create and configure item mock
260
        $item = $this->createMock(Item::class);
261
        $item
262
            ->method('hasAction')
263
            ->with($action)
264
            ->willReturn(false); // No action object
265
266
        // Configure location mock to find the item
267
        $location = $this->createMock(Location::class);
268
        $location
269
            ->expects($this->once())
270
            ->method('hasItem')
271
            ->willReturn(true);
272
273
        $location
274
            ->expects($this->once())
275
            ->method('getItem')
276
            ->willReturn($item);
277
278
        $target = 'key';
279
        $this->game->setCurrentLocation($location);
280
281
        // Assert error message is returned
282
        $response = $this->game->processAction($action, $target);
283
        $this->assertSame("You cannot {$action} the {$target}.", $response);
284
    }
285
}
286