/api/vendor/peej/tonic/features/bootstrap/FeatureContext.php
PHP | 519 lines | 330 code | 54 blank | 135 comment | 52 complexity | 8b7f42a23b1052cc464a1f85a5883dab MD5 | raw file
1<?php
2
3use Behat\Behat\Context\ClosuredContextInterface,
4 Behat\Behat\Context\TranslatedContextInterface,
5 Behat\Behat\Context\BehatContext,
6 Behat\Behat\Exception\PendingException;
7use Behat\Gherkin\Node\PyStringNode,
8 Behat\Gherkin\Node\TableNode;
9
10use Tonic\Application,
11 Tonic\Request,
12 Tonic\Resource,
13 Tonic\Response;
14
15/**
16 * Features context.
17 */
18class FeatureContext extends BehatContext
19{
20
21 private $app, $request, $resource, $response, $exception, $error;
22
23 private $createMethod = array();
24 private $data;
25
26 private $options = array();
27
28 /**
29 * @BeforeFeature
30 */
31 public static function setupFeature()
32 {
33 unset($_SERVER);
34 unset($_GET);
35 unset($_POST);
36 }
37
38 /**
39 * @Given /^the request URI of "([^"]*)"$/
40 */
41 public function theRequestUriOf($uri)
42 {
43 $parsedUri = parse_url($uri);
44 $_SERVER['REDIRECT_URL'] = $parsedUri['path'];
45 if (isset($parsedUri['query'])) {
46 $query = explode('&', $parsedUri['query']);
47 foreach ($query as $item) {
48 list($name, $value) = explode('=', $item);
49 $_GET[$name] = $value;
50 }
51 }
52 $_SERVER['SCRIPT_NAME'] = '';
53 }
54
55 /**
56 * @Given /^the request method of "([^"]*)"$/
57 */
58 public function theRequestMethodOf($method)
59 {
60 $_SERVER['REQUEST_METHOD'] = $method;
61 }
62
63 /**
64 * @When /^I create an application object$/
65 */
66 public function iCreateAnApplicationObject()
67 {
68 $this->app = new Application($this->options);
69 }
70
71 /**
72 * @When /^I create a request object$/
73 */
74 public function iCreateARequestObject()
75 {
76 if ($this->data) {
77 $this->options['data'] = $this->data;
78 $this->options['contentType'] = $_SERVER['CONTENT_TYPE'];
79 }
80 $this->request = new Request($this->options);
81 }
82
83 /**
84 * @Then /^I should see a request URI of "([^"]*)"$/
85 */
86 public function iShouldSeeARequestUriOf($uri)
87 {
88 if ($this->request->uri != $uri) throw new Exception;
89 }
90
91 /**
92 * @Then /^I should see a request method of "([^"]*)"$/
93 */
94 public function iShouldSeeARequestMethodOf($method)
95 {
96 if ($this->request->method != $method) throw new Exception;
97 }
98
99 /**
100 * @Given /^an? "([^"]*)" header of ['"]([^']*)['"]$/
101 */
102 public function aHeaderOf($header, $value)
103 {
104 $headerMapping = array(
105 'accept' => 'HTTP_ACCEPT',
106 'accept language' => 'HTTP_ACCEPT_LANGUAGE',
107 'if-none-match' => 'HTTP_IF_NONE_MATCH',
108 'if-match' => 'HTTP_IF_MATCH',
109 'content-type' => 'CONTENT_TYPE',
110 'auth user' => 'PHP_AUTH_USER',
111 'auth password' => 'PHP_AUTH_PW',
112 'x-authentication' => 'HTTP_X_AUTHENTICATION'
113 );
114 $_SERVER[$headerMapping[$header]] = $value;
115 }
116
117 /**
118 * @Given /^I should see an? "([^"]*)" string of "([^"]*)"$/
119 */
120 public function iShouldSeeAStringOf($header, $string)
121 {
122 $propertyMapping = array(
123 'accept' => 'accept',
124 'accept language' => 'acceptLanguage',
125 'if-none-match' => 'ifNoneMatch',
126 'if-match' => 'ifMatch',
127 'content-type' => 'contentType'
128 );
129 if (is_array($this->request->$propertyMapping[$header])) {
130 $value = join(',', $this->request->$propertyMapping[$header]);
131 } else {
132 $value = $this->request->$propertyMapping[$header];
133 }
134 if ($value != $string)
135 throw new Exception($value);
136 }
137
138 /**
139 * @Given /^body data of \'([^\']*)\'$/
140 */
141 public function bodyDataOf($data)
142 {
143 $this->data = $data;
144 }
145
146 /**
147 * @Given /^I should see body data of "([^"]*)"$/
148 */
149 public function iShouldSeeBodyDataOf($data)
150 {
151 if ($this->request->data != $data)
152 throw new Exception();
153 }
154
155 /**
156 * @Given /^a resource definition "([^"]*)" with URI "([^"]*)" and priority of (\d+)$/
157 */
158 public function aResourceDefinitionWithUriAndPriorityOf($className, $uri, $priority)
159 {
160 $this->aResourceDefinition($className, $uri, $priority);
161 }
162
163 /**
164 * @Given /^a resource definition "([^"]*)" with URI "([^"]*)" and namespace of "([^"]*)"$/
165 */
166 public function aResourceDefinitionWithUriAndNamespaceOf($className, $uri, $namespace)
167 {
168 $this->aResourceDefinition($className, $uri, 1, $namespace);
169 }
170
171 /**
172 * @Given /^a resource definition "([^"]*)" with URI "([^"]*)" and namespace annotation of "([^"]*)"$/
173 */
174 public function aResourceDefinitionWithUriAndNamespaceAnnotationOf($className, $uri, $namespace)
175 {
176 $this->aResourceDefinition($className, $uri, 1, NULL, $namespace);
177 }
178
179 /**
180 * @Given /^a resource definition "([^"]*)" with URI "([^"]*)" and windows style line endings$/
181 */
182 public function aResourceDefinitionWithUriAndWindowsStyleLineEndings($className, $uri)
183 {
184 $this->aResourceDefinition($className, $uri, 1, NULL, NULL, "\r\n");
185 }
186
187 private function aResourceDefinition($className, $uri, $priority = 1, $namespace = NULL, $annotationNamespace = NULL, $lineEnding = "\n")
188 {
189 $classDefinition = '';
190 if ($namespace) $classDefinition .= 'namespace '.$namespace.';'.$lineEnding;
191 $classDefinition .= '/**'.$lineEnding.
192 ' * @uri '.$uri.$lineEnding.
193 ' * @priority '.$priority.$lineEnding;
194 if ($annotationNamespace) $classDefinition .= ' * @namespace '.$annotationNamespace.$lineEnding;
195 $classDefinition .= ' */'.$lineEnding.
196 'class '.$className.' extends \Tonic\Resource {'.$lineEnding;
197 foreach ($this->createMethod as $methodData) {
198 $classDefinition .= ' /**'.$lineEnding;
199 $classDefinition .= ' * @method '.(isset($methodData['method']) ? $methodData['method'] : 'GET').$lineEnding;
200 if (isset($methodData['lang'])) $classDefinition .= ' * @lang '.$methodData['lang'].$lineEnding;
201 if (isset($methodData['accepts'])) $classDefinition .= ' * @accepts '.$methodData['accepts'].$lineEnding;
202 if (isset($methodData['provides'])) $classDefinition .= ' * @provides '.$methodData['provides'].$lineEnding;
203 $classDefinition .= $lineEnding.' */'.$lineEnding.
204 ' function '.$methodData['name'].'() {'.$lineEnding.
205 ' return "'.$methodData['name'].'";'.$lineEnding.
206 ' }'.$lineEnding;
207 }
208 $classDefinition .= '}'.$lineEnding;
209 eval($classDefinition);
210 }
211
212 /**
213 * @Given /^load the resource$/
214 */
215 public function loadTheResource()
216 {
217 try {
218 $this->resource = $this->app->getResource($this->request);
219 } catch (Tonic\Exception $e) {
220 $this->exception = $e;
221 }
222 }
223
224 /**
225 * @Then /^the loaded resource should have a class of "([^"]*)"$/
226 */
227 public function theLoadedResourceShouldHaveAClassOf($className)
228 {
229 $loadedClassName = get_class($this->resource);
230 if ($loadedClassName != $className) throw new Exception($loadedClassName.' != '.$className);
231 }
232
233 /**
234 * @Given /^the loaded resource should have a param "([^"]*)" with the value "([^"]*)"$/
235 */
236 public function theLoadedResourceShouldHaveAParamWithTheValue($name, $value)
237 {
238 if (!isset($this->resource->params[$name])) throw new Exception('Param '.$name.' not found');
239 if ($this->resource->params[$name] != $value) throw new Exception('Param '.$name.' does not equal '.$value);
240 }
241
242 /**
243 * @Given /^execute the resource$/
244 */
245 public function executeTheResource()
246 {
247 set_error_handler(function ($level, $message, $file, $line) {
248 throw new ErrorException($message, $level);
249 });
250 try {
251 if ($this->resource) {
252 $this->response = $this->resource->exec();
253 } else {
254 throw new Exception('Resource not loaded');
255 }
256 } catch (Tonic\Exception $e) {
257 $this->exception = $e;
258 } catch (ErrorException $e) {
259 $this->exception = $e;
260 $this->error = $e->getCode();
261 }
262 restore_error_handler();
263 }
264
265 /**
266 * @Then /^response should be "([^"]*)"$/
267 */
268 public function responseShouldBe($responseString)
269 {
270 if (!$this->response) throw new Exception('Response not loaded due to '.$this->exception);
271 if ($this->response->body != $responseString) throw new Exception('The response body is: "'.$this->response->body.'"');
272 }
273
274 /**
275 * @Given /^a "([^"]*)" resource method "([^"]*)"$/
276 */
277 public function aResourceMethod($method, $name)
278 {
279 $this->createMethod[] = array(
280 'method' => $method,
281 'name' => $name
282 );
283 }
284
285 /**
286 * @Given /^a "([^"]*)" resource method "([^"]*)" that provides "([^"]*)"$/
287 */
288 public function aResourceMethodThatProvides($method, $name, $provides)
289 {
290 $this->createMethod[] = array(
291 'method' => $method,
292 'name' => $name,
293 'provides' => $provides
294 );
295 }
296
297 /**
298 * @Given /^a "([^"]*)" resource method "([^"]*)" that accepts "([^"]*)"$/
299 */
300 public function aResourceMethodThatAccepts($method, $name, $accepts)
301 {
302 $this->createMethod[] = array(
303 'method' => $method,
304 'name' => $name,
305 'accepts' => $accepts
306 );
307 }
308
309 /**
310 * @Given /^the request content type of "([^"]*)"$/
311 */
312 public function theRequestContentTypeOf($contentType)
313 {
314 $_SERVER['CONTENT_TYPE'] = $contentType;
315 }
316
317 /**
318 * @Given /^the request data of "([^"]*)"$/
319 */
320 public function theRequestDataOf($data)
321 {
322 $this->data = $data;
323 }
324
325 /**
326 * @Then /^a "([^"]*)" should be thrown$/
327 */
328 public function aShouldBeThrown($exception)
329 {
330 if ($exception != get_class($this->exception)) throw new Exception($this->exception->getMessage());
331 }
332
333 /**
334 * @Then /^a PHP warning should occur$/
335 */
336 public function aPhpWarningShouldOccur()
337 {
338 if ($this->error != E_WARNING) throw new Exception('No PHP warning');
339 }
340
341 /**
342 * @Then /^a PHP notice should occur$/
343 */
344 public function aPhpNoticeShouldOccur()
345 {
346 if ($this->error != E_NOTICE) throw new Exception('No PHP notice');
347 }
348
349 /**
350 * @Given /^I mount "([^"]*)" at the URI "([^"]*)"$/
351 */
352 public function iMountAtTheUri($className, $uriSpace)
353 {
354 $this->app->mount($className, $uriSpace);
355 }
356
357 /**
358 * @Given /^a class definition:$/
359 */
360 public function aClassDefinition(PyStringNode $string)
361 {
362 eval($string);
363 }
364
365 /**
366 * @Given /^I set the request option "([^"]*)" to:$/
367 */
368 public function iSetTheRequestOptionTo($option, PyStringNode $json)
369 {
370 $this->options[$option] = json_decode($json, TRUE);
371 }
372
373 /**
374 * @Given /^I supply an empty cache object$/
375 */
376 public function iSupplyAnEmptyCacheObject()
377 {
378 $this->options['cache'] = new MockMetadataCache();
379 }
380
381 /**
382 * @Given /^a resource file "([^"]*)" to load$/
383 */
384 public function aResourceFileToLoad($filename)
385 {
386 $this->options['load'][] = $filename;
387 }
388
389 /**
390 * @Given /^the cache object should contain "([^"]*)" "([^"]*)"$/
391 */
392 public function theCacheObjectShouldContain($className, $methodName)
393 {
394 if (!$this->options['cache']->contains($className, $methodName)) throw new Exception;
395 }
396
397 /**
398 * @Given /^a cache object containing a class "([^"]*)" with a URL of "([^"]*)" and a method "([^"]*)" responding to HTTP "([^"]*)"$/
399 */
400 public function aCacheObjectContainingAClassWithAUrlOfAndAMethodRespondingToHttp($className, $uri, $methodName, $method)
401 {
402 $this->iSupplyAnEmptyCacheObject();
403 $this->options['cache']->save(array(
404 $className => array(
405 'class' => $className,
406 'uri' => $uri,
407 'methods' => array(
408 $methodName => array(
409 'method' => array(
410 $method
411 )
412 )
413 )
414 )
415 ));
416 }
417
418 /**
419 * @Then /^the loaded resource "([^"]*)" should respond with the method "([^"]*)"$/
420 */
421 public function theLoadedResourceShouldRespondToWithTheMethod($className, $methodName)
422 {
423 $metadata = $this->app->getResourceMetadata($className);
424 if (!isset($metadata['methods'][$methodName])) throw new Exception;
425 }
426
427 /**
428 * @Then /^fetching the URI for the resource "([^"]*)" with the parameter "([^"]*)" should get "([^"]*)"$/
429 */
430 public function fetchingTheUriForTheResourceShouldGet($className, $params, $url)
431 {
432 $params = explode(':', $params);
433 if ($this->app->uri($className, $params) != $url)
434 throw new Exception($this->app->uri($className, $params).' != '.$url);
435 }
436
437 /**
438 * @Given /^a "([^"]*)" resource method "([^"]*)" with lang "([^"]*)"$/
439 */
440 public function aResourceMethodWithLang($method, $name, $language)
441 {
442 $this->createMethod[] = array(
443 'method' => $method,
444 'name' => $name,
445 'lang' => $language
446 );
447 }
448
449 /**
450 * @Then /^the resource "([^"]*)" should have the URI "([^"]*)"$/
451 */
452 public function theResourceShouldHaveTheURI($resourceName, $url)
453 {
454 $found = FALSE;
455 $metadata = $this->app->getResourceMetadata($resourceName);
456 foreach ($metadata['uri'] as $uri) {
457 if ($uri[0] == $url) {
458 $found = TRUE;
459 break;
460 }
461 }
462 if (!$found) throw new Exception;
463 }
464
465 /**
466 * @Then /^the resource "([^"]*)" should have the condition "([^"]*)" with the parameters "([^"]*)"$/
467 */
468 public function theResourceShouldHaveTheConditionWithTheParameters($className, $conditionName, $parameters)
469 {
470 $metadata = $this->app->getResourceMetadata($className);
471 if ($parameters) {
472 if ($parameters != join(',', $metadata['methods']['test'][$conditionName][0])) throw new Exception('Condition method not found');
473
474 $resource = new $className($this->app, new Request, array());
475 $condition = call_user_func_array(array($resource, $conditionName), explode(',', $parameters));
476 if ($condition != explode(',', $parameters)) throw new Exception('Condition parameters not returned');
477 } else {
478 if (!isset($metadata['methods']['test'][$conditionName])) throw new Exception('Condition method not found');
479 }
480 }
481
482 /**
483 * @Given /^an issue "([^"]*)"$/
484 */
485 public function anIssue($issue)
486 {
487 require_once dirname(__FILE__).'/../../issues/'.$issue.'.php';
488 }
489
490 /**
491 * @Given /^the method priority for "([^"]*)" should be "([^"]*)"$/
492 */
493 public function theMethodPriorityForShouldBe($methodName, $value)
494 {
495 preg_match('/[\[ ]([0-9-]+)\] '.$methodName.' /', (string)$this->resource, $matches);
496 if (!$matches)
497 throw new Exception('"'.$methodName.'" not found');
498 if ($matches[1] != $value)
499 throw new Exception('"'.$methodName.'" has the priortiy of '.$matches[1]);
500 }
501
502 /**
503 * @Then /^the response should have the header "([^"]*)" with the value "([^"]*)"$/
504 */
505 public function theResponseShouldHaveTheHeaderWithTheValue($name, $value)
506 {
507 if ($this->response->headers[$name] != $value) throw new Exception('Response header '.$name.' does not equal '.$value);
508 }
509
510 /**
511 * @Then /^output the "([^"]*)"$/
512 */
513 public function outputThe($thing)
514 {
515 echo $this->$thing;
516 }
517
518
519}