GuzzleContext::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * Behat Guzzle Extension
4
 *
5
 * PHP version 5
6
 *
7
 * @package Behat\GuzzleExtension
8
 * @author  Dave Nash <[email protected]>
9
 * @license http://opensource.org/licenses/MIT The MIT License
10
 * @version GIT: $Id$
11
 * @link    https://github.com/teaandcode/behat-guzzle-extension GuzzleExtension
12
 */
13
14
namespace Behat\GuzzleExtension\Context;
15
16
use Behat\Gherkin\Node\PyStringNode;
17
use Behat\Gherkin\Node\TableNode;
18
use Guzzle\Http\Exception\ClientErrorResponseException;
19
20
/**
21
 * Guzzle context for Behat BDD tool
22
 * Provides raw Guzzle integration and base step definitions
23
 *
24
 * @package Behat\GuzzleExtension\Context
25
 * @author  Dave Nash <[email protected]>
26
 * @license http://opensource.org/licenses/MIT The MIT License
27
 * @version Release: @package_version@
28
 * @link    https://github.com/teaandcode/behat-guzzle-extension GuzzleExtension
29
 */
30
class GuzzleContext extends RawGuzzleContext
31
{
32
    /**
33
     * @var array
34
     *
35
     * @access protected
36
     */
37
    protected $storedResult;
38
39
    /**
40
     * @var array
41
     *
42
     * @access protected
43
     */
44
    protected $users;
45
46 16
    public function __construct(array $users = array())
47
    {
48 16
        $this->users = $users;
49 16
    }
50
51
    /**
52
     * Calls specified command
53
     *
54
     * Example: Given I authenticated as "bruce.wayne"
55
     * Example: When I authenticate as "bruce.wayne"
56
     *
57
     * @param string $user Key from users array to identify user
58
     *
59
     * @Given /^I authenticated as "(\S+)"$/
60
     * @When /^I authenticate as "(\S+)"$/
61
     */
62 2
    public function iAuthenticateAs($user)
63
    {
64 2
        if (!isset($this->users[$user])) {
65 1
            throw new ClientErrorResponseException(
66 1
                'User ' . $user . ' does not exist'
67 1
            );
68
        }
69
70 1
        $this->addGuzzleHeader(
71 1
            'Authorization',
72 1
            'Bearer ' . $this->users[$user]
73 1
        );
74 1
    }
75
76
    /**
77
     * Calls specified command
78
     *
79
     * Example: Given I called "getHeroesList"
80
     * Example: When I call "getHeroesList"
81
     *
82
     * @param string $command Command in service descriptions file
83
     *
84
     * @Given /^I called "(\S+)"$/
85
     * @When /^I call "(\S+)"$/
86
     */
87 6
    public function iCallCommand($command)
88
    {
89 6
        $this->executeCommand($command);
90 6
    }
91
92
    /**
93
     * Calls specified command with text
94
     *
95
     * Example: Given I called "postCertificates" with the following body text:
96
     *   """
97
     *   <?xml version="1.0" encoding="UTF-8"?>
98
     *   <Header userId="1" />
99
     *   <Body>
100
     *     <Document type="certificate" encoding="uft-8" noPages="1">
101
     *       <XML>...</XML>
102
     *       <Image>...</Image>
103
     *     </Document>
104
     *     <Document type="certificate" encoding="uft-8" noPages="1">
105
     *       <XML>...</XML>
106
     *       <Image>...</Image>
107
     *     </Document>
108
     *   </Body>
109
     *   """
110
     * Example: When I call "postCertificates" with the following body text:
111
     *   """
112
     *   <?xml version="1.0" encoding="UTF-8"?>
113
     *   <Header userId="1" />
114
     *   <Body>
115
     *     <Document type="certificate" encoding="uft-8" noPages="1">
116
     *       <XML>...</XML>
117
     *       <Image>...</Image>
118
     *     </Document>
119
     *     <Document type="certificate" encoding="uft-8" noPages="1">
120
     *       <XML>...</XML>
121
     *       <Image>...</Image>
122
     *     </Document>
123
     *   </Body>
124
     *   """
125
     *
126
     * @param string       $command Command in service descriptions file
127
     * @param PyStringNode $string  Text specified in feature
128
     *
129
     * @Given /^I called "(\S+)" with the following body text:$/
130
     * @When /^I call "(\S+)" with the following body text:$/
131
     */
132 1
    public function iCallCommandWithBodyText($command, PyStringNode $string)
133
    {
134 1
        $this->executeCommand(
135 1
            $command,
136
            array(
137 1
                'body' => $this->addStoredValues($string->getRaw())
138 1
            )
139 1
        );
140 1
    }
141
142
    /**
143
     * Calls specified command with fields
144
     *
145
     * Example: Given I called "putHero" with the following values:
146
     *   | description | I am not batman |
147
     *   | id          | 1               |
148
     * Example: When I call "putHero" with the following values:
149
     *   | description | I am not batman |
150
     *   | id          | 1               |
151
     *
152
     * @param string    $command Command in service descriptions file
153
     * @param TableNode $table   Values specified in feature
154
     *
155
     * @Given /^I called "(\S+)" with the following value(s?):$/
156
     * @When /^I call "(\S+)" with the following value(s?):$/
157
     */
158 2
    public function iCallCommandWithValue($command, TableNode $table)
159
    {
160 2
        $data = array();
161
162 2
        foreach ($table->getRowsHash() as $field => $value) {
163 2
            $value = $this->addStoredValues($value);
164 2
            $value = $this->castValue($value);
165
166 2
            $data[$field] = $value;
167 2
        }
168
169 2
        $this->executeCommand($command, $data);
170 2
    }
171
172
    /**
173
     * Calls specified command with fields
174
     *
175
     * Example: Given I called "putHero" with the following values from JSON:
176
     *   """
177
     *     [
178
     *       {
179
     *         "description": "I am not batman",
180
     *         "id": 1
181
     *       }
182
     *     ]
183
     *   """
184
     * Example: When I call "putHero" with the following values from JSON:
185
     *   """
186
     *     [
187
     *       {
188
     *         "description": "I am not batman",
189
     *         "id": 1
190
     *       }
191
     *     ]
192
     *   """
193
     *
194
     * @param string       $command Command in service descriptions file
195
     * @param PyStringNode $string  Values specified in feature as JSON
196
     *
197
     * @Given /^I called "(\S+)" with the following value(s?) from JSON:$/
198
     * @When /^I call "(\S+)" with the following value(s?) from JSON:$/
199
     */
200 5
    public function iCallCommandWithValueFromJSON(
201
        $command,
202
        PyStringNode $string
203
    ) {
204 5
        $this->executeCommand(
205 5
            $command,
206 5
            json_decode($this->addStoredValues($string->getRaw()), true)
207 5
        );
208 5
    }
209
210
    /**
211
     * Checks status code in reponse
212
     *
213
     * Example: And I get a response with a status code of 503
214
     * Example: Then I get a response with a status code of 503
215
     *
216
     * @param string $code Expected HTTP status code
217
     *
218
     * @Then I get a response with a status code of :code
219
     */
220 3
    public function iGetAResponseWithAStatusCodeOf($code)
221
    {
222 3
        $actual = $this->getGuzzleResponse()->getStatusCode();
223
224 3
        if ($actual != $code) {
225 1
            throw new ClientErrorResponseException(
226 1
                'Actual status code ' . $actual . ' does not match expected ' .
227 1
                'status code ' . $code . ' with message: ' .
228 1
                $this->getGuzzleResponse()->getMessage()
229 1
            );
230
        }
231 2
    }
232
233
    /**
234
     * Checks response is successful
235
     *
236
     * Example: And I get successful response
237
     * Example: Then I get successful response
238
     *
239
     * @Then I get a successful response
240
     */
241 2
    public function iGetASuccessfulResponse()
242
    {
243 2
        if (!$this->getGuzzleResponse()->isSuccessful()) {
244 1
            throw new ClientErrorResponseException(
245
                'Response unsuccessful with status code ' .
246 1
                $this->getGuzzleResponse()->getStatusCode()
247 1
            );
248
        }
249 1
    }
250
251
    /**
252
     * Checks response is unsuccessful with specified status code
253
     *
254
     * Example: And I get unsuccessful response with a status code of 503
255
     * Example: Then I get unsuccessful response with a status code of 503
256
     *
257
     * @param string $code Expected HTTP status code
258
     *
259
     * @Then I get an unsuccessful response with a status code of :code
260
     */
261 2
    public function iGetAnUnsuccessfulResponseWithAStatusCodeOf($code)
262
    {
263 2
        if ($this->getGuzzleResponse()->isSuccessful()) {
264 1
            throw new ClientErrorResponseException('Response successful');
265
        }
266
267 1
        $this->iGetAResponseWithAStatusCodeOf($code);
268 1
    }
269
270
    /**
271
     * Checks response body matches the following value
272
     *
273
     * Example: The the response body matches the following:
274
     *   """
275
     *   Id,Name,Age,Comment
276
     *   1,"Richard Saunders",33,"some description"
277
     *   2,"Dave Nash",,"another description"
278
     *   3,{stored[person][name]},{stored[person][age]},{stored[person][desc]}
279
     *   """
280
     *
281
     * @param PyStringNode $body
282
     *
283
     * @Then the response body matches the following:
284
     */
285 1
    public function theResponseBodyMatches(PyStringNode $body)
286
    {
287 1
        $this->compareValues(
288 1
            $this->getGuzzleResponse()->getBody(true),
289 1
            $this->addStoredValues($body->getRaw())
290 1
        );
291 1
    }
292
293
    /**
294
     * Check response contains a specified string
295
     *
296
     * Example: And the response contains the following string:
297
     *    """
298
     *      {stored[someArray][email][invalid]} is invalid
299
     *    """
300
     *
301
     * @param PyStringNode $string String specified in feature
302
     *
303
     * @Then the response contains the following string:
304
     */
305 1
    public function theResponseContainsTheFollowingString(
306
        PyStringNode $string
307
    ) {
308 1
        $response = $this->getGuzzleResponse()->getBody(true);
309 1
        $formatted = $this->addStoredValues($string->getRaw());
310
311 1
        if (strpos($response, $formatted) === false) {
312 1
            throw new ClientErrorResponseException(
313 1
                'Actual response ' . $response . ' does not contain ' .
314 1
                'string ' . $formatted
315 1
            );
316
        }
317
    }
318
319
    /**
320
     * Check response contains specified values
321
     *
322
     * Example: Then the response contains the following values:
323
     *   | id         | 27          |
324
     *   | importance | 3           |
325
     *   | username   | bruce.wayne |
326
     * Example: And the response contains the following value:
327
     *   | id | 27 |
328
     *
329
     * @param TableNode $table Values specified in feature
330
     *
331
     * @Then the response contains the following value(s):
332
     */
333 2
    public function theResponseContainsTheFollowingValue(TableNode $table)
334
    {
335 2
        $data = array();
336 2
        $item = $this->getGuzzleResult();
337
338 2
        foreach ($table->getRowsHash() as $field => $value) {
339 2
            $ref = &$data;
340 2
            foreach (explode('[', $field) as $part) {
341 2
                $part = trim($part, ']');
342 2
                $ref = &$ref[$part];
343 2
            }
344 2
            $ref = $this->addStoredValues($value);
345 2
        }
346
347 2
        $this->compareValues($item, $data);
348 1
    }
349
350
    /**
351
     * Check response contains specified values from JSON
352
     *
353
     * Example: The the response contains the following values from JSON:
354
     *   """
355
     *     {
356
     *       "name": "Test Name",
357
     *       "users": [
358
     *         {
359
     *           "id": 3
360
     *         },
361
     *         {
362
     *           "id": 6
363
     *         }
364
     *       ]
365
     *     }
366
     *   """
367
     * Example: And the response contains the following value from JSON:
368
     *   """
369
     *     {
370
     *       "name": "Test Name"
371
     *     }
372
     *   """
373
     *
374
     * @param PyStringNode $string Values specified in feature as JSON
375
     *
376
     * @Then the response contains the following value(s) from JSON:
377
     */
378 3
    public function theResponseContainsTheFollowingValueFromJSON(
379
        PyStringNode $string
380
    ) {
381 3
        $this->compareValues(
382 3
            $this->getGuzzleResult(),
383 3
            json_decode($this->addStoredValues($string->getRaw()), true)
384 3
        );
385 1
    }
386
387
    /**
388
     *
389
     * Example: Then the response contains 2 resources with the following data:
390
     *   | id | importance | username    |
391
     *   | 27 | 3          | bruce.wayne |
392
     *   | 34 | 2          | clark.kent  |
393
     * Example: And the response contains 1 resource with the following data:
394
     *   | id | importance | username    |
395
     *   | 27 | 3          | bruce.wayne |
396
     *
397
     * @param integer   $count Number of resources received
398
     * @param TableNode $table Values specified in feature
399
     *
400
     * @Then the response contains :count resource(s) with the following data:
401
     */
402 3
    public function theResponseContainsResourceWithTheFollowingData(
403
        $count,
404
        TableNode $table
405
    ) {
406 3
        $list = $this->getGuzzleResult();
407 3
        $length = count($list);
408
409 3
        if ($length != $count) {
410 1
            throw new ClientErrorResponseException(
411 1
                'Actual count ' . $length . ' does not match expected ' .
412 1
                'count ' . $count
413 1
            );
414
        }
415
416 2
        $data = $table->getHash();
417
418 2
        for ($i = 0; $i < $length; $i++) {
419 2
            $this->compareValues($list[$i], $data[$i]);
420 2
        }
421 2
    }
422
423
    /**
424
     * Store response for later use in the scenario
425
     *
426
     * Example: Then the response is stored as "heroes"
427
     * Example: And the response is stored as "heroes"
428
     *
429
     * @param string $name Name to use when storing response
430
     *
431
     * @Then /^the response is stored as "(\S+)"$/
432
     */
433 2
    public function theResponseIsStored($name)
434
    {
435 2
        $this->storedResult[$name] = $this->getGuzzleResult();
436 2
    }
437
438
    /**
439
     * Get stored value
440
     *
441
     * @param string $name Name used when storing response
442
     *
443
     * @access public
444
     * @return mixed
445
     */
446 1
    public function getStoredValue($name)
447
    {
448 1
        return $this->storedResult[$name];
449
    }
450
451
    /**
452
     * Set stored value
453
     *
454
     * @param string $name Name used for stored value
455
     * @param string $value Value stored under name
456
     *
457
     * @access public
458
     * @return $this
459
     */
460 1
    public function setStoredValue($name, $value)
461
    {
462 1
        $this->storedResult[$name] = $value;
463
464 1
        return $this;
465
    }
466
467
    /**
468
     * Cast value into type depending on content
469
     *
470
     * @param string $value String value
471
     *
472
     * @access protected
473
     * @return mixed
474
     */
475 2
    protected function castValue($value)
476
    {
477
        switch ($value) {
478 2
            case 'false':
479 1
                return false;
480
481 2
            case 'true':
482 1
                return true;
483
        }
484
485 2
        if (is_numeric($value)) {
486 1
            $value = intval($value);
487 1
        }
488
489 2
        return $value;
490
    }
491
492
    /**
493
     * Adds stored values to string
494
     *
495
     * @param string $string String containing stored field markers
496
     *
497
     * @access protected
498
     * @return string
499
     */
500 10
    protected function addStoredValues($string)
501
    {
502 10
        preg_match_all('/\{stored\[(.*?)\]\}/si', $string, $matches);
503
504 10
        $length = count($matches[0]);
505
506 10
        for ($i = 0; $i < $length; $i++) {
507 3
            $parts = explode('][', $matches[1][$i]);
508 3
            $value = $this->storedResult;
509 3
            foreach ($parts as $part) {
510 3
                if (isset($value[$part])) {
511 2
                    $value = $value[$part];
512 2
                }
513 3
            }
514
515 3
            $string = str_replace($matches[0][$i], $value, $string);
516 3
        }
517
518 10
        return $string;
519
    }
520
}
521