init
This commit is contained in:
47
vendor/codeception/base/src/Codeception/Lib/Actor/Shared/Comment.php
vendored
Normal file
47
vendor/codeception/base/src/Codeception/Lib/Actor/Shared/Comment.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Actor\Shared;
|
||||
|
||||
trait Comment
|
||||
{
|
||||
/**
|
||||
* @return \Codeception\Scenario
|
||||
*/
|
||||
abstract protected function getScenario();
|
||||
|
||||
public function expectTo($prediction)
|
||||
{
|
||||
return $this->comment('I expect to ' . $prediction);
|
||||
}
|
||||
|
||||
public function expect($prediction)
|
||||
{
|
||||
return $this->comment('I expect ' . $prediction);
|
||||
}
|
||||
|
||||
public function amGoingTo($argumentation)
|
||||
{
|
||||
return $this->comment('I am going to ' . $argumentation);
|
||||
}
|
||||
|
||||
public function am($role)
|
||||
{
|
||||
$role = trim($role);
|
||||
|
||||
if (stripos('aeiou', $role[0]) !== false) {
|
||||
return $this->comment('As an ' . $role);
|
||||
}
|
||||
|
||||
return $this->comment('As a ' . $role);
|
||||
}
|
||||
|
||||
public function lookForwardTo($achieveValue)
|
||||
{
|
||||
return $this->comment('So that I ' . $achieveValue);
|
||||
}
|
||||
|
||||
public function comment($description)
|
||||
{
|
||||
$this->getScenario()->comment($description);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
29
vendor/codeception/base/src/Codeception/Lib/Actor/Shared/Friend.php
vendored
Normal file
29
vendor/codeception/base/src/Codeception/Lib/Actor/Shared/Friend.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Actor\Shared;
|
||||
|
||||
use Codeception\Lib\Friend as LibFriend;
|
||||
use Codeception\Scenario;
|
||||
|
||||
trait Friend
|
||||
{
|
||||
protected $friends = [];
|
||||
|
||||
/**
|
||||
* @return Scenario
|
||||
*/
|
||||
abstract protected function getScenario();
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $actorClass
|
||||
* @return \Codeception\Lib\Friend
|
||||
*/
|
||||
public function haveFriend($name, $actorClass = null)
|
||||
{
|
||||
if (!isset($this->friends[$name])) {
|
||||
$actor = $actorClass === null ? $this : new $actorClass($this->getScenario());
|
||||
$this->friends[$name] = new LibFriend($name, $actor, $this->getScenario()->current('modules'));
|
||||
}
|
||||
return $this->friends[$name];
|
||||
}
|
||||
}
|
||||
295
vendor/codeception/base/src/Codeception/Lib/Connector/Guzzle.php
vendored
Normal file
295
vendor/codeception/base/src/Codeception/Lib/Connector/Guzzle.php
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector;
|
||||
|
||||
use Aws\Credentials\Credentials;
|
||||
use Aws\Signature\SignatureV4;
|
||||
use Codeception\Util\Uri;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Message\Response;
|
||||
use GuzzleHttp\Post\PostFile;
|
||||
use Symfony\Component\BrowserKit\Client;
|
||||
use Symfony\Component\BrowserKit\Response as BrowserKitResponse;
|
||||
use GuzzleHttp\Url;
|
||||
use Symfony\Component\BrowserKit\Request as BrowserKitRequest;
|
||||
|
||||
class Guzzle extends Client
|
||||
{
|
||||
protected $baseUri;
|
||||
protected $requestOptions = [
|
||||
'allow_redirects' => false,
|
||||
'headers' => [],
|
||||
];
|
||||
protected $refreshMaxInterval = 0;
|
||||
|
||||
protected $awsCredentials = null;
|
||||
protected $awsSignature = null;
|
||||
|
||||
/** @var \GuzzleHttp\Client */
|
||||
protected $client;
|
||||
|
||||
public function setBaseUri($uri)
|
||||
{
|
||||
$this->baseUri = $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum allowable timeout interval for a meta tag refresh to
|
||||
* automatically redirect a request.
|
||||
*
|
||||
* A meta tag detected with an interval equal to or greater than $seconds
|
||||
* would not result in a redirect. A meta tag without a specified interval
|
||||
* or one with a value less than $seconds would result in the client
|
||||
* automatically redirecting to the specified URL
|
||||
*
|
||||
* @param int $seconds Number of seconds
|
||||
*/
|
||||
public function setRefreshMaxInterval($seconds)
|
||||
{
|
||||
$this->refreshMaxInterval = $seconds;
|
||||
}
|
||||
|
||||
public function setClient(\GuzzleHttp\Client $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the request header to the passed value. The header will be
|
||||
* sent along with the next request.
|
||||
*
|
||||
* Passing an empty value clears the header, which is the equivalent
|
||||
* of calling deleteHeader.
|
||||
*
|
||||
* @param string $name the name of the header
|
||||
* @param string $value the value of the header
|
||||
*/
|
||||
public function setHeader($name, $value)
|
||||
{
|
||||
if (strval($value) === '') {
|
||||
$this->deleteHeader($name);
|
||||
} else {
|
||||
$this->requestOptions['headers'][$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the header with the passed name from the list of headers
|
||||
* that will be sent with the request.
|
||||
*
|
||||
* @param string $name the name of the header to delete.
|
||||
*/
|
||||
public function deleteHeader($name)
|
||||
{
|
||||
unset($this->requestOptions['headers'][$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param string $type Default: 'basic'
|
||||
*/
|
||||
public function setAuth($username, $password, $type = 'basic')
|
||||
{
|
||||
if (!$username) {
|
||||
unset($this->requestOptions['auth']);
|
||||
return;
|
||||
}
|
||||
$this->requestOptions['auth'] = [$username, $password, $type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Taken from Mink\BrowserKitDriver
|
||||
*
|
||||
* @param Response $response
|
||||
*
|
||||
* @return \Symfony\Component\BrowserKit\Response
|
||||
*/
|
||||
protected function createResponse(Response $response)
|
||||
{
|
||||
$contentType = $response->getHeader('Content-Type');
|
||||
|
||||
if (!$contentType) {
|
||||
$contentType = 'text/html';
|
||||
}
|
||||
|
||||
if (strpos($contentType, 'charset=') === false) {
|
||||
$body = $response->getBody(true);
|
||||
if (preg_match('/\<meta[^\>]+charset *= *["\']?([a-zA-Z\-0-9]+)/i', $body, $matches)) {
|
||||
$contentType .= ';charset=' . $matches[1];
|
||||
}
|
||||
$response->setHeader('Content-Type', $contentType);
|
||||
}
|
||||
|
||||
$headers = $response->getHeaders();
|
||||
$status = $response->getStatusCode();
|
||||
if ($status < 300 || $status >= 400) {
|
||||
$matches = [];
|
||||
|
||||
$matchesMeta = preg_match(
|
||||
'/\<meta[^\>]+http-equiv="refresh" content="\s*(\d*)\s*;\s*url=(.*?)"/i',
|
||||
$response->getBody(true),
|
||||
$matches
|
||||
);
|
||||
|
||||
if (!$matchesMeta) {
|
||||
// match by header
|
||||
preg_match(
|
||||
'/^\s*(\d*)\s*;\s*url=(.*)/i',
|
||||
(string)$response->getHeader('Refresh'),
|
||||
$matches
|
||||
);
|
||||
}
|
||||
|
||||
if ((!empty($matches)) && (empty($matches[1]) || $matches[1] < $this->refreshMaxInterval)) {
|
||||
$uri = $this->getAbsoluteUri($matches[2]);
|
||||
$partsUri = parse_url($uri);
|
||||
$partsCur = parse_url($this->getHistory()->current()->getUri());
|
||||
foreach ($partsCur as $key => $part) {
|
||||
if ($key === 'fragment') {
|
||||
continue;
|
||||
}
|
||||
if (!isset($partsUri[$key]) || $partsUri[$key] !== $part) {
|
||||
$status = 302;
|
||||
$headers['Location'] = $matchesMeta ? htmlspecialchars_decode($uri) : $uri;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new BrowserKitResponse($response->getBody(), $status, $headers);
|
||||
}
|
||||
|
||||
public function getAbsoluteUri($uri)
|
||||
{
|
||||
$baseUri = $this->baseUri;
|
||||
if (strpos($uri, '://') === false && strpos($uri, '//') !== 0) {
|
||||
if (strpos($uri, '/') === 0) {
|
||||
$baseUriPath = parse_url($baseUri, PHP_URL_PATH);
|
||||
if (!empty($baseUriPath) && strpos($uri, $baseUriPath) === 0) {
|
||||
$uri = substr($uri, strlen($baseUriPath));
|
||||
}
|
||||
|
||||
return Uri::appendPath((string)$baseUri, $uri);
|
||||
}
|
||||
// relative url
|
||||
if (!$this->getHistory()->isEmpty()) {
|
||||
return Uri::mergeUrls((string)$this->getHistory()->current()->getUri(), $uri);
|
||||
}
|
||||
}
|
||||
return Uri::mergeUrls($baseUri, $uri);
|
||||
}
|
||||
|
||||
protected function doRequest($request)
|
||||
{
|
||||
/** @var $request BrowserKitRequest **/
|
||||
$requestOptions = [
|
||||
'body' => $this->extractBody($request),
|
||||
'cookies' => $this->extractCookies($request),
|
||||
'headers' => $this->extractHeaders($request)
|
||||
];
|
||||
|
||||
$requestOptions = array_replace_recursive($requestOptions, $this->requestOptions);
|
||||
|
||||
$guzzleRequest = $this->client->createRequest(
|
||||
$request->getMethod(),
|
||||
$request->getUri(),
|
||||
$requestOptions
|
||||
);
|
||||
foreach ($this->extractFiles($request) as $postFile) {
|
||||
$guzzleRequest->getBody()->addFile($postFile);
|
||||
}
|
||||
|
||||
// Let BrowserKit handle redirects
|
||||
try {
|
||||
if (null !== $this->awsCredentials) {
|
||||
$response = $this->client->send($this->awsSignature->signRequest($guzzleRequest, $this->awsCredentials));
|
||||
} else {
|
||||
$response = $this->client->send($guzzleRequest);
|
||||
}
|
||||
} catch (RequestException $e) {
|
||||
if ($e->hasResponse()) {
|
||||
$response = $e->getResponse();
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
return $this->createResponse($response);
|
||||
}
|
||||
|
||||
protected function extractHeaders(BrowserKitRequest $request)
|
||||
{
|
||||
$headers = [];
|
||||
$server = $request->getServer();
|
||||
|
||||
$contentHeaders = ['Content-Length' => true, 'Content-Md5' => true, 'Content-Type' => true];
|
||||
foreach ($server as $header => $val) {
|
||||
$header = html_entity_decode(implode('-', array_map('ucfirst', explode('-', strtolower(str_replace('_', '-', $header))))), ENT_NOQUOTES);
|
||||
if (strpos($header, 'Http-') === 0) {
|
||||
$headers[substr($header, 5)] = $val;
|
||||
} elseif (isset($contentHeaders[$header])) {
|
||||
$headers[$header] = $val;
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
|
||||
protected function extractBody(BrowserKitRequest $request)
|
||||
{
|
||||
if (in_array(strtoupper($request->getMethod()), ['GET', 'HEAD'])) {
|
||||
return null;
|
||||
}
|
||||
if ($request->getContent() !== null) {
|
||||
return $request->getContent();
|
||||
}
|
||||
|
||||
return $request->getParameters();
|
||||
}
|
||||
|
||||
protected function extractFiles(BrowserKitRequest $request)
|
||||
{
|
||||
if (!in_array(strtoupper($request->getMethod()), ['POST', 'PUT'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->mapFiles($request->getFiles());
|
||||
}
|
||||
|
||||
protected function mapFiles($requestFiles, $arrayName = '')
|
||||
{
|
||||
$files = [];
|
||||
foreach ($requestFiles as $name => $info) {
|
||||
if (!empty($arrayName)) {
|
||||
$name = $arrayName.'['.$name.']';
|
||||
}
|
||||
|
||||
if (is_array($info)) {
|
||||
if (isset($info['tmp_name'])) {
|
||||
if ($info['tmp_name']) {
|
||||
$handle = fopen($info['tmp_name'], 'r');
|
||||
$filename = isset($info['name']) ? $info['name'] : null;
|
||||
|
||||
$files[] = new PostFile($name, $handle, $filename);
|
||||
}
|
||||
} else {
|
||||
$files = array_merge($files, $this->mapFiles($info, $name));
|
||||
}
|
||||
} else {
|
||||
$files[] = new PostFile($name, fopen($info, 'r'));
|
||||
}
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
protected function extractCookies(BrowserKitRequest $request)
|
||||
{
|
||||
return $this->getCookieJar()->allRawValues($request->getUri());
|
||||
}
|
||||
|
||||
public function setAwsAuth($config)
|
||||
{
|
||||
$this->awsCredentials = new Credentials($config['key'], $config['secret']);
|
||||
$this->awsSignature = new SignatureV4($config['service'], $config['region']);
|
||||
}
|
||||
}
|
||||
356
vendor/codeception/base/src/Codeception/Lib/Connector/Guzzle6.php
vendored
Normal file
356
vendor/codeception/base/src/Codeception/Lib/Connector/Guzzle6.php
vendored
Normal file
@@ -0,0 +1,356 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector;
|
||||
|
||||
use Aws\Credentials\Credentials;
|
||||
use Aws\Signature\SignatureV4;
|
||||
use Codeception\Util\Uri;
|
||||
use GuzzleHttp\Client as GuzzleClient;
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use GuzzleHttp\Cookie\SetCookie;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Handler\CurlHandler;
|
||||
use GuzzleHttp\Handler\StreamHandler;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Psr7\Request as Psr7Request;
|
||||
use GuzzleHttp\Psr7\Response as Psr7Response;
|
||||
use GuzzleHttp\Psr7\Uri as Psr7Uri;
|
||||
use Symfony\Component\BrowserKit\Client;
|
||||
use Symfony\Component\BrowserKit\Cookie;
|
||||
use Symfony\Component\BrowserKit\Request as BrowserKitRequest;
|
||||
use Symfony\Component\BrowserKit\Request;
|
||||
use Symfony\Component\BrowserKit\Response as BrowserKitResponse;
|
||||
|
||||
class Guzzle6 extends Client
|
||||
{
|
||||
protected $requestOptions = [
|
||||
'allow_redirects' => false,
|
||||
'headers' => [],
|
||||
];
|
||||
protected $refreshMaxInterval = 0;
|
||||
|
||||
protected $awsCredentials = null;
|
||||
protected $awsSignature = null;
|
||||
|
||||
/** @var \GuzzleHttp\Client */
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* Sets the maximum allowable timeout interval for a meta tag refresh to
|
||||
* automatically redirect a request.
|
||||
*
|
||||
* A meta tag detected with an interval equal to or greater than $seconds
|
||||
* would not result in a redirect. A meta tag without a specified interval
|
||||
* or one with a value less than $seconds would result in the client
|
||||
* automatically redirecting to the specified URL
|
||||
*
|
||||
* @param int $seconds Number of seconds
|
||||
*/
|
||||
public function setRefreshMaxInterval($seconds)
|
||||
{
|
||||
$this->refreshMaxInterval = $seconds;
|
||||
}
|
||||
|
||||
public function setClient(GuzzleClient &$client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the request header to the passed value. The header will be
|
||||
* sent along with the next request.
|
||||
*
|
||||
* Passing an empty value clears the header, which is the equivalent
|
||||
* of calling deleteHeader.
|
||||
*
|
||||
* @param string $name the name of the header
|
||||
* @param string $value the value of the header
|
||||
*/
|
||||
public function setHeader($name, $value)
|
||||
{
|
||||
if (strval($value) === '') {
|
||||
$this->deleteHeader($name);
|
||||
} else {
|
||||
$this->requestOptions['headers'][$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the header with the passed name from the list of headers
|
||||
* that will be sent with the request.
|
||||
*
|
||||
* @param string $name the name of the header to delete.
|
||||
*/
|
||||
public function deleteHeader($name)
|
||||
{
|
||||
unset($this->requestOptions['headers'][$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param string $type Default: 'basic'
|
||||
*/
|
||||
public function setAuth($username, $password, $type = 'basic')
|
||||
{
|
||||
if (!$username) {
|
||||
unset($this->requestOptions['auth']);
|
||||
return;
|
||||
}
|
||||
$this->requestOptions['auth'] = [$username, $password, $type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Taken from Mink\BrowserKitDriver
|
||||
*
|
||||
* @param Response $response
|
||||
*
|
||||
* @return \Symfony\Component\BrowserKit\Response
|
||||
*/
|
||||
protected function createResponse(Psr7Response $response)
|
||||
{
|
||||
$body = (string) $response->getBody();
|
||||
$headers = $response->getHeaders();
|
||||
|
||||
$contentType = null;
|
||||
|
||||
if (isset($headers['Content-Type'])) {
|
||||
$contentType = reset($headers['Content-Type']);
|
||||
}
|
||||
if (!$contentType) {
|
||||
$contentType = 'text/html';
|
||||
}
|
||||
|
||||
if (strpos($contentType, 'charset=') === false) {
|
||||
if (preg_match('/\<meta[^\>]+charset *= *["\']?([a-zA-Z\-0-9]+)/i', $body, $matches)) {
|
||||
$contentType .= ';charset=' . $matches[1];
|
||||
}
|
||||
$headers['Content-Type'] = [$contentType];
|
||||
}
|
||||
|
||||
$status = $response->getStatusCode();
|
||||
if ($status < 300 || $status >= 400) {
|
||||
$matches = [];
|
||||
|
||||
$matchesMeta = preg_match(
|
||||
'/\<meta[^\>]+http-equiv="refresh" content="\s*(\d*)\s*;\s*url=(.*?)"/i',
|
||||
$body,
|
||||
$matches
|
||||
);
|
||||
|
||||
if (!$matchesMeta && isset($headers['Refresh'])) {
|
||||
// match by header
|
||||
preg_match(
|
||||
'/^\s*(\d*)\s*;\s*url=(.*)/i',
|
||||
(string) reset($headers['Refresh']),
|
||||
$matches
|
||||
);
|
||||
}
|
||||
|
||||
if ((!empty($matches)) && (empty($matches[1]) || $matches[1] < $this->refreshMaxInterval)) {
|
||||
$uri = new Psr7Uri($this->getAbsoluteUri($matches[2]));
|
||||
$currentUri = new Psr7Uri($this->getHistory()->current()->getUri());
|
||||
|
||||
if ($uri->withFragment('') != $currentUri->withFragment('')) {
|
||||
$status = 302;
|
||||
$headers['Location'] = $matchesMeta ? htmlspecialchars_decode($uri) : (string)$uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new BrowserKitResponse($body, $status, $headers);
|
||||
}
|
||||
|
||||
public function getAbsoluteUri($uri)
|
||||
{
|
||||
$baseUri = $this->client->getConfig('base_uri');
|
||||
if (strpos($uri, '://') === false && strpos($uri, '//') !== 0) {
|
||||
if (strpos($uri, '/') === 0) {
|
||||
$baseUriPath = $baseUri->getPath();
|
||||
if (!empty($baseUriPath) && strpos($uri, $baseUriPath) === 0) {
|
||||
$uri = substr($uri, strlen($baseUriPath));
|
||||
}
|
||||
|
||||
return Uri::appendPath((string)$baseUri, $uri);
|
||||
}
|
||||
// relative url
|
||||
if (!$this->getHistory()->isEmpty()) {
|
||||
return Uri::mergeUrls((string)$this->getHistory()->current()->getUri(), $uri);
|
||||
}
|
||||
}
|
||||
return Uri::mergeUrls($baseUri, $uri);
|
||||
}
|
||||
|
||||
protected function doRequest($request)
|
||||
{
|
||||
/** @var $request BrowserKitRequest **/
|
||||
$guzzleRequest = new Psr7Request(
|
||||
$request->getMethod(),
|
||||
$request->getUri(),
|
||||
$this->extractHeaders($request),
|
||||
$request->getContent()
|
||||
);
|
||||
$options = $this->requestOptions;
|
||||
$options['cookies'] = $this->extractCookies($guzzleRequest->getUri()->getHost());
|
||||
$multipartData = $this->extractMultipartFormData($request);
|
||||
if (!empty($multipartData)) {
|
||||
$options['multipart'] = $multipartData;
|
||||
}
|
||||
|
||||
$formData = $this->extractFormData($request);
|
||||
if (empty($multipartData) and $formData) {
|
||||
$options['form_params'] = $formData;
|
||||
}
|
||||
|
||||
try {
|
||||
if (null !== $this->awsCredentials) {
|
||||
$response = $this->client->send($this->awsSignature->signRequest($guzzleRequest, $this->awsCredentials), $options);
|
||||
} else {
|
||||
$response = $this->client->send($guzzleRequest, $options);
|
||||
}
|
||||
} catch (RequestException $e) {
|
||||
if (!$e->hasResponse()) {
|
||||
throw $e;
|
||||
}
|
||||
$response = $e->getResponse();
|
||||
}
|
||||
return $this->createResponse($response);
|
||||
}
|
||||
|
||||
protected function extractHeaders(BrowserKitRequest $request)
|
||||
{
|
||||
$headers = [];
|
||||
$server = $request->getServer();
|
||||
|
||||
$contentHeaders = ['Content-Length' => true, 'Content-Md5' => true, 'Content-Type' => true];
|
||||
foreach ($server as $header => $val) {
|
||||
$header = html_entity_decode(implode('-', array_map('ucfirst', explode('-', strtolower(str_replace('_', '-', $header))))), ENT_NOQUOTES);
|
||||
if (strpos($header, 'Http-') === 0) {
|
||||
$headers[substr($header, 5)] = $val;
|
||||
} elseif (isset($contentHeaders[$header])) {
|
||||
$headers[$header] = $val;
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
|
||||
protected function extractFormData(BrowserKitRequest $request)
|
||||
{
|
||||
if (!in_array(strtoupper($request->getMethod()), ['POST', 'PUT', 'PATCH', 'DELETE'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// guessing if it is a form data
|
||||
$headers = $request->getServer();
|
||||
if (isset($headers['HTTP_CONTENT_TYPE'])) {
|
||||
// not a form
|
||||
if ($headers['HTTP_CONTENT_TYPE'] !== 'application/x-www-form-urlencoded') {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if ($request->getContent() !== null) {
|
||||
return null;
|
||||
}
|
||||
return $request->getParameters();
|
||||
}
|
||||
|
||||
protected function extractMultipartFormData(Request $request)
|
||||
{
|
||||
if (!in_array(strtoupper($request->getMethod()), ['POST', 'PUT', 'PATCH'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$parts = $this->mapFiles($request->getFiles());
|
||||
if (empty($parts)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
foreach ($request->getParameters() as $k => $v) {
|
||||
$parts = $this->formatMultipart($parts, $k, $v);
|
||||
}
|
||||
return $parts;
|
||||
}
|
||||
|
||||
protected function formatMultipart($parts, $key, $value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $subKey => $subValue) {
|
||||
$parts = array_merge($this->formatMultipart([], $key."[$subKey]", $subValue), $parts);
|
||||
}
|
||||
return $parts;
|
||||
}
|
||||
$parts[] = ['name' => $key, 'contents' => (string) $value];
|
||||
return $parts;
|
||||
}
|
||||
|
||||
protected function mapFiles($requestFiles, $arrayName = '')
|
||||
{
|
||||
$files = [];
|
||||
foreach ($requestFiles as $name => $info) {
|
||||
if (!empty($arrayName)) {
|
||||
$name = $arrayName . '[' . $name . ']';
|
||||
}
|
||||
|
||||
if (is_array($info)) {
|
||||
if (isset($info['tmp_name'])) {
|
||||
if ($info['tmp_name']) {
|
||||
$handle = fopen($info['tmp_name'], 'r');
|
||||
$filename = isset($info['name']) ? $info['name'] : null;
|
||||
|
||||
$files[] = [
|
||||
'name' => $name,
|
||||
'contents' => $handle,
|
||||
'filename' => $filename
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$files = array_merge($files, $this->mapFiles($info, $name));
|
||||
}
|
||||
} else {
|
||||
$files[] = [
|
||||
'name' => $name,
|
||||
'contents' => fopen($info, 'r')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
protected function extractCookies($host)
|
||||
{
|
||||
$jar = [];
|
||||
$cookies = $this->getCookieJar()->all();
|
||||
foreach ($cookies as $cookie) {
|
||||
/** @var $cookie Cookie **/
|
||||
$setCookie = SetCookie::fromString((string)$cookie);
|
||||
if (!$setCookie->getDomain()) {
|
||||
$setCookie->setDomain($host);
|
||||
}
|
||||
$jar[] = $setCookie;
|
||||
}
|
||||
return new CookieJar(false, $jar);
|
||||
}
|
||||
|
||||
public static function createHandler($handler)
|
||||
{
|
||||
if ($handler === 'curl') {
|
||||
return HandlerStack::create(new CurlHandler());
|
||||
}
|
||||
if ($handler === 'stream') {
|
||||
return HandlerStack::create(new StreamHandler());
|
||||
}
|
||||
if (class_exists($handler)) {
|
||||
return HandlerStack::create(new $handler);
|
||||
}
|
||||
if (is_callable($handler)) {
|
||||
return HandlerStack::create($handler);
|
||||
}
|
||||
return HandlerStack::create();
|
||||
}
|
||||
|
||||
public function setAwsAuth($config)
|
||||
{
|
||||
$this->awsCredentials = new Credentials($config['key'], $config['secret']);
|
||||
$this->awsSignature = new SignatureV4($config['service'], $config['region']);
|
||||
}
|
||||
}
|
||||
354
vendor/codeception/base/src/Codeception/Lib/Connector/Laravel5.php
vendored
Normal file
354
vendor/codeception/base/src/Codeception/Lib/Connector/Laravel5.php
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector;
|
||||
|
||||
use Codeception\Lib\Connector\Laravel5\ExceptionHandlerDecorator;
|
||||
use Codeception\Lib\Connector\Shared\LaravelCommon;
|
||||
use Codeception\Stub;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Client;
|
||||
|
||||
class Laravel5 extends Client
|
||||
{
|
||||
use LaravelCommon;
|
||||
|
||||
/**
|
||||
* @var Application
|
||||
*/
|
||||
private $app;
|
||||
|
||||
/**
|
||||
* @var \Codeception\Module\Laravel5
|
||||
*/
|
||||
private $module;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $firstRequest = true;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $triggeredEvents = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $exceptionHandlingDisabled;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $middlewareDisabled;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $eventsDisabled;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $modelEventsDisabled;
|
||||
|
||||
/**
|
||||
* @var object
|
||||
*/
|
||||
private $oldDb;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Codeception\Module\Laravel5 $module
|
||||
*/
|
||||
public function __construct($module)
|
||||
{
|
||||
$this->module = $module;
|
||||
|
||||
$this->exceptionHandlingDisabled = $this->module->config['disable_exception_handling'];
|
||||
$this->middlewareDisabled = $this->module->config['disable_middleware'];
|
||||
$this->eventsDisabled = $this->module->config['disable_events'];
|
||||
$this->modelEventsDisabled = $this->module->config['disable_model_events'];
|
||||
|
||||
$this->initialize();
|
||||
|
||||
$components = parse_url($this->app['config']->get('app.url', 'http://localhost'));
|
||||
if (array_key_exists('url', $this->module->config)) {
|
||||
$components = parse_url($this->module->config['url']);
|
||||
}
|
||||
$host = isset($components['host']) ? $components['host'] : 'localhost';
|
||||
|
||||
parent::__construct($this->app, ['HTTP_HOST' => $host]);
|
||||
|
||||
// Parent constructor defaults to not following redirects
|
||||
$this->followRedirects(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a request.
|
||||
*
|
||||
* @param SymfonyRequest $request
|
||||
* @return Response
|
||||
*/
|
||||
protected function doRequest($request)
|
||||
{
|
||||
if (!$this->firstRequest) {
|
||||
$this->initialize($request);
|
||||
}
|
||||
$this->firstRequest = false;
|
||||
|
||||
$this->applyBindings();
|
||||
$this->applyContextualBindings();
|
||||
$this->applyInstances();
|
||||
$this->applyApplicationHandlers();
|
||||
|
||||
$request = Request::createFromBase($request);
|
||||
$response = $this->kernel->handle($request);
|
||||
$this->app->make('Illuminate\Contracts\Http\Kernel')->terminate($request, $response);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure files are \Illuminate\Http\UploadedFile instances with the private $test property set to true.
|
||||
* Fixes issue https://github.com/Codeception/Codeception/pull/3417.
|
||||
*
|
||||
* @param array $files
|
||||
* @return array
|
||||
*/
|
||||
protected function filterFiles(array $files)
|
||||
{
|
||||
$files = parent::filterFiles($files);
|
||||
|
||||
if (! class_exists('Illuminate\Http\UploadedFile')) {
|
||||
// The \Illuminate\Http\UploadedFile class was introduced in Laravel 5.2.15,
|
||||
// so don't change the $files array if it does not exist.
|
||||
return $files;
|
||||
}
|
||||
|
||||
return $this->convertToTestFiles($files);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return array
|
||||
*/
|
||||
private function convertToTestFiles(array $files)
|
||||
{
|
||||
$filtered = [];
|
||||
|
||||
foreach ($files as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$filtered[$key] = $this->convertToTestFiles($value);
|
||||
} else {
|
||||
$filtered[$key] = UploadedFile::createFromBase($value, true);
|
||||
}
|
||||
}
|
||||
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Laravel framework.
|
||||
*
|
||||
* @param SymfonyRequest $request
|
||||
*/
|
||||
private function initialize($request = null)
|
||||
{
|
||||
// Store a reference to the database object
|
||||
// so the database connection can be reused during tests
|
||||
$this->oldDb = null;
|
||||
if (isset($this->app['db']) && $this->app['db']->connection()) {
|
||||
$this->oldDb = $this->app['db'];
|
||||
}
|
||||
|
||||
$this->app = $this->kernel = $this->loadApplication();
|
||||
|
||||
// Set the request instance for the application,
|
||||
if (is_null($request)) {
|
||||
$appConfig = require $this->module->config['project_dir'] . 'config/app.php';
|
||||
$request = SymfonyRequest::create($appConfig['url']);
|
||||
}
|
||||
$this->app->instance('request', Request::createFromBase($request));
|
||||
|
||||
// Reset the old database after all the service providers are registered.
|
||||
if ($this->oldDb) {
|
||||
$this->app['events']->listen('bootstrapped: Illuminate\Foundation\Bootstrap\RegisterProviders', function () {
|
||||
$this->app->singleton('db', function () {
|
||||
return $this->oldDb;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$this->app->make('Illuminate\Contracts\Http\Kernel')->bootstrap();
|
||||
|
||||
// Record all triggered events by adding a wildcard event listener
|
||||
// Since Laravel 5.4 wildcard event handlers receive the event name as the first argument,
|
||||
// but for earlier Laravel versions the firing() method of the event dispatcher should be used
|
||||
// to determine the event name.
|
||||
if (method_exists($this->app['events'], 'firing')) {
|
||||
$listener = function () {
|
||||
$this->triggeredEvents[] = $this->normalizeEvent($this->app['events']->firing());
|
||||
};
|
||||
} else {
|
||||
$listener = function ($event) {
|
||||
$this->triggeredEvents[] = $this->normalizeEvent($event);
|
||||
};
|
||||
}
|
||||
$this->app['events']->listen('*', $listener);
|
||||
|
||||
// Replace the Laravel exception handler with our decorated exception handler,
|
||||
// so exceptions can be intercepted for the disable_exception_handling functionality.
|
||||
$decorator = new ExceptionHandlerDecorator($this->app['Illuminate\Contracts\Debug\ExceptionHandler']);
|
||||
$decorator->exceptionHandlingDisabled($this->exceptionHandlingDisabled);
|
||||
$this->app->instance('Illuminate\Contracts\Debug\ExceptionHandler', $decorator);
|
||||
|
||||
if ($this->module->config['disable_middleware'] || $this->middlewareDisabled) {
|
||||
$this->app->instance('middleware.disable', true);
|
||||
}
|
||||
|
||||
if ($this->module->config['disable_events'] || $this->eventsDisabled) {
|
||||
$this->mockEventDispatcher();
|
||||
}
|
||||
|
||||
if ($this->module->config['disable_model_events'] || $this->modelEventsDisabled) {
|
||||
Model::unsetEventDispatcher();
|
||||
}
|
||||
|
||||
$this->module->setApplication($this->app);
|
||||
}
|
||||
|
||||
/**
|
||||
* Boot the Laravel application object.
|
||||
* @return Application
|
||||
* @throws ModuleConfig
|
||||
*/
|
||||
private function loadApplication()
|
||||
{
|
||||
$app = require $this->module->config['bootstrap_file'];
|
||||
$app->loadEnvironmentFrom($this->module->config['environment_file']);
|
||||
$app->instance('request', new Request());
|
||||
|
||||
return $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the Laravel event dispatcher with a mock.
|
||||
*/
|
||||
private function mockEventDispatcher()
|
||||
{
|
||||
// Even if events are disabled we still want to record the triggered events.
|
||||
// But by mocking the event dispatcher the wildcard listener registered in the initialize method is removed.
|
||||
// So to record the triggered events we have to catch the calls to the fire method of the event dispatcher mock.
|
||||
$callback = function ($event) {
|
||||
$this->triggeredEvents[] = $this->normalizeEvent($event);
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
// In Laravel 5.4 the Illuminate\Contracts\Events\Dispatcher interface was changed,
|
||||
// the 'fire' method was renamed to 'dispatch'. This code determines the correct method to mock.
|
||||
$method = method_exists($this->app['events'], 'dispatch') ? 'dispatch' : 'fire';
|
||||
|
||||
$mock = Stub::makeEmpty('Illuminate\Contracts\Events\Dispatcher', [
|
||||
$method => $callback
|
||||
]);
|
||||
|
||||
$this->app->instance('events', $mock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize events to class names.
|
||||
*
|
||||
* @param $event
|
||||
* @return string
|
||||
*/
|
||||
private function normalizeEvent($event)
|
||||
{
|
||||
if (is_object($event)) {
|
||||
$event = get_class($event);
|
||||
}
|
||||
|
||||
if (preg_match('/^bootstrapp(ing|ed): /', $event)) {
|
||||
return $event;
|
||||
}
|
||||
|
||||
// Events can be formatted as 'event.name: parameters'
|
||||
$segments = explode(':', $event);
|
||||
|
||||
return $segments[0];
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Public methods called by module
|
||||
//======================================================================
|
||||
|
||||
/**
|
||||
* Did an event trigger?
|
||||
*
|
||||
* @param $event
|
||||
* @return bool
|
||||
*/
|
||||
public function eventTriggered($event)
|
||||
{
|
||||
$event = $this->normalizeEvent($event);
|
||||
|
||||
foreach ($this->triggeredEvents as $triggeredEvent) {
|
||||
if ($event == $triggeredEvent || is_subclass_of($event, $triggeredEvent)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable Laravel exception handling.
|
||||
*/
|
||||
public function disableExceptionHandling()
|
||||
{
|
||||
$this->exceptionHandlingDisabled = true;
|
||||
$this->app['Illuminate\Contracts\Debug\ExceptionHandler']->exceptionHandlingDisabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Laravel exception handling.
|
||||
*/
|
||||
public function enableExceptionHandling()
|
||||
{
|
||||
$this->exceptionHandlingDisabled = false;
|
||||
$this->app['Illuminate\Contracts\Debug\ExceptionHandler']->exceptionHandlingDisabled(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable events.
|
||||
*/
|
||||
public function disableEvents()
|
||||
{
|
||||
$this->eventsDisabled = true;
|
||||
$this->mockEventDispatcher();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable model events.
|
||||
*/
|
||||
public function disableModelEvents()
|
||||
{
|
||||
$this->modelEventsDisabled = true;
|
||||
Model::unsetEventDispatcher();
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable middleware.
|
||||
*/
|
||||
public function disableMiddleware()
|
||||
{
|
||||
$this->middlewareDisabled = true;
|
||||
$this->app->instance('middleware.disable', true);
|
||||
}
|
||||
}
|
||||
106
vendor/codeception/base/src/Codeception/Lib/Connector/Laravel5/ExceptionHandlerDecorator.php
vendored
Normal file
106
vendor/codeception/base/src/Codeception/Lib/Connector/Laravel5/ExceptionHandlerDecorator.php
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector\Laravel5;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandlerContract;
|
||||
|
||||
/**
|
||||
* Class ExceptionHandlerDecorator
|
||||
*
|
||||
* @package Codeception\Lib\Connector\Laravel5
|
||||
*/
|
||||
class ExceptionHandlerDecorator implements ExceptionHandlerContract
|
||||
{
|
||||
/**
|
||||
* @var ExceptionHandlerContract
|
||||
*/
|
||||
private $laravelExceptionHandler;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
private $exceptionHandlingDisabled = true;
|
||||
|
||||
/**
|
||||
* ExceptionHandlerDecorator constructor.
|
||||
*
|
||||
* @param object $laravelExceptionHandler
|
||||
*/
|
||||
public function __construct($laravelExceptionHandler)
|
||||
{
|
||||
$this->laravelExceptionHandler = $laravelExceptionHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $exceptionHandlingDisabled
|
||||
*/
|
||||
public function exceptionHandlingDisabled($exceptionHandlingDisabled)
|
||||
{
|
||||
$this->exceptionHandlingDisabled = $exceptionHandlingDisabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report or log an exception.
|
||||
*
|
||||
* @param \Exception $e
|
||||
* @return void
|
||||
*/
|
||||
public function report(Exception $e)
|
||||
{
|
||||
$this->laravelExceptionHandler->report($e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $request
|
||||
* @param Exception $e
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* @throws Exception
|
||||
*/
|
||||
public function render($request, Exception $e)
|
||||
{
|
||||
$response = $this->laravelExceptionHandler->render($request, $e);
|
||||
|
||||
if ($this->exceptionHandlingDisabled && $this->isSymfonyExceptionHandlerOutput($response->getContent())) {
|
||||
// If content was generated by the \Symfony\Component\Debug\ExceptionHandler class
|
||||
// the Laravel application could not handle the exception,
|
||||
// so re-throw this exception if the Codeception user disabled Laravel's exception handling.
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the response content is HTML output of the Symfony exception handler class.
|
||||
*
|
||||
* @param string $content
|
||||
* @return bool
|
||||
*/
|
||||
private function isSymfonyExceptionHandlerOutput($content)
|
||||
{
|
||||
return strpos($content, '<div id="sf-resetcontent" class="sf-reset">') !== false ||
|
||||
strpos($content, '<div class="exception-summary">') !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an exception to the console.
|
||||
*
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @param \Exception $e
|
||||
* @return void
|
||||
*/
|
||||
public function renderForConsole($output, Exception $e)
|
||||
{
|
||||
$this->laravelExceptionHandler->renderForConsole($output, $e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
return call_user_func_array([$this->laravelExceptionHandler, $method], $args);
|
||||
}
|
||||
}
|
||||
167
vendor/codeception/base/src/Codeception/Lib/Connector/Lumen.php
vendored
Normal file
167
vendor/codeception/base/src/Codeception/Lib/Connector/Lumen.php
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector;
|
||||
|
||||
use Codeception\Lib\Connector\Lumen\DummyKernel;
|
||||
use Codeception\Lib\Connector\Shared\LaravelCommon;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Client;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
|
||||
class Lumen extends Client
|
||||
{
|
||||
use LaravelCommon;
|
||||
|
||||
/**
|
||||
* @var \Laravel\Lumen\Application
|
||||
*/
|
||||
private $app;
|
||||
|
||||
/**
|
||||
* @var \Codeception\Module\Lumen
|
||||
*/
|
||||
private $module;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $firstRequest = true;
|
||||
|
||||
/**
|
||||
* @var object
|
||||
*/
|
||||
private $oldDb;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Codeception\Module\Lumen $module
|
||||
*/
|
||||
public function __construct($module)
|
||||
{
|
||||
$this->module = $module;
|
||||
|
||||
$components = parse_url($this->module->config['url']);
|
||||
$server = ['HTTP_HOST' => $components['host']];
|
||||
|
||||
// Pass a DummyKernel to satisfy the arguments of the parent constructor.
|
||||
// The actual kernel object is set in the initialize() method.
|
||||
parent::__construct(new DummyKernel(), $server);
|
||||
|
||||
// Parent constructor defaults to not following redirects
|
||||
$this->followRedirects(true);
|
||||
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a request.
|
||||
*
|
||||
* @param SymfonyRequest $request
|
||||
* @return Response
|
||||
*/
|
||||
protected function doRequest($request)
|
||||
{
|
||||
if (!$this->firstRequest) {
|
||||
$this->initialize($request);
|
||||
}
|
||||
$this->firstRequest = false;
|
||||
|
||||
$this->applyBindings();
|
||||
$this->applyContextualBindings();
|
||||
$this->applyInstances();
|
||||
$this->applyApplicationHandlers();
|
||||
|
||||
$request = Request::createFromBase($request);
|
||||
$response = $this->kernel->handle($request);
|
||||
|
||||
$method = new \ReflectionMethod(get_class($this->app), 'callTerminableMiddleware');
|
||||
$method->setAccessible(true);
|
||||
$method->invoke($this->app, $response);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Lumen framework.
|
||||
*
|
||||
* @param SymfonyRequest|null $request
|
||||
*/
|
||||
private function initialize($request = null)
|
||||
{
|
||||
// Store a reference to the database object
|
||||
// so the database connection can be reused during tests
|
||||
$this->oldDb = null;
|
||||
if (isset($this->app['db']) && $this->app['db']->connection()) {
|
||||
$this->oldDb = $this->app['db'];
|
||||
}
|
||||
|
||||
if (class_exists(Facade::class)) {
|
||||
// If the container has been instantiated ever,
|
||||
// we need to clear its static fields before create new container.
|
||||
Facade::clearResolvedInstances();
|
||||
}
|
||||
|
||||
$this->app = $this->kernel = require $this->module->config['bootstrap_file'];
|
||||
|
||||
// Lumen registers necessary bindings on demand when calling $app->make(),
|
||||
// so here we force the request binding before registering our own request object,
|
||||
// otherwise Lumen will overwrite our request object.
|
||||
$this->app->make('request');
|
||||
|
||||
$request = $request ?: SymfonyRequest::create($this->module->config['url']);
|
||||
$this->app->instance('Illuminate\Http\Request', Request::createFromBase($request));
|
||||
|
||||
// Reset the old database if there is one
|
||||
if ($this->oldDb) {
|
||||
$this->app->singleton('db', function () {
|
||||
return $this->oldDb;
|
||||
});
|
||||
Model::setConnectionResolver($this->oldDb);
|
||||
}
|
||||
|
||||
$this->module->setApplication($this->app);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure files are \Illuminate\Http\UploadedFile instances with the private $test property set to true.
|
||||
* Fixes issue https://github.com/Codeception/Codeception/pull/3417.
|
||||
*
|
||||
* @param array $files
|
||||
* @return array
|
||||
*/
|
||||
protected function filterFiles(array $files)
|
||||
{
|
||||
$files = parent::filterFiles($files);
|
||||
|
||||
if (! class_exists('Illuminate\Http\UploadedFile')) {
|
||||
// The \Illuminate\Http\UploadedFile class was introduced in Laravel 5.2.15,
|
||||
// so don't change the $files array if it does not exist.
|
||||
return $files;
|
||||
}
|
||||
|
||||
return $this->convertToTestFiles($files);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return array
|
||||
*/
|
||||
private function convertToTestFiles(array $files)
|
||||
{
|
||||
$filtered = [];
|
||||
|
||||
foreach ($files as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$filtered[$key] = $this->convertToTestFiles($value);
|
||||
} else {
|
||||
$filtered[$key] = UploadedFile::createFromBase($value, true);
|
||||
}
|
||||
}
|
||||
|
||||
return $filtered;
|
||||
}
|
||||
}
|
||||
16
vendor/codeception/base/src/Codeception/Lib/Connector/Lumen/DummyKernel.php
vendored
Normal file
16
vendor/codeception/base/src/Codeception/Lib/Connector/Lumen/DummyKernel.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector\Lumen;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
|
||||
/**
|
||||
* Dummy kernel to satisfy the parent constructor of the LumenConnector class.
|
||||
*/
|
||||
class DummyKernel implements HttpKernelInterface
|
||||
{
|
||||
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
159
vendor/codeception/base/src/Codeception/Lib/Connector/Phalcon.php
vendored
Normal file
159
vendor/codeception/base/src/Codeception/Lib/Connector/Phalcon.php
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector;
|
||||
|
||||
use Closure;
|
||||
use Phalcon\Di;
|
||||
use Phalcon\Http;
|
||||
use RuntimeException;
|
||||
use ReflectionProperty;
|
||||
use Codeception\Util\Stub;
|
||||
use Phalcon\Mvc\Application;
|
||||
use Symfony\Component\BrowserKit\Cookie;
|
||||
use Symfony\Component\BrowserKit\Client;
|
||||
use Phalcon\Mvc\Micro as MicroApplication;
|
||||
use Symfony\Component\BrowserKit\Response;
|
||||
use Codeception\Lib\Connector\Shared\PhpSuperGlobalsConverter;
|
||||
|
||||
class Phalcon extends Client
|
||||
{
|
||||
use PhpSuperGlobalsConverter;
|
||||
|
||||
/**
|
||||
* Phalcon Application
|
||||
* @var mixed
|
||||
*/
|
||||
private $application;
|
||||
|
||||
/**
|
||||
* Set Phalcon Application by \Phalcon\DI\Injectable, Closure or bootstrap file path
|
||||
*
|
||||
* @param mixed $application
|
||||
*/
|
||||
public function setApplication($application)
|
||||
{
|
||||
$this->application = $application;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Phalcon Application
|
||||
*
|
||||
* @return Application|MicroApplication
|
||||
*/
|
||||
public function getApplication()
|
||||
{
|
||||
$application = $this->application;
|
||||
|
||||
if ($application instanceof Closure) {
|
||||
return $application();
|
||||
} elseif (is_string($application)) {
|
||||
/** @noinspection PhpIncludeInspection */
|
||||
return require $application;
|
||||
}
|
||||
|
||||
return $application;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request.
|
||||
*
|
||||
* @param \Symfony\Component\BrowserKit\Request $request
|
||||
*
|
||||
* @return \Symfony\Component\BrowserKit\Response
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function doRequest($request)
|
||||
{
|
||||
$application = $this->getApplication();
|
||||
if (!$application instanceof Application && !$application instanceof MicroApplication) {
|
||||
throw new RuntimeException('Unsupported application class.');
|
||||
}
|
||||
|
||||
$di = $application->getDI();
|
||||
/** @var Http\Request $phRequest */
|
||||
if ($di->has('request')) {
|
||||
$phRequest = $di->get('request');
|
||||
}
|
||||
|
||||
if (!$phRequest instanceof Http\RequestInterface) {
|
||||
$phRequest = new Http\Request();
|
||||
}
|
||||
|
||||
$uri = $request->getUri() ?: $phRequest->getURI();
|
||||
$pathString = parse_url($uri, PHP_URL_PATH);
|
||||
$queryString = parse_url($uri, PHP_URL_QUERY);
|
||||
|
||||
$_SERVER = $request->getServer();
|
||||
$_SERVER['REQUEST_METHOD'] = strtoupper($request->getMethod());
|
||||
$_SERVER['REQUEST_URI'] = null === $queryString ? $pathString : $pathString . '?' . $queryString;
|
||||
|
||||
$_COOKIE = $request->getCookies();
|
||||
$_FILES = $this->remapFiles($request->getFiles());
|
||||
$_REQUEST = $this->remapRequestParameters($request->getParameters());
|
||||
$_POST = [];
|
||||
$_GET = [];
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
|
||||
$_GET = $_REQUEST;
|
||||
} else {
|
||||
$_POST = $_REQUEST;
|
||||
}
|
||||
|
||||
parse_str($queryString, $output);
|
||||
foreach ($output as $k => $v) {
|
||||
$_GET[$k] = $v;
|
||||
}
|
||||
|
||||
$_GET['_url'] = $pathString;
|
||||
$_SERVER['QUERY_STRING'] = http_build_query($_GET);
|
||||
|
||||
Di::reset();
|
||||
Di::setDefault($di);
|
||||
|
||||
$di['request'] = Stub::construct($phRequest, [], ['getRawBody' => $request->getContent()]);
|
||||
|
||||
$response = $application->handle();
|
||||
if (!$response instanceof Http\ResponseInterface) {
|
||||
$response = $application->response;
|
||||
}
|
||||
|
||||
$headers = $response->getHeaders();
|
||||
$status = (int) $headers->get('Status');
|
||||
|
||||
$headersProperty = new ReflectionProperty($headers, '_headers');
|
||||
$headersProperty->setAccessible(true);
|
||||
$headers = $headersProperty->getValue($headers);
|
||||
if (!is_array($headers)) {
|
||||
$headers = [];
|
||||
}
|
||||
|
||||
$cookiesProperty = new ReflectionProperty($di['cookies'], '_cookies');
|
||||
$cookiesProperty->setAccessible(true);
|
||||
$cookies = $cookiesProperty->getValue($di['cookies']);
|
||||
if (is_array($cookies)) {
|
||||
$restoredProperty = new ReflectionProperty('\Phalcon\Http\Cookie', '_restored');
|
||||
$restoredProperty->setAccessible(true);
|
||||
$valueProperty = new ReflectionProperty('\Phalcon\Http\Cookie', '_value');
|
||||
$valueProperty->setAccessible(true);
|
||||
foreach ($cookies as $name => $cookie) {
|
||||
if (!$restoredProperty->getValue($cookie)) {
|
||||
$clientCookie = new Cookie(
|
||||
$name,
|
||||
$valueProperty->getValue($cookie),
|
||||
$cookie->getExpiration(),
|
||||
$cookie->getPath(),
|
||||
$cookie->getDomain(),
|
||||
$cookie->getSecure(),
|
||||
$cookie->getHttpOnly()
|
||||
);
|
||||
$headers['Set-Cookie'][] = (string)$clientCookie;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(
|
||||
$response->getContent(),
|
||||
$status ? $status : 200,
|
||||
$headers
|
||||
);
|
||||
}
|
||||
}
|
||||
309
vendor/codeception/base/src/Codeception/Lib/Connector/Phalcon/MemorySession.php
vendored
Normal file
309
vendor/codeception/base/src/Codeception/Lib/Connector/Phalcon/MemorySession.php
vendored
Normal file
@@ -0,0 +1,309 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector\Phalcon;
|
||||
|
||||
use Phalcon\Session\AdapterInterface;
|
||||
|
||||
class MemorySession implements AdapterInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $sessionId;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $started = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $memory = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [];
|
||||
|
||||
public function __construct(array $options = null)
|
||||
{
|
||||
$this->sessionId = $this->generateId();
|
||||
|
||||
if (is_array($options)) {
|
||||
$this->setOptions($options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function start()
|
||||
{
|
||||
if ($this->status() !== PHP_SESSION_ACTIVE) {
|
||||
$this->memory = [];
|
||||
$this->started = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function setOptions(array $options)
|
||||
{
|
||||
if (isset($options['uniqueId'])) {
|
||||
$this->sessionId = $options['uniqueId'];
|
||||
}
|
||||
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @param string $index
|
||||
* @param mixed $defaultValue
|
||||
* @param bool $remove
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($index, $defaultValue = null, $remove = false)
|
||||
{
|
||||
$key = $this->prepareIndex($index);
|
||||
|
||||
if (!isset($this->memory[$key])) {
|
||||
return $defaultValue;
|
||||
}
|
||||
|
||||
$return = $this->memory[$key];
|
||||
|
||||
if ($remove) {
|
||||
unset($this->memory[$key]);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @param string $index
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function set($index, $value)
|
||||
{
|
||||
$this->memory[$this->prepareIndex($index)] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @param string $index
|
||||
* @return bool
|
||||
*/
|
||||
public function has($index)
|
||||
{
|
||||
return isset($this->memory[$this->prepareIndex($index)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @param string $index
|
||||
*/
|
||||
public function remove($index)
|
||||
{
|
||||
unset($this->memory[$this->prepareIndex($index)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isStarted()
|
||||
{
|
||||
return $this->started;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the current session
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* if ($session->status() !== PHP_SESSION_ACTIVE) {
|
||||
* $session->start();
|
||||
* }
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function status()
|
||||
{
|
||||
if ($this->isStarted()) {
|
||||
return PHP_SESSION_ACTIVE;
|
||||
}
|
||||
|
||||
return PHP_SESSION_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @param bool $removeData
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy($removeData = false)
|
||||
{
|
||||
if ($removeData) {
|
||||
if (!empty($this->sessionId)) {
|
||||
foreach ($this->memory as $key => $value) {
|
||||
if (0 === strpos($key, $this->sessionId . '#')) {
|
||||
unset($this->memory[$key]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->memory = [];
|
||||
}
|
||||
}
|
||||
|
||||
$this->started = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @param bool $deleteOldSession
|
||||
* @return \Phalcon\Session\AdapterInterface
|
||||
*/
|
||||
public function regenerateId($deleteOldSession = true)
|
||||
{
|
||||
$this->sessionId = $this->generateId();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump all session
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return (array) $this->memory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias: Gets a session variable from an application context
|
||||
*
|
||||
* @param string $index
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($index)
|
||||
{
|
||||
return $this->get($index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias: Sets a session variable in an application context
|
||||
*
|
||||
* @param string $index
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __set($index, $value)
|
||||
{
|
||||
$this->set($index, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias: Check whether a session variable is set in an application context
|
||||
*
|
||||
* @param string $index
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($index)
|
||||
{
|
||||
return $this->has($index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias: Removes a session variable from an application context
|
||||
*
|
||||
* @param string $index
|
||||
*/
|
||||
public function __unset($index)
|
||||
{
|
||||
$this->remove($index);
|
||||
}
|
||||
|
||||
private function prepareIndex($index)
|
||||
{
|
||||
if ($this->sessionId) {
|
||||
$key = $this->sessionId . '#' . $index;
|
||||
} else {
|
||||
$key = $index;
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function generateId()
|
||||
{
|
||||
return md5(time());
|
||||
}
|
||||
}
|
||||
139
vendor/codeception/base/src/Codeception/Lib/Connector/Shared/LaravelCommon.php
vendored
Normal file
139
vendor/codeception/base/src/Codeception/Lib/Connector/Shared/LaravelCommon.php
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector\Shared;
|
||||
|
||||
/**
|
||||
* Common functions for Laravel family
|
||||
*
|
||||
* @package Codeception\Lib\Connector\Shared
|
||||
*/
|
||||
trait LaravelCommon
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $bindings = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $contextualBindings = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $instances = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $applicationHandlers = [];
|
||||
|
||||
/**
|
||||
* Apply the registered application handlers.
|
||||
*/
|
||||
private function applyApplicationHandlers()
|
||||
{
|
||||
foreach ($this->applicationHandlers as $handler) {
|
||||
call_user_func($handler, $this->app);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the registered Laravel service container bindings.
|
||||
*/
|
||||
private function applyBindings()
|
||||
{
|
||||
foreach ($this->bindings as $abstract => $binding) {
|
||||
list($concrete, $shared) = $binding;
|
||||
|
||||
$this->app->bind($abstract, $concrete, $shared);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the registered Laravel service container contextual bindings.
|
||||
*/
|
||||
private function applyContextualBindings()
|
||||
{
|
||||
foreach ($this->contextualBindings as $concrete => $bindings) {
|
||||
foreach ($bindings as $abstract => $implementation) {
|
||||
$this->app->addContextualBinding($concrete, $abstract, $implementation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the registered Laravel service container instance bindings.
|
||||
*/
|
||||
private function applyInstances()
|
||||
{
|
||||
foreach ($this->instances as $abstract => $instance) {
|
||||
$this->app->instance($abstract, $instance);
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Public methods called by module
|
||||
//======================================================================
|
||||
|
||||
/**
|
||||
* Register a Laravel service container binding that should be applied
|
||||
* after initializing the Laravel Application object.
|
||||
*
|
||||
* @param $abstract
|
||||
* @param $concrete
|
||||
* @param bool $shared
|
||||
*/
|
||||
public function haveBinding($abstract, $concrete, $shared = false)
|
||||
{
|
||||
$this->bindings[$abstract] = [$concrete, $shared];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a Laravel service container contextual binding that should be applied
|
||||
* after initializing the Laravel Application object.
|
||||
*
|
||||
* @param $concrete
|
||||
* @param $abstract
|
||||
* @param $implementation
|
||||
*/
|
||||
public function haveContextualBinding($concrete, $abstract, $implementation)
|
||||
{
|
||||
if (! isset($this->contextualBindings[$concrete])) {
|
||||
$this->contextualBindings[$concrete] = [];
|
||||
}
|
||||
|
||||
$this->contextualBindings[$concrete][$abstract] = $implementation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a Laravel service container instance binding that should be applied
|
||||
* after initializing the Laravel Application object.
|
||||
*
|
||||
* @param $abstract
|
||||
* @param $instance
|
||||
*/
|
||||
public function haveInstance($abstract, $instance)
|
||||
{
|
||||
$this->instances[$abstract] = $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a handler than can be used to modify the Laravel application object after it is initialized.
|
||||
* The Laravel application object will be passed as an argument to the handler.
|
||||
*
|
||||
* @param $handler
|
||||
*/
|
||||
public function haveApplicationHandler($handler)
|
||||
{
|
||||
$this->applicationHandlers[] = $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the registered application handlers.
|
||||
*/
|
||||
public function clearApplicationHandlers()
|
||||
{
|
||||
$this->applicationHandlers = [];
|
||||
}
|
||||
}
|
||||
117
vendor/codeception/base/src/Codeception/Lib/Connector/Shared/PhpSuperGlobalsConverter.php
vendored
Normal file
117
vendor/codeception/base/src/Codeception/Lib/Connector/Shared/PhpSuperGlobalsConverter.php
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector\Shared;
|
||||
|
||||
/**
|
||||
* Converts BrowserKit\Request's request parameters and files into PHP-compatible structure
|
||||
*
|
||||
* @see https://bugs.php.net/bug.php?id=25589
|
||||
* @see https://bugs.php.net/bug.php?id=25589
|
||||
*
|
||||
* @package Codeception\Lib\Connector
|
||||
*/
|
||||
trait PhpSuperGlobalsConverter
|
||||
{
|
||||
/**
|
||||
* Rearrange files array to be compatible with PHP $_FILES superglobal structure
|
||||
* @see https://bugs.php.net/bug.php?id=25589
|
||||
*
|
||||
* @param array $requestFiles
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function remapFiles(array $requestFiles)
|
||||
{
|
||||
$files = $this->rearrangeFiles($requestFiles);
|
||||
|
||||
return $this->replaceSpaces($files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape high-level variable name with dots, underscores and other "special" chars
|
||||
* to be compatible with PHP "bug"
|
||||
* @see https://bugs.php.net/bug.php?id=40000
|
||||
*
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function remapRequestParameters(array $parameters)
|
||||
{
|
||||
return $this->replaceSpaces($parameters);
|
||||
}
|
||||
|
||||
private function rearrangeFiles($requestFiles)
|
||||
{
|
||||
$files = [];
|
||||
foreach ($requestFiles as $name => $info) {
|
||||
if (!is_array($info)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we have a form with fields like
|
||||
* ```
|
||||
* <input type="file" name="foo" />
|
||||
* <input type="file" name="foo[bar]" />
|
||||
* ```
|
||||
* then only array variable will be used while simple variable will be ignored in php $_FILES
|
||||
* (eg $_FILES = [
|
||||
* foo => [
|
||||
* tmp_name => [
|
||||
* 'bar' => 'asdf'
|
||||
* ],
|
||||
* //...
|
||||
* ]
|
||||
* ]
|
||||
* )
|
||||
* (notice there is no entry for file "foo", only for file "foo[bar]"
|
||||
* this will check if current element contains inner arrays within it's keys
|
||||
* so we can ignore element itself and only process inner files
|
||||
*/
|
||||
$hasInnerArrays = count(array_filter($info, 'is_array'));
|
||||
|
||||
if ($hasInnerArrays || !isset($info['tmp_name'])) {
|
||||
$inner = $this->remapFiles($info);
|
||||
foreach ($inner as $innerName => $innerInfo) {
|
||||
/**
|
||||
* Convert from ['a' => ['tmp_name' => '/tmp/test.txt'] ]
|
||||
* to ['tmp_name' => ['a' => '/tmp/test.txt'] ]
|
||||
*/
|
||||
$innerInfo = array_map(
|
||||
function ($v) use ($innerName) {
|
||||
return [$innerName => $v];
|
||||
},
|
||||
$innerInfo
|
||||
);
|
||||
|
||||
if (empty($files[$name])) {
|
||||
$files[$name] = [];
|
||||
}
|
||||
|
||||
$files[$name] = array_replace_recursive($files[$name], $innerInfo);
|
||||
}
|
||||
} else {
|
||||
$files[$name] = $info;
|
||||
}
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace spaces and dots and other chars in high-level query parameters for
|
||||
* compatibility with PHP bug (or not a bug)
|
||||
* @see https://bugs.php.net/bug.php?id=40000
|
||||
*
|
||||
* @param array $parameters Array of request parameters to be converted
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function replaceSpaces($parameters)
|
||||
{
|
||||
$qs = http_build_query($parameters, '', '&');
|
||||
parse_str($qs, $output);
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
86
vendor/codeception/base/src/Codeception/Lib/Connector/Symfony.php
vendored
Normal file
86
vendor/codeception/base/src/Codeception/Lib/Connector/Symfony.php
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector;
|
||||
|
||||
class Symfony extends \Symfony\Component\HttpKernel\Client
|
||||
{
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
private $rebootable = true;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
private $hasPerformedRequest = false;
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\DependencyInjection\ContainerInterface
|
||||
*/
|
||||
private $container = null;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $persistentServices = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Kernel $kernel A booted HttpKernel instance
|
||||
* @param array $services An injected services
|
||||
* @param boolean $rebootable
|
||||
*/
|
||||
public function __construct(\Symfony\Component\HttpKernel\Kernel $kernel, array $services = [], $rebootable = true)
|
||||
{
|
||||
parent::__construct($kernel);
|
||||
$this->followRedirects(true);
|
||||
$this->rebootable = (boolean)$rebootable;
|
||||
$this->persistentServices = $services;
|
||||
$this->rebootKernel();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
*/
|
||||
protected function doRequest($request)
|
||||
{
|
||||
if ($this->rebootable) {
|
||||
if ($this->hasPerformedRequest) {
|
||||
$this->rebootKernel();
|
||||
} else {
|
||||
$this->hasPerformedRequest = true;
|
||||
}
|
||||
}
|
||||
return parent::doRequest($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reboot kernel
|
||||
*
|
||||
* Services from the list of persistent services
|
||||
* are updated from service container before kernel shutdown
|
||||
* and injected into newly initialized container after kernel boot.
|
||||
*/
|
||||
public function rebootKernel()
|
||||
{
|
||||
if ($this->container) {
|
||||
foreach ($this->persistentServices as $serviceName => $service) {
|
||||
if ($this->container->has($serviceName)) {
|
||||
$this->persistentServices[$serviceName] = $this->container->get($serviceName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->kernel->shutdown();
|
||||
$this->kernel->boot();
|
||||
$this->container = $this->kernel->getContainer();
|
||||
|
||||
foreach ($this->persistentServices as $serviceName => $service) {
|
||||
$this->container->set($serviceName, $service);
|
||||
}
|
||||
|
||||
if ($this->container->has('profiler')) {
|
||||
$this->container->get('profiler')->enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
72
vendor/codeception/base/src/Codeception/Lib/Connector/Universal.php
vendored
Normal file
72
vendor/codeception/base/src/Codeception/Lib/Connector/Universal.php
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector;
|
||||
|
||||
use Symfony\Component\BrowserKit\Client;
|
||||
use Symfony\Component\BrowserKit\Response;
|
||||
|
||||
class Universal extends Client
|
||||
{
|
||||
use Shared\PhpSuperGlobalsConverter;
|
||||
|
||||
protected $mockedResponse;
|
||||
protected $index;
|
||||
|
||||
public function setIndex($index)
|
||||
{
|
||||
$this->index = $index;
|
||||
}
|
||||
|
||||
public function mockResponse($response)
|
||||
{
|
||||
$this->mockedResponse = $response;
|
||||
}
|
||||
|
||||
public function doRequest($request)
|
||||
{
|
||||
if ($this->mockedResponse) {
|
||||
$response = $this->mockedResponse;
|
||||
$this->mockedResponse = null;
|
||||
return $response;
|
||||
}
|
||||
|
||||
$_COOKIE = $request->getCookies();
|
||||
$_SERVER = $request->getServer();
|
||||
$_FILES = $this->remapFiles($request->getFiles());
|
||||
|
||||
$uri = str_replace('http://localhost', '', $request->getUri());
|
||||
|
||||
$_REQUEST = $this->remapRequestParameters($request->getParameters());
|
||||
if (strtoupper($request->getMethod()) == 'GET') {
|
||||
$_GET = $_REQUEST;
|
||||
} else {
|
||||
$_POST = $_REQUEST;
|
||||
}
|
||||
|
||||
$_SERVER['REQUEST_METHOD'] = strtoupper($request->getMethod());
|
||||
$_SERVER['REQUEST_URI'] = $uri;
|
||||
|
||||
ob_start();
|
||||
include $this->index;
|
||||
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
$headers = [];
|
||||
$php_headers = headers_list();
|
||||
foreach ($php_headers as $value) {
|
||||
// Get the header name
|
||||
$parts = explode(':', $value);
|
||||
if (count($parts) > 1) {
|
||||
$name = trim(array_shift($parts));
|
||||
// Build the header hash map
|
||||
$headers[$name] = trim(implode(':', $parts));
|
||||
}
|
||||
}
|
||||
$headers['Content-type'] = isset($headers['Content-type'])
|
||||
? $headers['Content-type']
|
||||
: "text/html; charset=UTF-8";
|
||||
|
||||
$response = new Response($content, 200, $headers);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
147
vendor/codeception/base/src/Codeception/Lib/Connector/Yii1.php
vendored
Normal file
147
vendor/codeception/base/src/Codeception/Lib/Connector/Yii1.php
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector;
|
||||
|
||||
use Codeception\Util\Stub;
|
||||
use Symfony\Component\BrowserKit\Client;
|
||||
use Symfony\Component\BrowserKit\Response;
|
||||
|
||||
class Yii1 extends Client
|
||||
{
|
||||
use Shared\PhpSuperGlobalsConverter;
|
||||
/**
|
||||
* http://localhost/path/to/your/app/index.php
|
||||
* @var string url of the entry Yii script
|
||||
*/
|
||||
public $url;
|
||||
|
||||
/**
|
||||
* Current application settings {@see Codeception\Module\Yii1::$appSettings}
|
||||
* @var array
|
||||
*/
|
||||
public $appSettings;
|
||||
|
||||
/**
|
||||
* Full path to your application
|
||||
* @var string
|
||||
*/
|
||||
public $appPath;
|
||||
|
||||
/**
|
||||
* Current request headers
|
||||
* @var array
|
||||
*/
|
||||
private $headers;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param \Symfony\Component\BrowserKit\Request $request
|
||||
*
|
||||
* @return \Symfony\Component\BrowserKit\Response
|
||||
*/
|
||||
public function doRequest($request)
|
||||
{
|
||||
$this->headers = [];
|
||||
$_COOKIE = array_merge($_COOKIE, $request->getCookies());
|
||||
$_SERVER = array_merge($_SERVER, $request->getServer());
|
||||
$_FILES = $this->remapFiles($request->getFiles());
|
||||
$_REQUEST = $this->remapRequestParameters($request->getParameters());
|
||||
$_POST = $_GET = [];
|
||||
|
||||
if (strtoupper($request->getMethod()) == 'GET') {
|
||||
$_GET = $_REQUEST;
|
||||
} else {
|
||||
$_POST = $_REQUEST;
|
||||
}
|
||||
|
||||
// Parse url parts
|
||||
$uriPath = ltrim(parse_url($request->getUri(), PHP_URL_PATH), '/');
|
||||
$uriQuery = ltrim(parse_url($request->getUri(), PHP_URL_QUERY), '?');
|
||||
$scriptName = trim(parse_url($this->url, PHP_URL_PATH), '/');
|
||||
if (!empty($uriQuery)) {
|
||||
$uriPath .= "?{$uriQuery}";
|
||||
|
||||
parse_str($uriQuery, $params);
|
||||
foreach ($params as $k => $v) {
|
||||
$_GET[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
// Add script name to request if none
|
||||
if ($scriptName and strpos($uriPath, $scriptName) === false) {
|
||||
$uriPath = "/{$scriptName}/{$uriPath}";
|
||||
}
|
||||
|
||||
// Add forward slash if not exists
|
||||
if (strpos($uriPath, '/') !== 0) {
|
||||
$uriPath = "/{$uriPath}";
|
||||
}
|
||||
|
||||
$_SERVER['REQUEST_METHOD'] = strtoupper($request->getMethod());
|
||||
$_SERVER['REQUEST_URI'] = $uriPath;
|
||||
|
||||
/**
|
||||
* Hack to be sure that CHttpRequest will resolve route correctly
|
||||
*/
|
||||
$_SERVER['SCRIPT_NAME'] = "/{$scriptName}";
|
||||
$_SERVER['SCRIPT_FILENAME'] = $this->appPath;
|
||||
|
||||
ob_start();
|
||||
\Yii::setApplication(null);
|
||||
\Yii::createApplication($this->appSettings['class'], $this->appSettings['config']);
|
||||
|
||||
$app = \Yii::app();
|
||||
// disabling logging. Logs slow down test execution
|
||||
if ($app->hasComponent('log')) {
|
||||
foreach ($app->getComponent('log')->routes as $route) {
|
||||
$route->enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($app->hasComponent('session')) { // disable regenerate id in session
|
||||
$app->setComponent('session', Stub::make('CHttpSession', ['regenerateID' => false]));
|
||||
}
|
||||
|
||||
$app->onEndRequest->add([$this, 'setHeaders']);
|
||||
$app->run();
|
||||
|
||||
if ($app->hasComponent('db')) {
|
||||
// close connection
|
||||
$app->getDb()->setActive(false);
|
||||
// cleanup metadata cache
|
||||
$property = new \ReflectionProperty('CActiveRecord', '_md');
|
||||
$property->setAccessible(true);
|
||||
$property->setValue([]);
|
||||
}
|
||||
|
||||
$content = ob_get_clean();
|
||||
|
||||
$headers = $this->getHeaders();
|
||||
$statusCode = 200;
|
||||
foreach ($headers as $header => $val) {
|
||||
if ($header == 'Location') {
|
||||
$statusCode = 302;
|
||||
}
|
||||
}
|
||||
|
||||
$response = new Response($content, $statusCode, $this->getHeaders());
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current client headers when terminating yii application (onEndRequest)
|
||||
*/
|
||||
public function setHeaders()
|
||||
{
|
||||
$this->headers = \Yii::app()->request->getAllHeaders();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current client headers
|
||||
* @return array headers
|
||||
*/
|
||||
public function getHeaders()
|
||||
{
|
||||
return $this->headers;
|
||||
}
|
||||
}
|
||||
396
vendor/codeception/base/src/Codeception/Lib/Connector/Yii2.php
vendored
Normal file
396
vendor/codeception/base/src/Codeception/Lib/Connector/Yii2.php
vendored
Normal file
@@ -0,0 +1,396 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector;
|
||||
|
||||
use Codeception\Lib\Connector\Yii2\Logger;
|
||||
use Codeception\Lib\InnerBrowser;
|
||||
use Codeception\Util\Debug;
|
||||
use Symfony\Component\BrowserKit\Client;
|
||||
use Symfony\Component\BrowserKit\Cookie;
|
||||
use Symfony\Component\BrowserKit\Response;
|
||||
use Yii;
|
||||
use yii\base\ExitException;
|
||||
use yii\base\Security;
|
||||
use yii\web\Application;
|
||||
use yii\web\ErrorHandler;
|
||||
use yii\web\HttpException;
|
||||
use yii\web\Request;
|
||||
use yii\web\Response as YiiResponse;
|
||||
|
||||
class Yii2 extends Client
|
||||
{
|
||||
use Shared\PhpSuperGlobalsConverter;
|
||||
|
||||
const CLEAN_METHODS = [
|
||||
self::CLEAN_RECREATE,
|
||||
self::CLEAN_CLEAR,
|
||||
self::CLEAN_FORCE_RECREATE,
|
||||
self::CLEAN_MANUAL
|
||||
];
|
||||
/**
|
||||
* Clean the response object by recreating it.
|
||||
* This might lose behaviors / event handlers / other changes that are done in the application bootstrap phase.
|
||||
*/
|
||||
const CLEAN_RECREATE = 'recreate';
|
||||
/**
|
||||
* Same as recreate but will not warn when behaviors / event handlers are lost.
|
||||
*/
|
||||
const CLEAN_FORCE_RECREATE = 'force_recreate';
|
||||
/**
|
||||
* Clean the response object by resetting specific properties via its' `clear()` method.
|
||||
* This will keep behaviors / event handlers, but could inadvertently leave some changes intact.
|
||||
* @see \Yii\web\Response::clear()
|
||||
*/
|
||||
const CLEAN_CLEAR = 'clear';
|
||||
|
||||
/**
|
||||
* Do not clean the response, instead the test writer will be responsible for manually resetting the response in
|
||||
* between requests during one test
|
||||
*/
|
||||
const CLEAN_MANUAL = 'manual';
|
||||
|
||||
|
||||
/**
|
||||
* @var string application config file
|
||||
*/
|
||||
public $configFile;
|
||||
|
||||
/**
|
||||
* @var string method for cleaning the response object before each request
|
||||
*/
|
||||
public $responseCleanMethod;
|
||||
|
||||
/**
|
||||
* @var string method for cleaning the request object before each request
|
||||
*/
|
||||
public $requestCleanMethod;
|
||||
|
||||
/**
|
||||
* @var string[] List of component names that must be recreated before each request
|
||||
*/
|
||||
public $recreateComponents = [];
|
||||
|
||||
/**
|
||||
* This option is there primarily for backwards compatibility.
|
||||
* It means you cannot make any modification to application state inside your app, since they will get discarded.
|
||||
* @var bool whether to recreate the whole application before each request
|
||||
*/
|
||||
public $recreateApplication = false;
|
||||
|
||||
/**
|
||||
* @return \yii\web\Application
|
||||
*/
|
||||
public function getApplication()
|
||||
{
|
||||
if (!isset(Yii::$app)) {
|
||||
$this->startApp();
|
||||
}
|
||||
return Yii::$app;
|
||||
}
|
||||
|
||||
public function resetApplication()
|
||||
{
|
||||
codecept_debug('Destroying application');
|
||||
Yii::$app = null;
|
||||
\yii\web\UploadedFile::reset();
|
||||
if (method_exists(\yii\base\Event::className(), 'offAll')) {
|
||||
\yii\base\Event::offAll();
|
||||
}
|
||||
Yii::setLogger(null);
|
||||
// This resolves an issue with database connections not closing properly.
|
||||
gc_collect_cycles();
|
||||
}
|
||||
|
||||
public function startApp()
|
||||
{
|
||||
codecept_debug('Starting application');
|
||||
$config = require($this->configFile);
|
||||
if (!isset($config['class'])) {
|
||||
$config['class'] = 'yii\web\Application';
|
||||
}
|
||||
|
||||
$config = $this->mockMailer($config);
|
||||
/** @var \yii\web\Application $app */
|
||||
Yii::$app = Yii::createObject($config);
|
||||
|
||||
Yii::setLogger(new Logger());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param \Symfony\Component\BrowserKit\Request $request
|
||||
*
|
||||
* @return \Symfony\Component\BrowserKit\Response
|
||||
*/
|
||||
public function doRequest($request)
|
||||
{
|
||||
$_COOKIE = $request->getCookies();
|
||||
$_SERVER = $request->getServer();
|
||||
$_FILES = $this->remapFiles($request->getFiles());
|
||||
$_REQUEST = $this->remapRequestParameters($request->getParameters());
|
||||
$_POST = $_GET = [];
|
||||
|
||||
if (strtoupper($request->getMethod()) === 'GET') {
|
||||
$_GET = $_REQUEST;
|
||||
} else {
|
||||
$_POST = $_REQUEST;
|
||||
}
|
||||
|
||||
$uri = $request->getUri();
|
||||
|
||||
$pathString = parse_url($uri, PHP_URL_PATH);
|
||||
$queryString = parse_url($uri, PHP_URL_QUERY);
|
||||
$_SERVER['REQUEST_URI'] = $queryString === null ? $pathString : $pathString . '?' . $queryString;
|
||||
$_SERVER['REQUEST_METHOD'] = strtoupper($request->getMethod());
|
||||
|
||||
parse_str($queryString, $params);
|
||||
foreach ($params as $k => $v) {
|
||||
$_GET[$k] = $v;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
$this->beforeRequest();
|
||||
|
||||
$app = $this->getApplication();
|
||||
|
||||
// disabling logging. Logs are slowing test execution down
|
||||
foreach ($app->log->targets as $target) {
|
||||
$target->enabled = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
$yiiRequest = $app->getRequest();
|
||||
if ($request->getContent() !== null) {
|
||||
$yiiRequest->setRawBody($request->getContent());
|
||||
$yiiRequest->setBodyParams(null);
|
||||
} else {
|
||||
$yiiRequest->setRawBody(null);
|
||||
$yiiRequest->setBodyParams($_POST);
|
||||
}
|
||||
$yiiRequest->setQueryParams($_GET);
|
||||
|
||||
try {
|
||||
/*
|
||||
* This is basically equivalent to $app->run() without sending the response.
|
||||
* Sending the response is problematic because it tries to send headers.
|
||||
*/
|
||||
$app->trigger($app::EVENT_BEFORE_REQUEST);
|
||||
$response = $app->handleRequest($yiiRequest);
|
||||
$app->trigger($app::EVENT_AFTER_REQUEST);
|
||||
$response->send();
|
||||
} catch (\Exception $e) {
|
||||
if ($e instanceof HttpException) {
|
||||
// Don't discard output and pass exception handling to Yii to be able
|
||||
// to expect error response codes in tests.
|
||||
$app->errorHandler->discardExistingOutput = false;
|
||||
$app->errorHandler->handleException($e);
|
||||
} elseif (!$e instanceof ExitException) {
|
||||
// for exceptions not related to Http, we pass them to Codeception
|
||||
throw $e;
|
||||
}
|
||||
$response = $app->response;
|
||||
}
|
||||
|
||||
$this->encodeCookies($response, $yiiRequest, $app->security);
|
||||
|
||||
if ($response->isRedirection) {
|
||||
Debug::debug("[Redirect with headers]" . print_r($response->getHeaders()->toArray(), true));
|
||||
}
|
||||
|
||||
$content = ob_get_clean();
|
||||
if (empty($content) && !empty($response->content)) {
|
||||
throw new \Exception('No content was sent from Yii application');
|
||||
}
|
||||
|
||||
return new Response($content, $response->statusCode, $response->getHeaders()->toArray());
|
||||
}
|
||||
|
||||
protected function revertErrorHandler()
|
||||
{
|
||||
$handler = new ErrorHandler();
|
||||
set_error_handler([$handler, 'errorHandler']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes the cookies and adds them to the headers.
|
||||
* @param \yii\web\Response $response
|
||||
* @throws \yii\base\InvalidConfigException
|
||||
*/
|
||||
protected function encodeCookies(
|
||||
YiiResponse $response,
|
||||
Request $request,
|
||||
Security $security
|
||||
) {
|
||||
if ($request->enableCookieValidation) {
|
||||
$validationKey = $request->cookieValidationKey;
|
||||
}
|
||||
|
||||
foreach ($response->getCookies() as $cookie) {
|
||||
/** @var \yii\web\Cookie $cookie */
|
||||
$value = $cookie->value;
|
||||
if ($cookie->expire != 1 && isset($validationKey)) {
|
||||
$data = version_compare(Yii::getVersion(), '2.0.2', '>')
|
||||
? [$cookie->name, $cookie->value]
|
||||
: $cookie->value;
|
||||
$value = $security->hashData(serialize($data), $validationKey);
|
||||
}
|
||||
$c = new Cookie(
|
||||
$cookie->name,
|
||||
$value,
|
||||
$cookie->expire,
|
||||
$cookie->path,
|
||||
$cookie->domain,
|
||||
$cookie->secure,
|
||||
$cookie->httpOnly
|
||||
);
|
||||
$this->getCookieJar()->set($c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace mailer with in memory mailer
|
||||
* @param array $config Original configuration
|
||||
* @return array New configuration
|
||||
*/
|
||||
protected function mockMailer(array $config)
|
||||
{
|
||||
// options that make sense for mailer mock
|
||||
$allowedOptions = [
|
||||
'htmlLayout',
|
||||
'textLayout',
|
||||
'messageConfig',
|
||||
'messageClass',
|
||||
'useFileTransport',
|
||||
'fileTransportPath',
|
||||
'fileTransportCallback',
|
||||
'view',
|
||||
'viewPath',
|
||||
];
|
||||
|
||||
$mailerConfig = [
|
||||
'class' => 'Codeception\Lib\Connector\Yii2\TestMailer',
|
||||
];
|
||||
|
||||
if (isset($config['components']['mailer']) && is_array($config['components']['mailer'])) {
|
||||
foreach ($config['components']['mailer'] as $name => $value) {
|
||||
if (in_array($name, $allowedOptions, true)) {
|
||||
$mailerConfig[$name] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
$config['components']['mailer'] = $mailerConfig;
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function restart()
|
||||
{
|
||||
parent::restart();
|
||||
$this->resetApplication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the applications' response object.
|
||||
* The method used depends on the module configuration.
|
||||
*/
|
||||
protected function resetResponse(Application $app)
|
||||
{
|
||||
$method = $this->responseCleanMethod;
|
||||
// First check the current response object.
|
||||
if (($app->response->hasEventHandlers(\yii\web\Response::EVENT_BEFORE_SEND)
|
||||
|| $app->response->hasEventHandlers(\yii\web\Response::EVENT_AFTER_SEND)
|
||||
|| $app->response->hasEventHandlers(\yii\web\Response::EVENT_AFTER_PREPARE)
|
||||
|| count($app->response->getBehaviors()) > 0
|
||||
) && $method === self::CLEAN_RECREATE
|
||||
) {
|
||||
Debug::debug(<<<TEXT
|
||||
[WARNING] You are attaching event handlers or behaviors to the response object. But the Yii2 module is configured to recreate
|
||||
the response object, this means any behaviors or events that are not attached in the component config will be lost.
|
||||
We will fall back to clearing the response. If you are certain you want to recreate it, please configure
|
||||
responseCleanMethod = 'force_recreate' in the module.
|
||||
TEXT
|
||||
);
|
||||
$method = self::CLEAN_CLEAR;
|
||||
}
|
||||
|
||||
switch ($method) {
|
||||
case self::CLEAN_FORCE_RECREATE:
|
||||
case self::CLEAN_RECREATE:
|
||||
$app->set('response', $app->getComponents()['response']);
|
||||
break;
|
||||
case self::CLEAN_CLEAR:
|
||||
$app->response->clear();
|
||||
break;
|
||||
case self::CLEAN_MANUAL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function resetRequest(Application $app)
|
||||
{
|
||||
$method = $this->requestCleanMethod;
|
||||
$request = $app->request;
|
||||
|
||||
// First check the current request object.
|
||||
if (count($request->getBehaviors()) > 0 && $method === self::CLEAN_RECREATE) {
|
||||
Debug::debug(<<<TEXT
|
||||
[WARNING] You are attaching event handlers or behaviors to the request object. But the Yii2 module is configured to recreate
|
||||
the request object, this means any behaviors or events that are not attached in the component config will be lost.
|
||||
We will fall back to clearing the request. If you are certain you want to recreate it, please configure
|
||||
requestCleanMethod = 'force_recreate' in the module.
|
||||
TEXT
|
||||
);
|
||||
$method = self::CLEAN_CLEAR;
|
||||
}
|
||||
|
||||
switch ($method) {
|
||||
case self::CLEAN_FORCE_RECREATE:
|
||||
case self::CLEAN_RECREATE:
|
||||
$app->set('request', $app->getComponents()['request']);
|
||||
break;
|
||||
case self::CLEAN_CLEAR:
|
||||
$request->getHeaders()->removeAll();
|
||||
$request->setBaseUrl(null);
|
||||
$request->setHostInfo(null);
|
||||
$request->setPathInfo(null);
|
||||
$request->setScriptFile(null);
|
||||
$request->setScriptUrl(null);
|
||||
$request->setUrl(null);
|
||||
$request->setPort(null);
|
||||
$request->setSecurePort(null);
|
||||
$request->setAcceptableContentTypes(null);
|
||||
$request->setAcceptableLanguages(null);
|
||||
|
||||
break;
|
||||
case self::CLEAN_MANUAL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before each request, preparation happens here.
|
||||
*/
|
||||
protected function beforeRequest()
|
||||
{
|
||||
if ($this->recreateApplication) {
|
||||
$this->resetApplication();
|
||||
return;
|
||||
}
|
||||
|
||||
$application = $this->getApplication();
|
||||
|
||||
$this->resetResponse($application);
|
||||
$this->resetRequest($application);
|
||||
|
||||
$definitions = $application->getComponents(true);
|
||||
foreach ($this->recreateComponents as $component) {
|
||||
// Only recreate if it has actually been instantiated.
|
||||
if ($application->has($component, true)) {
|
||||
$application->set($component, $definitions[$component]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
67
vendor/codeception/base/src/Codeception/Lib/Connector/Yii2/ConnectionWatcher.php
vendored
Normal file
67
vendor/codeception/base/src/Codeception/Lib/Connector/Yii2/ConnectionWatcher.php
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Codeception\Lib\Connector\Yii2;
|
||||
|
||||
use yii\base\Event;
|
||||
use yii\db\Connection;
|
||||
|
||||
/**
|
||||
* Class ConnectionWatcher
|
||||
* This class will watch for new database connection and store a reference to the connection object.
|
||||
* @package Codeception\Lib\Connector\Yii2
|
||||
*/
|
||||
class ConnectionWatcher
|
||||
{
|
||||
private $handler;
|
||||
|
||||
/** @var Connection[] */
|
||||
private $connections = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->handler = function (Event $event) {
|
||||
if ($event->sender instanceof Connection) {
|
||||
$this->connectionOpened($event->sender);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected function connectionOpened(Connection $connection)
|
||||
{
|
||||
$this->debug('Connection opened!');
|
||||
if ($connection instanceof Connection) {
|
||||
$this->connections[] = $connection;
|
||||
}
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
Event::on(Connection::class, Connection::EVENT_AFTER_OPEN, $this->handler);
|
||||
$this->debug('watching new connections');
|
||||
}
|
||||
|
||||
public function stop()
|
||||
{
|
||||
Event::off(Connection::class, Connection::EVENT_AFTER_OPEN, $this->handler);
|
||||
$this->debug('no longer watching new connections');
|
||||
}
|
||||
|
||||
public function closeAll()
|
||||
{
|
||||
$count = count($this->connections);
|
||||
$this->debug("closing all ($count) connections");
|
||||
foreach ($this->connections as $connection) {
|
||||
$connection->close();
|
||||
}
|
||||
}
|
||||
|
||||
protected function debug($message)
|
||||
{
|
||||
$title = (new \ReflectionClass($this))->getShortName();
|
||||
if (is_array($message) or is_object($message)) {
|
||||
$message = stripslashes(json_encode($message));
|
||||
}
|
||||
codecept_debug("[$title] $message");
|
||||
}
|
||||
}
|
||||
35
vendor/codeception/base/src/Codeception/Lib/Connector/Yii2/FixturesStore.php
vendored
Normal file
35
vendor/codeception/base/src/Codeception/Lib/Connector/Yii2/FixturesStore.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector\Yii2;
|
||||
|
||||
use yii\test\FixtureTrait;
|
||||
use yii\test\InitDbFixture;
|
||||
|
||||
class FixturesStore
|
||||
{
|
||||
use FixtureTrait;
|
||||
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* Expects fixtures config
|
||||
*
|
||||
* FixturesStore constructor.
|
||||
* @param $data
|
||||
*/
|
||||
public function __construct($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function fixtures()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function globalFixtures()
|
||||
{
|
||||
return [
|
||||
InitDbFixture::className()
|
||||
];
|
||||
}
|
||||
}
|
||||
33
vendor/codeception/base/src/Codeception/Lib/Connector/Yii2/Logger.php
vendored
Normal file
33
vendor/codeception/base/src/Codeception/Lib/Connector/Yii2/Logger.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector\Yii2;
|
||||
|
||||
use Codeception\Util\Debug;
|
||||
|
||||
class Logger extends \yii\log\Logger
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
// overridden to prevent register_shutdown_function
|
||||
}
|
||||
|
||||
public function log($message, $level, $category = 'application')
|
||||
{
|
||||
if (!in_array($level, [
|
||||
\yii\log\Logger::LEVEL_INFO,
|
||||
\yii\log\Logger::LEVEL_WARNING,
|
||||
\yii\log\Logger::LEVEL_ERROR,
|
||||
])) {
|
||||
return;
|
||||
}
|
||||
if (strpos($category, 'yii\db\Command')===0) {
|
||||
return; // don't log queries
|
||||
}
|
||||
|
||||
// https://github.com/Codeception/Codeception/issues/3696
|
||||
if ($message instanceof \yii\base\Exception) {
|
||||
$message = $message->__toString();
|
||||
}
|
||||
|
||||
Debug::debug("[$category] " . \yii\helpers\VarDumper::export($message));
|
||||
}
|
||||
}
|
||||
32
vendor/codeception/base/src/Codeception/Lib/Connector/Yii2/TestMailer.php
vendored
Normal file
32
vendor/codeception/base/src/Codeception/Lib/Connector/Yii2/TestMailer.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector\Yii2;
|
||||
|
||||
use yii\mail\BaseMailer;
|
||||
|
||||
class TestMailer extends BaseMailer
|
||||
{
|
||||
public $messageClass = 'yii\swiftmailer\Message';
|
||||
|
||||
private $sentMessages = [];
|
||||
|
||||
protected function sendMessage($message)
|
||||
{
|
||||
$this->sentMessages[] = $message;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function saveMessage($message)
|
||||
{
|
||||
return $this->sendMessage($message);
|
||||
}
|
||||
|
||||
public function getSentMessages()
|
||||
{
|
||||
return $this->sentMessages;
|
||||
}
|
||||
|
||||
public function reset()
|
||||
{
|
||||
$this->sentMessages = [];
|
||||
}
|
||||
}
|
||||
97
vendor/codeception/base/src/Codeception/Lib/Connector/Yii2/TransactionForcer.php
vendored
Normal file
97
vendor/codeception/base/src/Codeception/Lib/Connector/Yii2/TransactionForcer.php
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Codeception\Lib\Connector\Yii2;
|
||||
|
||||
use yii\base\Event;
|
||||
use yii\db\Connection;
|
||||
use yii\db\Transaction;
|
||||
|
||||
/**
|
||||
* Class TransactionForcer
|
||||
* This class adds support for forcing transactions as well as reusing PDO objects.
|
||||
* @package Codeception\Lib\Connector\Yii2
|
||||
*/
|
||||
class TransactionForcer extends ConnectionWatcher
|
||||
{
|
||||
private $ignoreCollidingDSN;
|
||||
|
||||
private $pdoCache = [];
|
||||
|
||||
private $dsnCache;
|
||||
|
||||
private $transactions = [];
|
||||
|
||||
public function __construct(
|
||||
$ignoreCollidingDSN
|
||||
) {
|
||||
parent::__construct();
|
||||
$this->ignoreCollidingDSN = $ignoreCollidingDSN;
|
||||
}
|
||||
|
||||
|
||||
protected function connectionOpened(Connection $connection)
|
||||
{
|
||||
parent::connectionOpened($connection);
|
||||
/**
|
||||
* We should check if the known PDO objects are the same, in which case we should reuse the PDO
|
||||
* object so only 1 transaction is started and multiple connections to the same database see the
|
||||
* same data (due to writes inside a transaction not being visible from the outside).
|
||||
*
|
||||
*/
|
||||
$key = md5(json_encode([
|
||||
'dsn' => $connection->dsn,
|
||||
'user' => $connection->username,
|
||||
'pass' => $connection->password,
|
||||
'attributes' => $connection->attributes,
|
||||
'emulatePrepare' => $connection->emulatePrepare,
|
||||
'charset' => $connection->charset
|
||||
]));
|
||||
|
||||
/*
|
||||
* If keys match we assume connections are "similar enough".
|
||||
*/
|
||||
if (isset($this->pdoCache[$key])) {
|
||||
$connection->pdo = $this->pdoCache[$key];
|
||||
} else {
|
||||
$this->pdoCache[$key] = $connection->pdo;
|
||||
}
|
||||
|
||||
if (isset($this->dsnCache[$connection->dsn])
|
||||
&& $this->dsnCache[$connection->dsn] !== $key
|
||||
&& !$this->ignoreCollidingDSN
|
||||
) {
|
||||
$this->debug(<<<TEXT
|
||||
You use multiple connections to the same DSN ({$connection->dsn}) with different configuration.
|
||||
These connections will not see the same database state since we cannot share a transaction between different PDO
|
||||
instances.
|
||||
You can remove this message by adding 'ignoreCollidingDSN = true' in the module configuration.
|
||||
TEXT
|
||||
);
|
||||
Debug::pause();
|
||||
}
|
||||
|
||||
if (isset($this->transactions[$key])) {
|
||||
$this->debug('Reusing PDO, so no need for a new transaction');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->debug('Transaction started for: ' . $connection->dsn);
|
||||
$this->transactions[$key] = $connection->beginTransaction();
|
||||
}
|
||||
|
||||
public function rollbackAll()
|
||||
{
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($this->transactions as $transaction) {
|
||||
if ($transaction->db->isActive) {
|
||||
$transaction->rollBack();
|
||||
$this->debug('Transaction cancelled; all changes reverted.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->transactions = [];
|
||||
$this->pdoCache = [];
|
||||
$this->dsnCache = [];
|
||||
}
|
||||
}
|
||||
145
vendor/codeception/base/src/Codeception/Lib/Connector/ZF1.php
vendored
Normal file
145
vendor/codeception/base/src/Codeception/Lib/Connector/ZF1.php
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector;
|
||||
|
||||
use Symfony\Component\BrowserKit\Client;
|
||||
use Symfony\Component\BrowserKit\Response;
|
||||
use Symfony\Component\BrowserKit\Request as BrowserKitRequest;
|
||||
|
||||
class ZF1 extends Client
|
||||
{
|
||||
use Shared\PhpSuperGlobalsConverter;
|
||||
|
||||
/**
|
||||
* @var \Zend_Controller_Front
|
||||
*/
|
||||
protected $front;
|
||||
|
||||
/**
|
||||
* @var \Zend_Application
|
||||
*/
|
||||
protected $bootstrap;
|
||||
|
||||
/**
|
||||
* @var \Zend_Controller_Request_HttpTestCase
|
||||
*/
|
||||
protected $zendRequest;
|
||||
|
||||
public function setBootstrap($bootstrap)
|
||||
{
|
||||
$this->bootstrap = $bootstrap;
|
||||
|
||||
$this->front = $this->bootstrap
|
||||
->getBootstrap()
|
||||
->getResource('frontcontroller');
|
||||
$this->front
|
||||
->throwExceptions(true)
|
||||
->returnResponse(false);
|
||||
}
|
||||
|
||||
public function doRequest($request)
|
||||
{
|
||||
|
||||
// redirector should not exit
|
||||
$redirector = \Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
|
||||
$redirector->setExit(false);
|
||||
|
||||
// json helper should not exit
|
||||
$json = \Zend_Controller_Action_HelperBroker::getStaticHelper('json');
|
||||
$json->suppressExit = true;
|
||||
|
||||
$zendRequest = new \Zend_Controller_Request_HttpTestCase();
|
||||
$zendRequest->setMethod($request->getMethod());
|
||||
$zendRequest->setCookies($request->getCookies());
|
||||
$zendRequest->setParams($request->getParameters());
|
||||
// Sf2's BrowserKit does not distinguish between GET, POST, PUT etc.,
|
||||
// so we set all parameters in ZF's request here to not break apps
|
||||
// relying on $request->getPost()
|
||||
$zendRequest->setPost($request->getParameters());
|
||||
$zendRequest->setRawBody($request->getContent());
|
||||
|
||||
$uri = $request->getUri();
|
||||
$queryString = parse_url($uri, PHP_URL_QUERY);
|
||||
$requestUri = parse_url($uri, PHP_URL_PATH);
|
||||
if (!empty($queryString)) {
|
||||
$requestUri .= '?' . $queryString;
|
||||
}
|
||||
$zendRequest->setRequestUri($requestUri);
|
||||
|
||||
$zendRequest->setHeaders($this->extractHeaders($request));
|
||||
$_FILES = $this->remapFiles($request->getFiles());
|
||||
$_SERVER = array_merge($_SERVER, $request->getServer());
|
||||
|
||||
$zendResponse = new \Zend_Controller_Response_HttpTestCase;
|
||||
$this->front->setRequest($zendRequest)->setResponse($zendResponse);
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
$this->bootstrap->run();
|
||||
$_GET = $_POST = [];
|
||||
} catch (\Exception $e) {
|
||||
ob_end_clean();
|
||||
$_GET = $_POST = [];
|
||||
throw $e;
|
||||
}
|
||||
ob_end_clean();
|
||||
|
||||
$this->zendRequest = $zendRequest;
|
||||
|
||||
$response = new Response(
|
||||
$zendResponse->getBody(),
|
||||
$zendResponse->getHttpResponseCode(),
|
||||
$this->formatResponseHeaders($zendResponse)
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format up the ZF1 response headers into Symfony\Component\BrowserKit\Response headers format.
|
||||
*
|
||||
* @param \Zend_Controller_Response_Abstract $response The ZF1 Response Object.
|
||||
* @return array the clean key/value headers
|
||||
*/
|
||||
private function formatResponseHeaders(\Zend_Controller_Response_Abstract $response)
|
||||
{
|
||||
$headers = [];
|
||||
foreach ($response->getHeaders() as $header) {
|
||||
$name = $header['name'];
|
||||
if (array_key_exists($name, $headers)) {
|
||||
if ($header['replace']) {
|
||||
$headers[$name] = $header['value'];
|
||||
}
|
||||
} else {
|
||||
$headers[$name] = $header['value'];
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \Zend_Controller_Request_HttpTestCase
|
||||
*/
|
||||
public function getZendRequest()
|
||||
{
|
||||
return $this->zendRequest;
|
||||
}
|
||||
|
||||
private function extractHeaders(BrowserKitRequest $request)
|
||||
{
|
||||
$headers = [];
|
||||
$server = $request->getServer();
|
||||
|
||||
$contentHeaders = ['Content-Length' => true, 'Content-Md5' => true, 'Content-Type' => true];
|
||||
foreach ($server as $header => $val) {
|
||||
$header = html_entity_decode(implode('-', array_map('ucfirst', explode('-', strtolower(str_replace('_', '-', $header))))), ENT_NOQUOTES);
|
||||
|
||||
if (strpos($header, 'Http-') === 0) {
|
||||
$headers[substr($header, 5)] = $val;
|
||||
} elseif (isset($contentHeaders[$header])) {
|
||||
$headers[$header] = $val;
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
}
|
||||
192
vendor/codeception/base/src/Codeception/Lib/Connector/ZF2.php
vendored
Normal file
192
vendor/codeception/base/src/Codeception/Lib/Connector/ZF2.php
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector;
|
||||
|
||||
use Codeception\Exception\ModuleException;
|
||||
use Codeception\Lib\Connector\ZF2\PersistentServiceManager;
|
||||
use Symfony\Component\BrowserKit\Client;
|
||||
use Symfony\Component\BrowserKit\Request;
|
||||
use Symfony\Component\BrowserKit\Response;
|
||||
use Zend\Http\Request as HttpRequest;
|
||||
use Zend\Http\Headers as HttpHeaders;
|
||||
use Zend\Mvc\Application;
|
||||
use Zend\Stdlib\Parameters;
|
||||
use Zend\Uri\Http as HttpUri;
|
||||
use Symfony\Component\BrowserKit\Request as BrowserKitRequest;
|
||||
|
||||
class ZF2 extends Client
|
||||
{
|
||||
/**
|
||||
* @var \Zend\Mvc\ApplicationInterface
|
||||
*/
|
||||
protected $application;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $applicationConfig;
|
||||
|
||||
/**
|
||||
* @var \Zend\Http\PhpEnvironment\Request
|
||||
*/
|
||||
protected $zendRequest;
|
||||
|
||||
/**
|
||||
* @var PersistentServiceManager
|
||||
*/
|
||||
private $persistentServiceManager;
|
||||
|
||||
/**
|
||||
* @param array $applicationConfig
|
||||
*/
|
||||
public function setApplicationConfig($applicationConfig)
|
||||
{
|
||||
$this->applicationConfig = $applicationConfig;
|
||||
$this->createApplication();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return Response
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function doRequest($request)
|
||||
{
|
||||
$this->createApplication();
|
||||
$zendRequest = $this->application->getRequest();
|
||||
|
||||
$uri = new HttpUri($request->getUri());
|
||||
$queryString = $uri->getQuery();
|
||||
$method = strtoupper($request->getMethod());
|
||||
|
||||
$zendRequest->setCookies(new Parameters($request->getCookies()));
|
||||
|
||||
$query = [];
|
||||
$post = [];
|
||||
$content = $request->getContent();
|
||||
if ($queryString) {
|
||||
parse_str($queryString, $query);
|
||||
}
|
||||
|
||||
if ($method !== HttpRequest::METHOD_GET) {
|
||||
$post = $request->getParameters();
|
||||
}
|
||||
|
||||
$zendRequest->setQuery(new Parameters($query));
|
||||
$zendRequest->setPost(new Parameters($post));
|
||||
$zendRequest->setFiles(new Parameters($request->getFiles()));
|
||||
$zendRequest->setContent($content);
|
||||
$zendRequest->setMethod($method);
|
||||
$zendRequest->setUri($uri);
|
||||
$requestUri = $uri->getPath();
|
||||
if (!empty($queryString)) {
|
||||
$requestUri .= '?' . $queryString;
|
||||
}
|
||||
|
||||
$zendRequest->setRequestUri($requestUri);
|
||||
|
||||
$zendRequest->setHeaders($this->extractHeaders($request));
|
||||
$this->application->run();
|
||||
|
||||
// get the response *after* the application has run, because other ZF
|
||||
// libraries like API Agility may *replace* the application's response
|
||||
//
|
||||
$zendResponse = $this->application->getResponse();
|
||||
|
||||
$this->zendRequest = $zendRequest;
|
||||
|
||||
$exception = $this->application->getMvcEvent()->getParam('exception');
|
||||
if ($exception instanceof \Exception) {
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
$response = new Response(
|
||||
$zendResponse->getBody(),
|
||||
$zendResponse->getStatusCode(),
|
||||
$zendResponse->getHeaders()->toArray()
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Zend\Http\PhpEnvironment\Request
|
||||
*/
|
||||
public function getZendRequest()
|
||||
{
|
||||
return $this->zendRequest;
|
||||
}
|
||||
|
||||
private function extractHeaders(BrowserKitRequest $request)
|
||||
{
|
||||
$headers = [];
|
||||
$server = $request->getServer();
|
||||
|
||||
$contentHeaders = ['Content-Length' => true, 'Content-Md5' => true, 'Content-Type' => true];
|
||||
foreach ($server as $header => $val) {
|
||||
$header = html_entity_decode(implode('-', array_map('ucfirst', explode('-', strtolower(str_replace('_', '-', $header))))), ENT_NOQUOTES);
|
||||
|
||||
if (strpos($header, 'Http-') === 0) {
|
||||
$headers[substr($header, 5)] = $val;
|
||||
} elseif (isset($contentHeaders[$header])) {
|
||||
$headers[$header] = $val;
|
||||
}
|
||||
}
|
||||
$zendHeaders = new HttpHeaders();
|
||||
$zendHeaders->addHeaders($headers);
|
||||
return $zendHeaders;
|
||||
}
|
||||
|
||||
public function grabServiceFromContainer($service)
|
||||
{
|
||||
$serviceManager = $this->application->getServiceManager();
|
||||
|
||||
if (!$serviceManager->has($service)) {
|
||||
throw new \PHPUnit\Framework\AssertionFailedError("Service $service is not available in container");
|
||||
}
|
||||
|
||||
if ($service === 'Doctrine\ORM\EntityManager' && !isset($this->persistentServiceManager)) {
|
||||
if (!method_exists($serviceManager, 'addPeeringServiceManager')) {
|
||||
throw new ModuleException('Codeception\Module\ZF2', 'integration with Doctrine2 module is not compatible with ZF3');
|
||||
}
|
||||
$this->persistentServiceManager = new PersistentServiceManager($serviceManager);
|
||||
}
|
||||
|
||||
return $serviceManager->get($service);
|
||||
}
|
||||
|
||||
public function addServiceToContainer($name, $service)
|
||||
{
|
||||
if (!isset($this->persistentServiceManager)) {
|
||||
$serviceManager = $this->application->getServiceManager();
|
||||
if (!method_exists($serviceManager, 'addPeeringServiceManager')) {
|
||||
throw new ModuleException('Codeception\Module\ZF2', 'addServiceToContainer method is not compatible with ZF3');
|
||||
}
|
||||
$this->persistentServiceManager = new PersistentServiceManager($serviceManager);
|
||||
$serviceManager->addPeeringServiceManager($this->persistentServiceManager);
|
||||
$serviceManager->setRetrieveFromPeeringManagerFirst(true);
|
||||
}
|
||||
$this->persistentServiceManager->setAllowOverride(true);
|
||||
$this->persistentServiceManager->setService($name, $service);
|
||||
$this->persistentServiceManager->setAllowOverride(false);
|
||||
}
|
||||
|
||||
private function createApplication()
|
||||
{
|
||||
$this->application = Application::init($this->applicationConfig);
|
||||
$serviceManager = $this->application->getServiceManager();
|
||||
|
||||
if (isset($this->persistentServiceManager)) {
|
||||
$serviceManager->addPeeringServiceManager($this->persistentServiceManager);
|
||||
$serviceManager->setRetrieveFromPeeringManagerFirst(true);
|
||||
}
|
||||
|
||||
$sendResponseListener = $serviceManager->get('SendResponseListener');
|
||||
$events = $this->application->getEventManager();
|
||||
if (class_exists('Zend\EventManager\StaticEventManager')) {
|
||||
$events->detach($sendResponseListener); //ZF2
|
||||
} else {
|
||||
$events->detach([$sendResponseListener, 'sendResponse']); //ZF3
|
||||
}
|
||||
}
|
||||
}
|
||||
43
vendor/codeception/base/src/Codeception/Lib/Connector/ZF2/PersistentServiceManager.php
vendored
Normal file
43
vendor/codeception/base/src/Codeception/Lib/Connector/ZF2/PersistentServiceManager.php
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Codeception\Lib\Connector\ZF2;
|
||||
|
||||
use \Zend\ServiceManager\ServiceLocatorInterface;
|
||||
use \Zend\ServiceManager\ServiceManager;
|
||||
|
||||
class PersistentServiceManager extends ServiceManager implements ServiceLocatorInterface
|
||||
{
|
||||
/**
|
||||
* @var ServiceLocatorInterface Used to retrieve Doctrine services
|
||||
*/
|
||||
private $serviceManager;
|
||||
|
||||
public function __construct(ServiceLocatorInterface $serviceManager)
|
||||
{
|
||||
$this->serviceManager = $serviceManager;
|
||||
}
|
||||
|
||||
public function get($name, $usePeeringServiceManagers = true)
|
||||
{
|
||||
if (parent::has($name)) {
|
||||
return parent::get($name, $usePeeringServiceManagers);
|
||||
}
|
||||
return $this->serviceManager->get($name);
|
||||
}
|
||||
|
||||
public function has($name, $checkAbstractFactories = true, $usePeeringServiceManagers = true)
|
||||
{
|
||||
if (parent::has($name, $checkAbstractFactories, $usePeeringServiceManagers)) {
|
||||
return true;
|
||||
}
|
||||
if (preg_match('/doctrine/i', $name)) {
|
||||
return $this->serviceManager->has($name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function setService($name, $service)
|
||||
{
|
||||
parent::setService($name, $service);
|
||||
}
|
||||
}
|
||||
142
vendor/codeception/base/src/Codeception/Lib/Connector/ZendExpressive.php
vendored
Normal file
142
vendor/codeception/base/src/Codeception/Lib/Connector/ZendExpressive.php
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector;
|
||||
|
||||
use Codeception\Lib\Connector\ZendExpressive\ResponseCollector;
|
||||
use Symfony\Component\BrowserKit\Client;
|
||||
use Symfony\Component\BrowserKit\Request;
|
||||
use Symfony\Component\BrowserKit\Response;
|
||||
use Symfony\Component\BrowserKit\Request as BrowserKitRequest;
|
||||
use Zend\Diactoros\ServerRequest;
|
||||
use Zend\Expressive\Application;
|
||||
use Zend\Diactoros\UploadedFile;
|
||||
|
||||
class ZendExpressive extends Client
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Application
|
||||
*/
|
||||
protected $application;
|
||||
|
||||
/**
|
||||
* @var ResponseCollector
|
||||
*/
|
||||
protected $responseCollector;
|
||||
|
||||
/**
|
||||
* @param Application
|
||||
*/
|
||||
public function setApplication(Application $application)
|
||||
{
|
||||
$this->application = $application;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ResponseCollector $responseCollector
|
||||
*/
|
||||
public function setResponseCollector(ResponseCollector $responseCollector)
|
||||
{
|
||||
$this->responseCollector = $responseCollector;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return Response
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function doRequest($request)
|
||||
{
|
||||
$inputStream = fopen('php://memory', 'r+');
|
||||
$content = $request->getContent();
|
||||
if ($content !== null) {
|
||||
fwrite($inputStream, $content);
|
||||
rewind($inputStream);
|
||||
}
|
||||
|
||||
$queryParams = [];
|
||||
$postParams = [];
|
||||
$queryString = parse_url($request->getUri(), PHP_URL_QUERY);
|
||||
if ($queryString != '') {
|
||||
parse_str($queryString, $queryParams);
|
||||
}
|
||||
if ($request->getMethod() !== 'GET') {
|
||||
$postParams = $request->getParameters();
|
||||
}
|
||||
|
||||
$serverParams = $request->getServer();
|
||||
if (!isset($serverParams['SCRIPT_NAME'])) {
|
||||
//required by WhoopsErrorHandler
|
||||
$serverParams['SCRIPT_NAME'] = 'Codeception';
|
||||
}
|
||||
|
||||
$zendRequest = new ServerRequest(
|
||||
$serverParams,
|
||||
$this->convertFiles($request->getFiles()),
|
||||
$request->getUri(),
|
||||
$request->getMethod(),
|
||||
$inputStream,
|
||||
$this->extractHeaders($request)
|
||||
);
|
||||
|
||||
$zendRequest = $zendRequest->withCookieParams($request->getCookies())
|
||||
->withQueryParams($queryParams)
|
||||
->withParsedBody($postParams);
|
||||
|
||||
$cwd = getcwd();
|
||||
chdir(codecept_root_dir());
|
||||
$this->application->run($zendRequest);
|
||||
chdir($cwd);
|
||||
|
||||
$this->request = $zendRequest;
|
||||
|
||||
$response = $this->responseCollector->getResponse();
|
||||
$this->responseCollector->clearResponse();
|
||||
|
||||
return new Response(
|
||||
$response->getBody(),
|
||||
$response->getStatusCode(),
|
||||
$response->getHeaders()
|
||||
);
|
||||
}
|
||||
|
||||
private function convertFiles(array $files)
|
||||
{
|
||||
$fileObjects = [];
|
||||
foreach ($files as $fieldName => $file) {
|
||||
if ($file instanceof UploadedFile) {
|
||||
$fileObjects[$fieldName] = $file;
|
||||
} elseif (!isset($file['tmp_name']) && !isset($file['name'])) {
|
||||
$fileObjects[$fieldName] = $this->convertFiles($file);
|
||||
} else {
|
||||
$fileObjects[$fieldName] = new UploadedFile(
|
||||
$file['tmp_name'],
|
||||
$file['size'],
|
||||
$file['error'],
|
||||
$file['name'],
|
||||
$file['type']
|
||||
);
|
||||
}
|
||||
}
|
||||
return $fileObjects;
|
||||
}
|
||||
|
||||
private function extractHeaders(BrowserKitRequest $request)
|
||||
{
|
||||
$headers = [];
|
||||
$server = $request->getServer();
|
||||
|
||||
$contentHeaders = ['Content-Length' => true, 'Content-Md5' => true, 'Content-Type' => true];
|
||||
foreach ($server as $header => $val) {
|
||||
$header = html_entity_decode(implode('-', array_map('ucfirst', explode('-', strtolower(str_replace('_', '-', $header))))), ENT_NOQUOTES);
|
||||
|
||||
if (strpos($header, 'Http-') === 0) {
|
||||
$headers[substr($header, 5)] = $val;
|
||||
} elseif (isset($contentHeaders[$header])) {
|
||||
$headers[$header] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
}
|
||||
31
vendor/codeception/base/src/Codeception/Lib/Connector/ZendExpressive/ResponseCollector.php
vendored
Normal file
31
vendor/codeception/base/src/Codeception/Lib/Connector/ZendExpressive/ResponseCollector.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Connector\ZendExpressive;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Zend\Diactoros\Response\EmitterInterface;
|
||||
|
||||
class ResponseCollector implements EmitterInterface
|
||||
{
|
||||
/**
|
||||
* @var ResponseInterface
|
||||
*/
|
||||
private $response;
|
||||
|
||||
public function emit(ResponseInterface $response)
|
||||
{
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
public function getResponse()
|
||||
{
|
||||
if ($this->response === null) {
|
||||
throw new \LogicException('Response wasn\'t emitted yet');
|
||||
}
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
public function clearResponse()
|
||||
{
|
||||
$this->response = null;
|
||||
}
|
||||
}
|
||||
37
vendor/codeception/base/src/Codeception/Lib/Console/Colorizer.php
vendored
Normal file
37
vendor/codeception/base/src/Codeception/Lib/Console/Colorizer.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Console;
|
||||
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
|
||||
class Colorizer
|
||||
{
|
||||
/**
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
public function colorize($string = '')
|
||||
{
|
||||
$fp = fopen('php://memory', 'r+');
|
||||
fwrite($fp, $string);
|
||||
rewind($fp);
|
||||
|
||||
$colorizedMessage = '';
|
||||
while ($line = fgets($fp)) {
|
||||
$char = $line[0];
|
||||
$line = OutputFormatter::escape(trim($line));
|
||||
|
||||
switch ($char) {
|
||||
case '+':
|
||||
$line = "<info>$line</info>";
|
||||
break;
|
||||
case '-':
|
||||
$line = "<comment>$line</comment>";
|
||||
break;
|
||||
}
|
||||
|
||||
$colorizedMessage .= $line . "\n";
|
||||
}
|
||||
|
||||
return trim($colorizedMessage);
|
||||
}
|
||||
}
|
||||
41
vendor/codeception/base/src/Codeception/Lib/Console/DiffFactory.php
vendored
Normal file
41
vendor/codeception/base/src/Codeception/Lib/Console/DiffFactory.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Console;
|
||||
|
||||
use SebastianBergmann\Comparator\ComparisonFailure;
|
||||
use SebastianBergmann\Diff\Differ;
|
||||
|
||||
/**
|
||||
* DiffFactory
|
||||
**/
|
||||
class DiffFactory
|
||||
{
|
||||
/**
|
||||
* @param ComparisonFailure $failure
|
||||
* @return string|null
|
||||
*/
|
||||
public function createDiff(ComparisonFailure $failure)
|
||||
{
|
||||
$diff = $this->getDiff($failure->getExpectedAsString(), $failure->getActualAsString());
|
||||
if (!$diff) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $diff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $expected
|
||||
* @param string $actual
|
||||
* @return string
|
||||
*/
|
||||
private function getDiff($expected = '', $actual = '')
|
||||
{
|
||||
if (!$actual && !$expected) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$differ = new Differ('');
|
||||
|
||||
return $differ->diff($expected, $actual);
|
||||
}
|
||||
}
|
||||
122
vendor/codeception/base/src/Codeception/Lib/Console/Message.php
vendored
Normal file
122
vendor/codeception/base/src/Codeception/Lib/Console/Message.php
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Console;
|
||||
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Message
|
||||
{
|
||||
protected $output;
|
||||
protected $message;
|
||||
|
||||
public function __construct($message, Output $output = null)
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->output = $output;
|
||||
}
|
||||
|
||||
public function with($param)
|
||||
{
|
||||
$args = array_merge([$this->message], func_get_args());
|
||||
$this->message = call_user_func_array('sprintf', $args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function style($name)
|
||||
{
|
||||
$this->message = sprintf('<%s>%s</%s>', $name, $this->message, $name);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function width($length, $char = ' ')
|
||||
{
|
||||
$message_length = $this->getLength();
|
||||
|
||||
if ($message_length < $length) {
|
||||
$this->message .= str_repeat($char, $length - $message_length);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function cut($length)
|
||||
{
|
||||
$this->message = mb_substr($this->message, 0, $length, 'utf-8');
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function write($verbose = OutputInterface::VERBOSITY_NORMAL)
|
||||
{
|
||||
if ($verbose > $this->output->getVerbosity()) {
|
||||
return;
|
||||
}
|
||||
$this->output->write($this->message);
|
||||
}
|
||||
|
||||
public function writeln($verbose = OutputInterface::VERBOSITY_NORMAL)
|
||||
{
|
||||
if ($verbose > $this->output->getVerbosity()) {
|
||||
return;
|
||||
}
|
||||
$this->output->writeln($this->message);
|
||||
}
|
||||
|
||||
public function prepend($string)
|
||||
{
|
||||
if ($string instanceof Message) {
|
||||
$string = $string->getMessage();
|
||||
}
|
||||
$this->message = $string . $this->message;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function append($string)
|
||||
{
|
||||
if ($string instanceof Message) {
|
||||
$string = $string->getMessage();
|
||||
}
|
||||
$this->message .= $string;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function apply($func)
|
||||
{
|
||||
$this->message = call_user_func($func, $this->message);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function center($char)
|
||||
{
|
||||
$this->message = $char . $this->message . $char;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMessage()
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
public function block($style)
|
||||
{
|
||||
$this->message = $this->output->formatHelper->formatBlock($this->message, $style, true);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLength($includeTags = false)
|
||||
{
|
||||
return mb_strwidth($includeTags ? $this->message : strip_tags($this->message), 'utf-8');
|
||||
}
|
||||
|
||||
public static function ucfirst($text)
|
||||
{
|
||||
return mb_strtoupper(mb_substr($text, 0, 1, 'utf-8'), 'utf-8') . mb_substr($text, 1, null, 'utf-8');
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
}
|
||||
59
vendor/codeception/base/src/Codeception/Lib/Console/MessageFactory.php
vendored
Normal file
59
vendor/codeception/base/src/Codeception/Lib/Console/MessageFactory.php
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Console;
|
||||
|
||||
use SebastianBergmann\Comparator\ComparisonFailure;
|
||||
|
||||
/**
|
||||
* MessageFactory
|
||||
**/
|
||||
class MessageFactory
|
||||
{
|
||||
/**
|
||||
* @var DiffFactory
|
||||
*/
|
||||
protected $diffFactory;
|
||||
/**
|
||||
* @var Output
|
||||
*/
|
||||
private $output;
|
||||
|
||||
/**
|
||||
* @var Colorizer
|
||||
*/
|
||||
protected $colorizer;
|
||||
|
||||
/**
|
||||
* MessageFactory constructor.
|
||||
* @param Output $output
|
||||
*/
|
||||
public function __construct(Output $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
$this->diffFactory = new DiffFactory();
|
||||
$this->colorizer = new Colorizer();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @return Message
|
||||
*/
|
||||
public function message($text = '')
|
||||
{
|
||||
return new Message($text, $this->output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ComparisonFailure $failure
|
||||
* @return string
|
||||
*/
|
||||
public function prepareComparisonFailureMessage(ComparisonFailure $failure)
|
||||
{
|
||||
$diff = $this->diffFactory->createDiff($failure);
|
||||
if (!$diff) {
|
||||
return '';
|
||||
}
|
||||
$diff = $this->colorizer->colorize($diff);
|
||||
|
||||
return "\n<comment>- Expected</comment> | <info>+ Actual</info>\n$diff";
|
||||
}
|
||||
}
|
||||
100
vendor/codeception/base/src/Codeception/Lib/Console/Output.php
vendored
Normal file
100
vendor/codeception/base/src/Codeception/Lib/Console/Output.php
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Console;
|
||||
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Helper\FormatterHelper;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
class Output extends ConsoleOutput
|
||||
{
|
||||
protected $config = [
|
||||
'colors' => true,
|
||||
'verbosity' => self::VERBOSITY_NORMAL,
|
||||
'interactive' => true
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\Console\Helper\FormatterHelper
|
||||
*/
|
||||
public $formatHelper;
|
||||
|
||||
public $waitForDebugOutput = true;
|
||||
|
||||
protected $isInteractive = false;
|
||||
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = array_merge($this->config, $config);
|
||||
|
||||
// enable interactive output mode for CLI
|
||||
$this->isInteractive = $this->config['interactive']
|
||||
&& isset($_SERVER['TERM'])
|
||||
&& php_sapi_name() == 'cli'
|
||||
&& $_SERVER['TERM'] != 'linux';
|
||||
|
||||
$formatter = new OutputFormatter($this->config['colors']);
|
||||
$formatter->setStyle('default', new OutputFormatterStyle());
|
||||
$formatter->setStyle('bold', new OutputFormatterStyle(null, null, ['bold']));
|
||||
$formatter->setStyle('focus', new OutputFormatterStyle('magenta', null, ['bold']));
|
||||
$formatter->setStyle('ok', new OutputFormatterStyle('green', null, ['bold']));
|
||||
$formatter->setStyle('error', new OutputFormatterStyle('white', 'red', ['bold']));
|
||||
$formatter->setStyle('fail', new OutputFormatterStyle('red', null, ['bold']));
|
||||
$formatter->setStyle('pending', new OutputFormatterStyle('yellow', null, ['bold']));
|
||||
$formatter->setStyle('debug', new OutputFormatterStyle('cyan'));
|
||||
$formatter->setStyle('comment', new OutputFormatterStyle('yellow'));
|
||||
$formatter->setStyle('info', new OutputFormatterStyle('green'));
|
||||
|
||||
$this->formatHelper = new FormatterHelper();
|
||||
|
||||
|
||||
parent::__construct($this->config['verbosity'], $this->config['colors'], $formatter);
|
||||
}
|
||||
|
||||
public function isInteractive()
|
||||
{
|
||||
return $this->isInteractive;
|
||||
}
|
||||
|
||||
protected function clean($message)
|
||||
{
|
||||
// clear json serialization
|
||||
$message = str_replace('\/', '/', $message);
|
||||
return $message;
|
||||
}
|
||||
|
||||
public function debug($message)
|
||||
{
|
||||
$message = print_r($message, true);
|
||||
$message = str_replace("\n", "\n ", $message);
|
||||
$message = $this->clean($message);
|
||||
$message = OutputFormatter::escape($message);
|
||||
|
||||
if ($this->waitForDebugOutput) {
|
||||
$this->writeln('');
|
||||
$this->waitForDebugOutput = false;
|
||||
}
|
||||
$this->writeln("<debug> $message</debug>");
|
||||
}
|
||||
|
||||
public function message($message)
|
||||
{
|
||||
$message = call_user_func_array('sprintf', func_get_args());
|
||||
return new Message($message, $this);
|
||||
}
|
||||
|
||||
public function exception(\Exception $e)
|
||||
{
|
||||
$class = get_class($e);
|
||||
|
||||
$this->writeln("");
|
||||
$this->writeln("(![ $class ]!)");
|
||||
$this->writeln($e->getMessage());
|
||||
$this->writeln("");
|
||||
}
|
||||
|
||||
public function notification($message)
|
||||
{
|
||||
$this->writeln("<comment>$message</comment>");
|
||||
}
|
||||
}
|
||||
105
vendor/codeception/base/src/Codeception/Lib/DbPopulator.php
vendored
Normal file
105
vendor/codeception/base/src/Codeception/Lib/DbPopulator.php
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Codeception\Lib;
|
||||
|
||||
/**
|
||||
* Populates a db using a parameterized command built from the Db module configuration.
|
||||
*/
|
||||
class DbPopulator
|
||||
{
|
||||
/**
|
||||
* The command to be executed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $builtCommand;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Constructs a DbPopulator object for the given command and Db module.
|
||||
*
|
||||
* @param $config
|
||||
* @internal param string $command The parameterized command to evaluate and execute later.
|
||||
* @internal param Codeception\Module\Db|null $dbModule The Db module used to build the populator command or null.
|
||||
*/
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
$command = $this->config['populator'];
|
||||
$this->builtCommand = $this->buildCommand((string) $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds out a command replacing any found `$key` with its value if found in the given configuration.
|
||||
*
|
||||
* Process any $key found in the configuration array as a key of the array and replaces it with
|
||||
* the found value for the key. Example:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
*
|
||||
* $command = 'Hello $name';
|
||||
* $config = ['name' => 'Mauro'];
|
||||
*
|
||||
* // With the above parameters it will return `'Hello Mauro'`.
|
||||
* ```
|
||||
*
|
||||
* @param string $command The command to be evaluated using the given config
|
||||
* @param array $config The configuration values used to replace any found $keys with values from this array.
|
||||
* @return string The resulting command string after evaluating any configuration's key
|
||||
*/
|
||||
protected function buildCommand($command)
|
||||
{
|
||||
$dsn = isset($this->config['dsn']) ? $this->config['dsn'] : '';
|
||||
$dsnVars = [];
|
||||
$dsnWithoutDriver = preg_replace('/^[a-z]+:/i', '', $dsn);
|
||||
foreach (explode(';', $dsnWithoutDriver) as $item) {
|
||||
$keyValueTuple = explode('=', $item);
|
||||
if (count($keyValueTuple) > 1) {
|
||||
list($k, $v) = array_values($keyValueTuple);
|
||||
$dsnVars[$k] = $v;
|
||||
}
|
||||
}
|
||||
$vars = array_merge($dsnVars, $this->config);
|
||||
foreach ($vars as $key => $value) {
|
||||
$vars['$'.$key] = $value;
|
||||
unset($vars[$key]);
|
||||
}
|
||||
return str_replace(array_keys($vars), array_values($vars), $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command built using the Db module configuration.
|
||||
*
|
||||
* Uses the PHP `exec` to spin off a child process for the built command.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$command = $this->getBuiltCommand();
|
||||
codecept_debug("[Db] Executing Populator: `$command`");
|
||||
|
||||
exec($command, $output, $exitCode);
|
||||
|
||||
if (0 !== $exitCode) {
|
||||
throw new \RuntimeException(
|
||||
"The populator command did not end successfully: \n" .
|
||||
" Exit code: $exitCode \n" .
|
||||
" Output:" . implode("\n", $output)
|
||||
);
|
||||
}
|
||||
|
||||
codecept_debug("[Db] Populator Finished.");
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getBuiltCommand()
|
||||
{
|
||||
return $this->builtCommand;
|
||||
}
|
||||
}
|
||||
161
vendor/codeception/base/src/Codeception/Lib/Di.php
vendored
Normal file
161
vendor/codeception/base/src/Codeception/Lib/Di.php
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
namespace Codeception\Lib;
|
||||
|
||||
use Codeception\Exception\InjectionException;
|
||||
|
||||
class Di
|
||||
{
|
||||
const DEFAULT_INJECT_METHOD_NAME = '_inject';
|
||||
|
||||
protected $container = [];
|
||||
|
||||
/**
|
||||
* @var Di
|
||||
*/
|
||||
protected $fallback;
|
||||
|
||||
public function __construct($fallback = null)
|
||||
{
|
||||
$this->fallback = $fallback;
|
||||
}
|
||||
|
||||
public function get($className)
|
||||
{
|
||||
// normalize namespace
|
||||
$className = ltrim($className, '\\');
|
||||
return isset($this->container[$className]) ? $this->container[$className] : null;
|
||||
}
|
||||
|
||||
public function set($class)
|
||||
{
|
||||
$this->container[get_class($class)] = $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param array $constructorArgs
|
||||
* @param string $injectMethodName Method which will be invoked after object creation;
|
||||
* Resolved dependencies will be passed to it as arguments
|
||||
* @throws InjectionException
|
||||
* @return null|object
|
||||
*/
|
||||
public function instantiate(
|
||||
$className,
|
||||
$constructorArgs = null,
|
||||
$injectMethodName = self::DEFAULT_INJECT_METHOD_NAME
|
||||
) {
|
||||
// normalize namespace
|
||||
$className = ltrim($className, '\\');
|
||||
|
||||
// get class from container
|
||||
if (isset($this->container[$className])) {
|
||||
if ($this->container[$className] instanceof $className) {
|
||||
return $this->container[$className];
|
||||
}
|
||||
|
||||
throw new InjectionException("Failed to resolve cyclic dependencies for class '$className'");
|
||||
}
|
||||
|
||||
// get class from parent container
|
||||
if ($this->fallback) {
|
||||
if ($class = $this->fallback->get($className)) {
|
||||
return $class;
|
||||
}
|
||||
}
|
||||
|
||||
$this->container[$className] = false; // flag that object is being instantiated
|
||||
|
||||
$reflectedClass = new \ReflectionClass($className);
|
||||
if (!$reflectedClass->isInstantiable()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$reflectedConstructor = $reflectedClass->getConstructor();
|
||||
if (is_null($reflectedConstructor)) {
|
||||
$object = new $className;
|
||||
} else {
|
||||
try {
|
||||
if (!$constructorArgs) {
|
||||
$constructorArgs = $this->prepareArgs($reflectedConstructor);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw new InjectionException("Failed to create instance of '$className'. " . $e->getMessage());
|
||||
}
|
||||
$object = $reflectedClass->newInstanceArgs($constructorArgs);
|
||||
}
|
||||
|
||||
if ($injectMethodName) {
|
||||
$this->injectDependencies($object, $injectMethodName);
|
||||
}
|
||||
|
||||
$this->container[$className] = $object;
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $object
|
||||
* @param string $injectMethodName Method which will be invoked with resolved dependencies as its arguments
|
||||
* @throws InjectionException
|
||||
*/
|
||||
public function injectDependencies($object, $injectMethodName = self::DEFAULT_INJECT_METHOD_NAME, $defaults = [])
|
||||
{
|
||||
if (!is_object($object)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$reflectedObject = new \ReflectionObject($object);
|
||||
if (!$reflectedObject->hasMethod($injectMethodName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$reflectedMethod = $reflectedObject->getMethod($injectMethodName);
|
||||
try {
|
||||
$args = $this->prepareArgs($reflectedMethod, $defaults);
|
||||
} catch (\Exception $e) {
|
||||
$msg = $e->getMessage();
|
||||
if ($e->getPrevious()) { // injection failed because PHP code is invalid. See #3869
|
||||
$msg .= '; '. $e->getPrevious();
|
||||
}
|
||||
throw new InjectionException(
|
||||
"Failed to inject dependencies in instance of '{$reflectedObject->name}'. $msg"
|
||||
);
|
||||
}
|
||||
|
||||
if (!$reflectedMethod->isPublic()) {
|
||||
$reflectedMethod->setAccessible(true);
|
||||
}
|
||||
$reflectedMethod->invokeArgs($object, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ReflectionMethod $method
|
||||
* @param $defaults
|
||||
* @throws InjectionException
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareArgs(\ReflectionMethod $method, $defaults = [])
|
||||
{
|
||||
$args = [];
|
||||
$parameters = $method->getParameters();
|
||||
foreach ($parameters as $k => $parameter) {
|
||||
$dependency = $parameter->getClass();
|
||||
if (is_null($dependency)) {
|
||||
if (!$parameter->isOptional()) {
|
||||
if (!isset($defaults[$k])) {
|
||||
throw new InjectionException("Parameter '$parameter->name' must have default value.");
|
||||
}
|
||||
$args[] = $defaults[$k];
|
||||
continue;
|
||||
}
|
||||
$args[] = $parameter->getDefaultValue();
|
||||
} else {
|
||||
$arg = $this->instantiate($dependency->name);
|
||||
if (is_null($arg)) {
|
||||
throw new InjectionException("Failed to resolve dependency '{$dependency->name}'.");
|
||||
}
|
||||
$args[] = $arg;
|
||||
}
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
}
|
||||
152
vendor/codeception/base/src/Codeception/Lib/Driver/AmazonSQS.php
vendored
Normal file
152
vendor/codeception/base/src/Codeception/Lib/Driver/AmazonSQS.php
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Driver;
|
||||
|
||||
use Codeception\Exception\TestRuntimeException;
|
||||
use Codeception\Lib\Interfaces\Queue;
|
||||
use Aws\Sqs\SqsClient;
|
||||
use Aws\Credentials\Credentials;
|
||||
|
||||
class AmazonSQS implements Queue
|
||||
{
|
||||
protected $queue;
|
||||
|
||||
/**
|
||||
* Connect to the queueing server. (AWS, Iron.io and Beanstalkd)
|
||||
* @param array $config
|
||||
* @return
|
||||
*/
|
||||
public function openConnection($config)
|
||||
{
|
||||
$params = [
|
||||
'region' => $config['region'],
|
||||
];
|
||||
|
||||
if (! empty($config['key']) && ! empty($config['secret'])) {
|
||||
$params['credentials'] = new Credentials($config['key'], $config['secret']);
|
||||
}
|
||||
|
||||
if (! empty($config['profile'])) {
|
||||
$params['profile'] = $config['profile'];
|
||||
}
|
||||
|
||||
if (! empty($config['version'])) {
|
||||
$params['version'] = $config['version'];
|
||||
}
|
||||
|
||||
if (! empty($config['endpoint'])) {
|
||||
$params['endpoint'] = $config['endpoint'];
|
||||
}
|
||||
|
||||
$this->queue = new SqsClient($params);
|
||||
if (!$this->queue) {
|
||||
throw new TestRuntimeException('connection failed or timed-out.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post/Put a message on to the queue server
|
||||
*
|
||||
* @param string $message Message Body to be send
|
||||
* @param string $queue Queue Name
|
||||
*/
|
||||
public function addMessageToQueue($message, $queue)
|
||||
{
|
||||
$this->queue->sendMessage([
|
||||
'QueueUrl' => $this->getQueueURL($queue),
|
||||
'MessageBody' => $message,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of queues/tubes on the queueing server
|
||||
*
|
||||
* @return array Array of Queues
|
||||
*/
|
||||
public function getQueues()
|
||||
{
|
||||
$queueNames = [];
|
||||
$queues = $this->queue->listQueues(['QueueNamePrefix' => ''])->get('QueueUrls');
|
||||
foreach ($queues as $queue) {
|
||||
$tokens = explode('/', $queue);
|
||||
$queueNames[] = $tokens[sizeof($tokens) - 1];
|
||||
}
|
||||
return $queueNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the current number of messages on the queue.
|
||||
*
|
||||
* @param $queue Queue Name
|
||||
*
|
||||
* @return int Count
|
||||
*/
|
||||
public function getMessagesCurrentCountOnQueue($queue)
|
||||
{
|
||||
return $this->queue->getQueueAttributes([
|
||||
'QueueUrl' => $this->getQueueURL($queue),
|
||||
'AttributeNames' => ['ApproximateNumberOfMessages'],
|
||||
])->get('Attributes')['ApproximateNumberOfMessages'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the total number of messages on the queue.
|
||||
*
|
||||
* @param $queue Queue Name
|
||||
*
|
||||
* @return int Count
|
||||
*/
|
||||
public function getMessagesTotalCountOnQueue($queue)
|
||||
{
|
||||
return $this->queue->getQueueAttributes([
|
||||
'QueueUrl' => $this->getQueueURL($queue),
|
||||
'AttributeNames' => ['ApproximateNumberOfMessages'],
|
||||
])->get('Attributes')['ApproximateNumberOfMessages'];
|
||||
}
|
||||
|
||||
public function clearQueue($queue)
|
||||
{
|
||||
$queueURL = $this->getQueueURL($queue);
|
||||
while (true) {
|
||||
$res = $this->queue->receiveMessage(['QueueUrl' => $queueURL]);
|
||||
|
||||
if (!$res->getPath('Messages')) {
|
||||
return;
|
||||
}
|
||||
foreach ($res->getPath('Messages') as $msg) {
|
||||
$this->queue->deleteMessage([
|
||||
'QueueUrl' => $queueURL,
|
||||
'ReceiptHandle' => $msg['ReceiptHandle']
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the queue/tube URL from the queue name (AWS function only)
|
||||
*
|
||||
* @param $queue Queue Name
|
||||
*
|
||||
* @return string Queue URL
|
||||
*/
|
||||
private function getQueueURL($queue)
|
||||
{
|
||||
$queues = $this->queue->listQueues(['QueueNamePrefix' => ''])->get('QueueUrls');
|
||||
foreach ($queues as $queueURL) {
|
||||
$tokens = explode('/', $queueURL);
|
||||
if (strtolower($queue) == strtolower($tokens[sizeof($tokens) - 1])) {
|
||||
return $queueURL;
|
||||
}
|
||||
}
|
||||
throw new TestRuntimeException('queue [' . $queue . '] not found');
|
||||
}
|
||||
|
||||
public function getRequiredConfig()
|
||||
{
|
||||
return ['region'];
|
||||
}
|
||||
|
||||
public function getDefaultConfig()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
90
vendor/codeception/base/src/Codeception/Lib/Driver/Beanstalk.php
vendored
Normal file
90
vendor/codeception/base/src/Codeception/Lib/Driver/Beanstalk.php
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Driver;
|
||||
|
||||
use Codeception\Lib\Interfaces\Queue;
|
||||
use Pheanstalk\Pheanstalk;
|
||||
use Pheanstalk\Exception\ConnectionException;
|
||||
|
||||
class Beanstalk implements Queue
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Pheanstalk
|
||||
*/
|
||||
protected $queue;
|
||||
|
||||
public function openConnection($config)
|
||||
{
|
||||
$this->queue = new Pheanstalk($config['host'], $config['port'], $config['timeout']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post/Put a message on to the queue server
|
||||
*
|
||||
* @param string $message Message Body to be send
|
||||
* @param string $queue Queue Name
|
||||
*/
|
||||
public function addMessageToQueue($message, $queue)
|
||||
{
|
||||
$this->queue->putInTube($queue, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the total number of messages on the queue.
|
||||
*
|
||||
* @param $queue Queue Name
|
||||
*
|
||||
* @return int Count
|
||||
*/
|
||||
public function getMessagesTotalCountOnQueue($queue)
|
||||
{
|
||||
try {
|
||||
return $this->queue->statsTube($queue)['total-jobs'];
|
||||
} catch (ConnectionException $ex) {
|
||||
\PHPUnit\Framework\Assert::fail("queue [$queue] not found");
|
||||
}
|
||||
}
|
||||
|
||||
public function clearQueue($queue = 'default')
|
||||
{
|
||||
while ($job = $this->queue->reserveFromTube($queue, 0)) {
|
||||
$this->queue->delete($job);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of queues/tubes on the queueing server
|
||||
*
|
||||
* @return array Array of Queues
|
||||
*/
|
||||
public function getQueues()
|
||||
{
|
||||
return $this->queue->listTubes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the current number of messages on the queue.
|
||||
*
|
||||
* @param $queue Queue Name
|
||||
*
|
||||
* @return int Count
|
||||
*/
|
||||
public function getMessagesCurrentCountOnQueue($queue)
|
||||
{
|
||||
try {
|
||||
return $this->queue->statsTube($queue)['current-jobs-ready'];
|
||||
} catch (ConnectionException $e) {
|
||||
\PHPUnit\Framework\Assert::fail("queue [$queue] not found");
|
||||
}
|
||||
}
|
||||
|
||||
public function getRequiredConfig()
|
||||
{
|
||||
return ['host'];
|
||||
}
|
||||
|
||||
public function getDefaultConfig()
|
||||
{
|
||||
return ['port' => 11300, 'timeout' => 90];
|
||||
}
|
||||
}
|
||||
381
vendor/codeception/base/src/Codeception/Lib/Driver/Db.php
vendored
Normal file
381
vendor/codeception/base/src/Codeception/Lib/Driver/Db.php
vendored
Normal file
@@ -0,0 +1,381 @@
|
||||
<?php
|
||||
|
||||
namespace Codeception\Lib\Driver;
|
||||
|
||||
use Codeception\Exception\ModuleException;
|
||||
|
||||
class Db
|
||||
{
|
||||
/**
|
||||
* @var \PDO
|
||||
*/
|
||||
protected $dbh;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $dsn;
|
||||
|
||||
protected $user;
|
||||
protected $password;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* @see http://php.net/manual/de/pdo.construct.php
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* associative array with table name => primary-key
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $primaryKeys = [];
|
||||
|
||||
public static function connect($dsn, $user, $password, $options = null)
|
||||
{
|
||||
$dbh = new \PDO($dsn, $user, $password, $options);
|
||||
$dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
*
|
||||
* @param $dsn
|
||||
* @param $user
|
||||
* @param $password
|
||||
* @param [optional] $options
|
||||
*
|
||||
* @see http://php.net/manual/en/pdo.construct.php
|
||||
* @see http://php.net/manual/de/ref.pdo-mysql.php#pdo-mysql.constants
|
||||
*
|
||||
* @return Db|SqlSrv|MySql|Oci|PostgreSql|Sqlite
|
||||
*/
|
||||
public static function create($dsn, $user, $password, $options = null)
|
||||
{
|
||||
$provider = self::getProvider($dsn);
|
||||
|
||||
switch ($provider) {
|
||||
case 'sqlite':
|
||||
return new Sqlite($dsn, $user, $password, $options);
|
||||
case 'mysql':
|
||||
return new MySql($dsn, $user, $password, $options);
|
||||
case 'pgsql':
|
||||
return new PostgreSql($dsn, $user, $password, $options);
|
||||
case 'mssql':
|
||||
case 'dblib':
|
||||
case 'sqlsrv':
|
||||
return new SqlSrv($dsn, $user, $password, $options);
|
||||
case 'oci':
|
||||
return new Oci($dsn, $user, $password, $options);
|
||||
default:
|
||||
return new Db($dsn, $user, $password, $options);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getProvider($dsn)
|
||||
{
|
||||
return substr($dsn, 0, strpos($dsn, ':'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $dsn
|
||||
* @param $user
|
||||
* @param $password
|
||||
* @param [optional] $options
|
||||
*
|
||||
* @see http://php.net/manual/en/pdo.construct.php
|
||||
* @see http://php.net/manual/de/ref.pdo-mysql.php#pdo-mysql.constants
|
||||
*/
|
||||
public function __construct($dsn, $user, $password, $options = null)
|
||||
{
|
||||
$this->dbh = new \PDO($dsn, $user, $password, $options);
|
||||
$this->dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$this->dsn = $dsn;
|
||||
$this->user = $user;
|
||||
$this->password = $password;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->dbh->inTransaction()) {
|
||||
$this->dbh->rollBack();
|
||||
}
|
||||
$this->dbh = null;
|
||||
}
|
||||
|
||||
public function getDbh()
|
||||
{
|
||||
return $this->dbh;
|
||||
}
|
||||
|
||||
public function getDb()
|
||||
{
|
||||
$matches = [];
|
||||
$matched = preg_match('~dbname=(\w+)~s', $this->dsn, $matches);
|
||||
if (!$matched) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
public function cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the lock waiting interval for the database session
|
||||
* @param int $seconds
|
||||
* @return void
|
||||
*/
|
||||
public function setWaitLock($seconds)
|
||||
{
|
||||
}
|
||||
|
||||
public function load($sql)
|
||||
{
|
||||
$query = '';
|
||||
$delimiter = ';';
|
||||
$delimiterLength = 1;
|
||||
|
||||
foreach ($sql as $sqlLine) {
|
||||
if (preg_match('/DELIMITER ([\;\$\|\\\\]+)/i', $sqlLine, $match)) {
|
||||
$delimiter = $match[1];
|
||||
$delimiterLength = strlen($delimiter);
|
||||
continue;
|
||||
}
|
||||
|
||||
$parsed = $this->sqlLine($sqlLine);
|
||||
if ($parsed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$query .= "\n" . rtrim($sqlLine);
|
||||
|
||||
if (substr($query, -1 * $delimiterLength, $delimiterLength) == $delimiter) {
|
||||
$this->sqlQuery(substr($query, 0, -1 * $delimiterLength));
|
||||
$query = '';
|
||||
}
|
||||
}
|
||||
|
||||
if ($query !== '') {
|
||||
$this->sqlQuery($query);
|
||||
}
|
||||
}
|
||||
|
||||
public function insert($tableName, array &$data)
|
||||
{
|
||||
$columns = array_map(
|
||||
[$this, 'getQuotedName'],
|
||||
array_keys($data)
|
||||
);
|
||||
|
||||
return sprintf(
|
||||
"INSERT INTO %s (%s) VALUES (%s)",
|
||||
$this->getQuotedName($tableName),
|
||||
implode(', ', $columns),
|
||||
implode(', ', array_fill(0, count($data), '?'))
|
||||
);
|
||||
}
|
||||
|
||||
public function select($column, $table, array &$criteria)
|
||||
{
|
||||
$where = $this->generateWhereClause($criteria);
|
||||
|
||||
$query = "SELECT %s FROM %s %s";
|
||||
return sprintf($query, $column, $this->getQuotedName($table), $where);
|
||||
}
|
||||
|
||||
private function getSupportedOperators()
|
||||
{
|
||||
return [
|
||||
'like',
|
||||
'!=',
|
||||
'<=',
|
||||
'>=',
|
||||
'<',
|
||||
'>',
|
||||
];
|
||||
}
|
||||
|
||||
protected function generateWhereClause(array &$criteria)
|
||||
{
|
||||
if (empty($criteria)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$operands = $this->getSupportedOperators();
|
||||
|
||||
$params = [];
|
||||
foreach ($criteria as $k => $v) {
|
||||
if ($v === null) {
|
||||
$params[] = $this->getQuotedName($k) . " IS NULL ";
|
||||
unset($criteria[$k]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$hasOperand = false; // search for equals - no additional operand given
|
||||
|
||||
foreach ($operands as $operand) {
|
||||
if (!stripos($k, " $operand") > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hasOperand = true;
|
||||
$k = str_ireplace(" $operand", '', $k);
|
||||
$operand = strtoupper($operand);
|
||||
$params[] = $this->getQuotedName($k) . " $operand ? ";
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$hasOperand) {
|
||||
$params[] = $this->getQuotedName($k) . " = ? ";
|
||||
}
|
||||
}
|
||||
|
||||
return 'WHERE ' . implode('AND ', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use deleteQueryByCriteria instead
|
||||
*/
|
||||
public function deleteQuery($table, $id, $primaryKey = 'id')
|
||||
{
|
||||
$query = 'DELETE FROM ' . $this->getQuotedName($table) . ' WHERE ' . $this->getQuotedName($primaryKey) . ' = ?';
|
||||
$this->executeQuery($query, [$id]);
|
||||
}
|
||||
|
||||
public function deleteQueryByCriteria($table, array $criteria)
|
||||
{
|
||||
$where = $this->generateWhereClause($criteria);
|
||||
|
||||
$query = 'DELETE FROM ' . $this->getQuotedName($table) . ' ' . $where;
|
||||
$this->executeQuery($query, array_values($criteria));
|
||||
}
|
||||
|
||||
public function lastInsertId($table)
|
||||
{
|
||||
return $this->getDbh()->lastInsertId();
|
||||
}
|
||||
|
||||
public function getQuotedName($name)
|
||||
{
|
||||
return '"' . str_replace('.', '"."', $name) . '"';
|
||||
}
|
||||
|
||||
protected function sqlLine($sql)
|
||||
{
|
||||
$sql = trim($sql);
|
||||
return (
|
||||
$sql === ''
|
||||
|| $sql === ';'
|
||||
|| preg_match('~^((--.*?)|(#))~s', $sql)
|
||||
);
|
||||
}
|
||||
|
||||
protected function sqlQuery($query)
|
||||
{
|
||||
try {
|
||||
$this->dbh->exec($query);
|
||||
} catch (\PDOException $e) {
|
||||
throw new ModuleException(
|
||||
'Codeception\Module\Db',
|
||||
$e->getMessage() . "\nSQL query being executed: " . $query
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function executeQuery($query, array $params)
|
||||
{
|
||||
$sth = $this->dbh->prepare($query);
|
||||
if (!$sth) {
|
||||
throw new \Exception("Query '$query' can't be prepared.");
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
foreach ($params as $value) {
|
||||
$i++;
|
||||
if (is_bool($value)) {
|
||||
$type = \PDO::PARAM_BOOL;
|
||||
} elseif (is_int($value)) {
|
||||
$type = \PDO::PARAM_INT;
|
||||
} else {
|
||||
$type = \PDO::PARAM_STR;
|
||||
}
|
||||
$sth->bindValue($i, $value, $type);
|
||||
}
|
||||
|
||||
$sth->execute();
|
||||
return $sth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tableName
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
* @deprecated use getPrimaryKey instead
|
||||
*/
|
||||
public function getPrimaryColumn($tableName)
|
||||
{
|
||||
$primaryKey = $this->getPrimaryKey($tableName);
|
||||
if (empty($primaryKey)) {
|
||||
return null;
|
||||
} elseif (count($primaryKey) > 1) {
|
||||
throw new \Exception(
|
||||
'getPrimaryColumn method does not support composite primary keys, use getPrimaryKey instead'
|
||||
);
|
||||
}
|
||||
|
||||
return $primaryKey[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tableName
|
||||
*
|
||||
* @return array[string]
|
||||
*/
|
||||
public function getPrimaryKey($tableName)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function flushPrimaryColumnCache()
|
||||
{
|
||||
$this->primaryKeys = [];
|
||||
|
||||
return empty($this->primaryKeys);
|
||||
}
|
||||
|
||||
public function update($table, array $data, array $criteria)
|
||||
{
|
||||
if (empty($data)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Query update can't be prepared without data."
|
||||
);
|
||||
}
|
||||
|
||||
$set = [];
|
||||
foreach ($data as $column => $value) {
|
||||
$set[] = $this->getQuotedName($column) . " = ?";
|
||||
}
|
||||
|
||||
$where = $this->generateWhereClause($criteria);
|
||||
|
||||
return sprintf('UPDATE %s SET %s %s', $this->getQuotedName($table), implode(', ', $set), $where);
|
||||
}
|
||||
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
}
|
||||
176
vendor/codeception/base/src/Codeception/Lib/Driver/Facebook.php
vendored
Normal file
176
vendor/codeception/base/src/Codeception/Lib/Driver/Facebook.php
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
/**
|
||||
* @author tiger
|
||||
*/
|
||||
|
||||
namespace Codeception\Lib\Driver;
|
||||
|
||||
use Facebook\Facebook as FacebookSDK;
|
||||
|
||||
class Facebook
|
||||
{
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
protected $logCallback;
|
||||
|
||||
/**
|
||||
* @var FacebookSDK
|
||||
*/
|
||||
protected $fb;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $appId;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $appSecret;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $appToken;
|
||||
|
||||
/**
|
||||
* Facebook constructor.
|
||||
*
|
||||
* @param array $config
|
||||
* @param callable|null $logCallback
|
||||
*/
|
||||
public function __construct($config, $logCallback = null)
|
||||
{
|
||||
if (is_callable($logCallback)) {
|
||||
$this->logCallback = $logCallback;
|
||||
}
|
||||
|
||||
$this->fb = new FacebookSDK(
|
||||
[
|
||||
'app_id' => $config['app_id'],
|
||||
'app_secret' => $config['secret'],
|
||||
'default_graph_version' => 'v2.5', //TODO add to config
|
||||
]
|
||||
);
|
||||
|
||||
$this->appId = $config['app_id'];
|
||||
$this->appSecret = $config['secret'];
|
||||
$this->appToken = $this->appId . '|' . $this->appSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $permissions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function createTestUser($name, array $permissions)
|
||||
{
|
||||
$response = $this->executeFacebookRequest(
|
||||
'POST',
|
||||
$this->appId . '/accounts/test-users',
|
||||
[
|
||||
'name' => $name,
|
||||
'installed' => true,
|
||||
'permissions' => $permissions
|
||||
]
|
||||
);
|
||||
|
||||
return $response->getDecodedBody();
|
||||
}
|
||||
|
||||
public function deleteTestUser($testUserID)
|
||||
{
|
||||
$this->executeFacebookRequest('DELETE', '/' . $testUserID);
|
||||
}
|
||||
|
||||
public function getTestUserInfo($testUserAccessToken)
|
||||
{
|
||||
$response = $this->executeFacebookRequest(
|
||||
'GET',
|
||||
'/me',
|
||||
$parameters = [],
|
||||
$testUserAccessToken
|
||||
);
|
||||
|
||||
return $response->getDecodedBody();
|
||||
}
|
||||
|
||||
public function getLastPostsForTestUser($testUserAccessToken)
|
||||
{
|
||||
$response = $this->executeFacebookRequest(
|
||||
'GET',
|
||||
'/me/feed',
|
||||
$parameters = [],
|
||||
$testUserAccessToken
|
||||
);
|
||||
|
||||
return $response->getDecodedBody();
|
||||
}
|
||||
|
||||
public function getVisitedPlaceTagForTestUser($placeId, $testUserAccessToken)
|
||||
{
|
||||
$response = $this->executeFacebookRequest(
|
||||
'GET',
|
||||
"/$placeId",
|
||||
$parameters = [],
|
||||
$testUserAccessToken
|
||||
);
|
||||
|
||||
return $response->getDecodedBody();
|
||||
}
|
||||
|
||||
public function sendPostToFacebook($testUserAccessToken, array $parameters)
|
||||
{
|
||||
$response = $this->executeFacebookRequest(
|
||||
'POST',
|
||||
'/me/feed',
|
||||
$parameters,
|
||||
$testUserAccessToken
|
||||
);
|
||||
|
||||
return $response->getDecodedBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param string $endpoint
|
||||
* @param array $parameters
|
||||
* @param string $token
|
||||
*
|
||||
* @return \Facebook\FacebookResponse
|
||||
*/
|
||||
private function executeFacebookRequest($method, $endpoint, array $parameters = [], $token = null)
|
||||
{
|
||||
if (is_callable($this->logCallback)) {
|
||||
//used only for debugging:
|
||||
call_user_func($this->logCallback, 'Facebook API request', func_get_args());
|
||||
}
|
||||
|
||||
if (!$token) {
|
||||
$token = $this->appToken;
|
||||
}
|
||||
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
$response = $this->fb->get($endpoint, $token);
|
||||
break;
|
||||
case 'POST':
|
||||
$response = $this->fb->post($endpoint, $parameters, $token);
|
||||
break;
|
||||
case 'DELETE':
|
||||
$response = $this->fb->delete($endpoint, $parameters, $token);
|
||||
break;
|
||||
default:
|
||||
throw new \Exception("Facebook driver exception, please add support for method: " . $method);
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_callable($this->logCallback)) {
|
||||
call_user_func($this->logCallback, 'Facebook API response', $response->getDecodedBody());
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
106
vendor/codeception/base/src/Codeception/Lib/Driver/Iron.php
vendored
Normal file
106
vendor/codeception/base/src/Codeception/Lib/Driver/Iron.php
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Driver;
|
||||
|
||||
use Codeception\Lib\Interfaces\Queue;
|
||||
|
||||
class Iron implements Queue
|
||||
{
|
||||
/**
|
||||
* @var \IronMQ
|
||||
*/
|
||||
protected $queue;
|
||||
|
||||
/**
|
||||
* Connect to the queueing server. (AWS, Iron.io and Beanstalkd)
|
||||
* @param array $config
|
||||
* @return
|
||||
*/
|
||||
public function openConnection($config)
|
||||
{
|
||||
$this->queue = new \IronMQ([
|
||||
"token" => $config['token'],
|
||||
"project_id" => $config['project'],
|
||||
"host" => $config['host']
|
||||
]);
|
||||
if (!$this->queue) {
|
||||
\PHPUnit\Framework\Assert::fail('connection failed or timed-out.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post/Put a message on to the queue server
|
||||
*
|
||||
* @param string $message Message Body to be send
|
||||
* @param string $queue Queue Name
|
||||
*/
|
||||
public function addMessageToQueue($message, $queue)
|
||||
{
|
||||
$this->queue->postMessage($queue, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of queues/tubes on the queueing server
|
||||
*
|
||||
* @return array Array of Queues
|
||||
*/
|
||||
public function getQueues()
|
||||
{
|
||||
// Format the output to suit
|
||||
$queues = [];
|
||||
foreach ($this->queue->getQueues() as $queue) {
|
||||
$queues[] = $queue->name;
|
||||
}
|
||||
return $queues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the current number of messages on the queue.
|
||||
*
|
||||
* @param $queue Queue Name
|
||||
*
|
||||
* @return int Count
|
||||
*/
|
||||
public function getMessagesCurrentCountOnQueue($queue)
|
||||
{
|
||||
try {
|
||||
return $this->queue->getQueue($queue)->size;
|
||||
} catch (\Http_Exception $ex) {
|
||||
\PHPUnit\Framework\Assert::fail("queue [$queue] not found");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the total number of messages on the queue.
|
||||
*
|
||||
* @param $queue Queue Name
|
||||
*
|
||||
* @return int Count
|
||||
*/
|
||||
public function getMessagesTotalCountOnQueue($queue)
|
||||
{
|
||||
try {
|
||||
return $this->queue->getQueue($queue)->total_messages;
|
||||
} catch (\Http_Exception $e) {
|
||||
\PHPUnit\Framework\Assert::fail("queue [$queue] not found");
|
||||
}
|
||||
}
|
||||
|
||||
public function clearQueue($queue)
|
||||
{
|
||||
try {
|
||||
$this->queue->clearQueue($queue);
|
||||
} catch (\Http_Exception $ex) {
|
||||
\PHPUnit\Framework\Assert::fail("queue [$queue] not found");
|
||||
}
|
||||
}
|
||||
|
||||
public function getRequiredConfig()
|
||||
{
|
||||
return ['host', 'token', 'project'];
|
||||
}
|
||||
|
||||
public function getDefaultConfig()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
264
vendor/codeception/base/src/Codeception/Lib/Driver/MongoDb.php
vendored
Normal file
264
vendor/codeception/base/src/Codeception/Lib/Driver/MongoDb.php
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
|
||||
namespace Codeception\Lib\Driver;
|
||||
|
||||
use Codeception\Exception\ModuleConfigException;
|
||||
use Codeception\Exception\ModuleException;
|
||||
use MongoDB\Database;
|
||||
|
||||
class MongoDb
|
||||
{
|
||||
const DEFAULT_PORT = 27017;
|
||||
|
||||
private $legacy;
|
||||
private $dbh;
|
||||
private $dsn;
|
||||
private $dbName;
|
||||
private $host;
|
||||
private $user;
|
||||
private $password;
|
||||
private $client;
|
||||
private $quiet = '';
|
||||
|
||||
public static function connect($dsn, $user, $password)
|
||||
{
|
||||
throw new \Exception(__CLASS__ . '::connect() - hm, it looked like this method had become obsolete...');
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the Mongo server using the MongoDB extension.
|
||||
*/
|
||||
protected function setupMongoDB($dsn, $options)
|
||||
{
|
||||
try {
|
||||
$this->client = new \MongoDB\Client($dsn, $options);
|
||||
$this->dbh = $this->client->selectDatabase($this->dbName);
|
||||
} catch (\MongoDB\Driver\Exception $e) {
|
||||
throw new ModuleException($this, sprintf('Failed to open Mongo connection: %s', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the Mongo server using the legacy mongo extension.
|
||||
*/
|
||||
protected function setupMongo($dsn, $options)
|
||||
{
|
||||
try {
|
||||
$this->client = new \MongoClient($dsn, $options);
|
||||
$this->dbh = $this->client->selectDB($this->dbName);
|
||||
} catch (\MongoConnectionException $e) {
|
||||
throw new ModuleException($this, sprintf('Failed to open Mongo connection: %s', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up the Mongo database using the MongoDB extension.
|
||||
*/
|
||||
protected function cleanupMongoDB()
|
||||
{
|
||||
try {
|
||||
$this->dbh->drop();
|
||||
} catch (\MongoDB\Driver\Exception $e) {
|
||||
throw new \Exception(sprintf('Failed to drop the DB: %s', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up the Mongo database using the legacy Mongo extension.
|
||||
*/
|
||||
protected function cleanupMongo()
|
||||
{
|
||||
try {
|
||||
$list = $this->dbh->listCollections();
|
||||
} catch (\MongoException $e) {
|
||||
throw new \Exception(sprintf('Failed to list collections of the DB: %s', $e->getMessage()));
|
||||
}
|
||||
foreach ($list as $collection) {
|
||||
try {
|
||||
$collection->drop();
|
||||
} catch (\MongoException $e) {
|
||||
throw new \Exception(sprintf('Failed to drop collection: %s', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* $dsn has to contain db_name after the host. E.g. "mongodb://localhost:27017/mongo_test_db"
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @param $dsn
|
||||
* @param $user
|
||||
* @param $password
|
||||
*
|
||||
* @throws ModuleConfigException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($dsn, $user, $password)
|
||||
{
|
||||
$this->legacy = extension_loaded('mongodb') === false &&
|
||||
class_exists('\\MongoClient') &&
|
||||
strpos(\MongoClient::VERSION, 'mongofill') === false;
|
||||
|
||||
/* defining DB name */
|
||||
$this->dbName = preg_replace('/\?.*/', '', substr($dsn, strrpos($dsn, '/') + 1));
|
||||
|
||||
if (strlen($this->dbName) == 0) {
|
||||
throw new ModuleConfigException($this, 'Please specify valid $dsn with DB name after the host:port');
|
||||
}
|
||||
|
||||
/* defining host */
|
||||
if (strpos($dsn, 'mongodb://') !== false) {
|
||||
$this->host = str_replace('mongodb://', '', preg_replace('/\?.*/', '', $dsn));
|
||||
} else {
|
||||
$this->host = $dsn;
|
||||
}
|
||||
$this->host = rtrim(str_replace($this->dbName, '', $this->host), '/');
|
||||
|
||||
$options = [
|
||||
'connect' => true
|
||||
];
|
||||
|
||||
if ($user && $password) {
|
||||
$options += [
|
||||
'username' => $user,
|
||||
'password' => $password
|
||||
];
|
||||
}
|
||||
|
||||
$this->{$this->legacy ? 'setupMongo' : 'setupMongoDB'}($dsn, $options);
|
||||
|
||||
$this->dsn = $dsn;
|
||||
$this->user = $user;
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
*
|
||||
* @param $dsn
|
||||
* @param $user
|
||||
* @param $password
|
||||
*
|
||||
* @return MongoDb
|
||||
*/
|
||||
public static function create($dsn, $user, $password)
|
||||
{
|
||||
return new MongoDb($dsn, $user, $password);
|
||||
}
|
||||
|
||||
public function cleanup()
|
||||
{
|
||||
$this->{$this->legacy ? 'cleanupMongo' : 'cleanupMongoDB'}();
|
||||
}
|
||||
|
||||
/**
|
||||
* dump file has to be a javascript document where one can use all the mongo shell's commands
|
||||
* just FYI: this file can be easily created be RockMongo's export button
|
||||
*
|
||||
* @param $dumpFile
|
||||
*/
|
||||
public function load($dumpFile)
|
||||
{
|
||||
$cmd = sprintf(
|
||||
'mongo %s %s%s',
|
||||
$this->host . '/' . $this->dbName,
|
||||
$this->createUserPasswordCmdString(),
|
||||
escapeshellarg($dumpFile)
|
||||
);
|
||||
shell_exec($cmd);
|
||||
}
|
||||
|
||||
public function loadFromMongoDump($dumpFile)
|
||||
{
|
||||
list($host, $port) = $this->getHostPort();
|
||||
$cmd = sprintf(
|
||||
"mongorestore %s --host %s --port %s -d %s %s %s",
|
||||
$this->quiet,
|
||||
$host,
|
||||
$port,
|
||||
$this->dbName,
|
||||
$this->createUserPasswordCmdString(),
|
||||
escapeshellarg($dumpFile)
|
||||
);
|
||||
shell_exec($cmd);
|
||||
}
|
||||
|
||||
public function loadFromTarGzMongoDump($dumpFile)
|
||||
{
|
||||
list($host, $port) = $this->getHostPort();
|
||||
$getDirCmd = sprintf(
|
||||
"tar -tf %s | awk 'BEGIN { FS = \"/\" } ; { print $1 }' | uniq",
|
||||
escapeshellarg($dumpFile)
|
||||
);
|
||||
$dirCountCmd = $getDirCmd . ' | wc -l';
|
||||
if (trim(shell_exec($dirCountCmd)) !== '1') {
|
||||
throw new ModuleException(
|
||||
$this,
|
||||
'Archive MUST contain single directory with db dump'
|
||||
);
|
||||
}
|
||||
$dirName = trim(shell_exec($getDirCmd));
|
||||
$cmd = sprintf(
|
||||
'tar -xzf %s && mongorestore %s --host %s --port %s -d %s %s %s && rm -r %s',
|
||||
escapeshellarg($dumpFile),
|
||||
$this->quiet,
|
||||
$host,
|
||||
$port,
|
||||
$this->dbName,
|
||||
$this->createUserPasswordCmdString(),
|
||||
$dirName,
|
||||
$dirName
|
||||
);
|
||||
shell_exec($cmd);
|
||||
}
|
||||
|
||||
private function createUserPasswordCmdString()
|
||||
{
|
||||
if ($this->user && $this->password) {
|
||||
return sprintf(
|
||||
'--username %s --password %s ',
|
||||
$this->user,
|
||||
$this->password
|
||||
);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getDbh()
|
||||
{
|
||||
return $this->dbh;
|
||||
}
|
||||
|
||||
public function setDatabase($dbName)
|
||||
{
|
||||
$this->dbh = $this->client->{$this->legacy ? 'selectDB' : 'selectDatabase'}($dbName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this driver is using the legacy extension or not.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isLegacy()
|
||||
{
|
||||
return $this->legacy;
|
||||
}
|
||||
|
||||
private function getHostPort()
|
||||
{
|
||||
$hostPort = explode(':', $this->host);
|
||||
if (count($hostPort) === 2) {
|
||||
return $hostPort;
|
||||
}
|
||||
if (count($hostPort) === 1) {
|
||||
return [$hostPort[0], self::DEFAULT_PORT];
|
||||
}
|
||||
throw new ModuleException($this, '$dsn MUST be like (mongodb://)<host>:<port>/<db name>');
|
||||
}
|
||||
|
||||
public function setQuiet($quiet)
|
||||
{
|
||||
$this->quiet = $quiet ? '--quiet' : '';
|
||||
}
|
||||
}
|
||||
50
vendor/codeception/base/src/Codeception/Lib/Driver/MySql.php
vendored
Normal file
50
vendor/codeception/base/src/Codeception/Lib/Driver/MySql.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Driver;
|
||||
|
||||
class MySql extends Db
|
||||
{
|
||||
public function cleanup()
|
||||
{
|
||||
$this->dbh->exec('SET FOREIGN_KEY_CHECKS=0;');
|
||||
$res = $this->dbh->query("SHOW FULL TABLES WHERE TABLE_TYPE LIKE '%TABLE';")->fetchAll();
|
||||
foreach ($res as $row) {
|
||||
$this->dbh->exec('drop table `' . $row[0] . '`');
|
||||
}
|
||||
$this->dbh->exec('SET FOREIGN_KEY_CHECKS=1;');
|
||||
}
|
||||
|
||||
protected function sqlQuery($query)
|
||||
{
|
||||
$this->dbh->exec('SET FOREIGN_KEY_CHECKS=0;');
|
||||
parent::sqlQuery($query);
|
||||
$this->dbh->exec('SET FOREIGN_KEY_CHECKS=1;');
|
||||
}
|
||||
|
||||
public function getQuotedName($name)
|
||||
{
|
||||
return '`' . str_replace('.', '`.`', $name) . '`';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tableName
|
||||
*
|
||||
* @return array[string]
|
||||
*/
|
||||
public function getPrimaryKey($tableName)
|
||||
{
|
||||
if (!isset($this->primaryKeys[$tableName])) {
|
||||
$primaryKey = [];
|
||||
$stmt = $this->getDbh()->query(
|
||||
'SHOW KEYS FROM ' . $this->getQuotedName($tableName) . ' WHERE Key_name = "PRIMARY"'
|
||||
);
|
||||
$columns = $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$primaryKey []= $column['Column_name'];
|
||||
}
|
||||
$this->primaryKeys[$tableName] = $primaryKey;
|
||||
}
|
||||
|
||||
return $this->primaryKeys[$tableName];
|
||||
}
|
||||
}
|
||||
113
vendor/codeception/base/src/Codeception/Lib/Driver/Oci.php
vendored
Normal file
113
vendor/codeception/base/src/Codeception/Lib/Driver/Oci.php
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Driver;
|
||||
|
||||
class Oci extends Db
|
||||
{
|
||||
public function setWaitLock($seconds)
|
||||
{
|
||||
$this->dbh->exec('ALTER SESSION SET ddl_lock_timeout = ' . (int) $seconds);
|
||||
}
|
||||
|
||||
public function cleanup()
|
||||
{
|
||||
$this->dbh->exec(
|
||||
"BEGIN
|
||||
FOR i IN (SELECT trigger_name FROM user_triggers)
|
||||
LOOP
|
||||
EXECUTE IMMEDIATE('DROP TRIGGER ' || user || '.\"' || i.trigger_name || '\"');
|
||||
END LOOP;
|
||||
END;"
|
||||
);
|
||||
$this->dbh->exec(
|
||||
"BEGIN
|
||||
FOR i IN (SELECT table_name FROM user_tables)
|
||||
LOOP
|
||||
EXECUTE IMMEDIATE('DROP TABLE ' || user || '.\"' || i.table_name || '\" CASCADE CONSTRAINTS');
|
||||
END LOOP;
|
||||
END;"
|
||||
);
|
||||
$this->dbh->exec(
|
||||
"BEGIN
|
||||
FOR i IN (SELECT sequence_name FROM user_sequences)
|
||||
LOOP
|
||||
EXECUTE IMMEDIATE('DROP SEQUENCE ' || user || '.\"' || i.sequence_name || '\"');
|
||||
END LOOP;
|
||||
END;"
|
||||
);
|
||||
$this->dbh->exec(
|
||||
"BEGIN
|
||||
FOR i IN (SELECT view_name FROM user_views)
|
||||
LOOP
|
||||
EXECUTE IMMEDIATE('DROP VIEW ' || user || '.\"' || i.view_name || '\"');
|
||||
END LOOP;
|
||||
END;"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL commands should ends with `//` in the dump file
|
||||
* IF you want to load triggers too.
|
||||
* IF you do not want to load triggers you can use the `;` characters
|
||||
* but in this case you need to change the $delimiter from `//` to `;`
|
||||
*
|
||||
* @param $sql
|
||||
*/
|
||||
public function load($sql)
|
||||
{
|
||||
$query = '';
|
||||
$delimiter = '//';
|
||||
$delimiterLength = 2;
|
||||
|
||||
foreach ($sql as $sqlLine) {
|
||||
if (preg_match('/DELIMITER ([\;\$\|\\\\]+)/i', $sqlLine, $match)) {
|
||||
$delimiter = $match[1];
|
||||
$delimiterLength = strlen($delimiter);
|
||||
continue;
|
||||
}
|
||||
|
||||
$parsed = $this->sqlLine($sqlLine);
|
||||
if ($parsed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$query .= "\n" . rtrim($sqlLine);
|
||||
|
||||
if (substr($query, -1 * $delimiterLength, $delimiterLength) == $delimiter) {
|
||||
$this->sqlQuery(substr($query, 0, -1 * $delimiterLength));
|
||||
$query = "";
|
||||
}
|
||||
}
|
||||
|
||||
if ($query !== '') {
|
||||
$this->sqlQuery($query);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tableName
|
||||
*
|
||||
* @return array[string]
|
||||
*/
|
||||
public function getPrimaryKey($tableName)
|
||||
{
|
||||
if (!isset($this->primaryKeys[$tableName])) {
|
||||
$primaryKey = [];
|
||||
$query = "SELECT cols.column_name
|
||||
FROM all_constraints cons, all_cons_columns cols
|
||||
WHERE cols.table_name = ?
|
||||
AND cons.constraint_type = 'P'
|
||||
AND cons.constraint_name = cols.constraint_name
|
||||
AND cons.owner = cols.owner
|
||||
ORDER BY cols.table_name, cols.position";
|
||||
$stmt = $this->executeQuery($query, [$tableName]);
|
||||
$columns = $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$primaryKey []= $column['COLUMN_NAME'];
|
||||
}
|
||||
$this->primaryKeys[$tableName] = $primaryKey;
|
||||
}
|
||||
|
||||
return $this->primaryKeys[$tableName];
|
||||
}
|
||||
}
|
||||
177
vendor/codeception/base/src/Codeception/Lib/Driver/PostgreSql.php
vendored
Normal file
177
vendor/codeception/base/src/Codeception/Lib/Driver/PostgreSql.php
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
namespace Codeception\Lib\Driver;
|
||||
|
||||
use Codeception\Exception\ModuleException;
|
||||
|
||||
class PostgreSql extends Db
|
||||
{
|
||||
protected $putline = false;
|
||||
|
||||
protected $connection = null;
|
||||
|
||||
protected $searchPath = null;
|
||||
|
||||
/**
|
||||
* Loads a SQL file.
|
||||
*
|
||||
* @param string $sql sql file
|
||||
*/
|
||||
public function load($sql)
|
||||
{
|
||||
$query = '';
|
||||
$delimiter = ';';
|
||||
$delimiterLength = 1;
|
||||
|
||||
$dollarsOpen = false;
|
||||
foreach ($sql as $sqlLine) {
|
||||
if (preg_match('/DELIMITER ([\;\$\|\\\\]+)/i', $sqlLine, $match)) {
|
||||
$delimiter = $match[1];
|
||||
$delimiterLength = strlen($delimiter);
|
||||
continue;
|
||||
}
|
||||
|
||||
$parsed = trim($query) == '' && $this->sqlLine($sqlLine);
|
||||
if ($parsed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore $$ inside SQL standard string syntax such as in INSERT statements.
|
||||
if (!preg_match('/\'.*\$\$.*\'/', $sqlLine)) {
|
||||
$pos = strpos($sqlLine, '$$');
|
||||
if (($pos !== false) && ($pos >= 0)) {
|
||||
$dollarsOpen = !$dollarsOpen;
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match('/SET search_path = .*/i', $sqlLine, $match)) {
|
||||
$this->searchPath = $match[0];
|
||||
}
|
||||
|
||||
$query .= "\n" . rtrim($sqlLine);
|
||||
|
||||
if (!$dollarsOpen && substr($query, -1 * $delimiterLength, $delimiterLength) == $delimiter) {
|
||||
$this->sqlQuery(substr($query, 0, -1 * $delimiterLength));
|
||||
$query = '';
|
||||
}
|
||||
}
|
||||
|
||||
if ($query !== '') {
|
||||
$this->sqlQuery($query);
|
||||
}
|
||||
}
|
||||
|
||||
public function cleanup()
|
||||
{
|
||||
$this->dbh->exec('DROP SCHEMA IF EXISTS public CASCADE;');
|
||||
$this->dbh->exec('CREATE SCHEMA public;');
|
||||
}
|
||||
|
||||
public function sqlLine($sql)
|
||||
{
|
||||
if (!$this->putline) {
|
||||
return parent::sqlLine($sql);
|
||||
}
|
||||
|
||||
if ($sql == '\.') {
|
||||
$this->putline = false;
|
||||
pg_put_line($this->connection, $sql . "\n");
|
||||
pg_end_copy($this->connection);
|
||||
pg_close($this->connection);
|
||||
} else {
|
||||
pg_put_line($this->connection, $sql . "\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function sqlQuery($query)
|
||||
{
|
||||
if (strpos(trim($query), 'COPY ') === 0) {
|
||||
if (!extension_loaded('pgsql')) {
|
||||
throw new ModuleException(
|
||||
'\Codeception\Module\Db',
|
||||
"To run 'COPY' commands 'pgsql' extension should be installed"
|
||||
);
|
||||
}
|
||||
if (defined('HHVM_VERSION')) {
|
||||
throw new ModuleException(
|
||||
'\Codeception\Module\Db',
|
||||
"'COPY' command is not supported on HHVM, please use INSERT instead"
|
||||
);
|
||||
}
|
||||
$constring = str_replace(';', ' ', substr($this->dsn, 6));
|
||||
$constring .= ' user=' . $this->user;
|
||||
$constring .= ' password=' . $this->password;
|
||||
$this->connection = pg_connect($constring);
|
||||
|
||||
if ($this->searchPath !== null) {
|
||||
pg_query($this->connection, $this->searchPath);
|
||||
}
|
||||
|
||||
pg_query($this->connection, $query);
|
||||
$this->putline = true;
|
||||
} else {
|
||||
$this->dbh->exec($query);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last inserted ID of table.
|
||||
*/
|
||||
public function lastInsertId($table)
|
||||
{
|
||||
/*
|
||||
* We make an assumption that the sequence name for this table
|
||||
* is based on how postgres names sequences for SERIAL columns
|
||||
*/
|
||||
|
||||
$sequenceName = $this->getQuotedName($table . '_id_seq');
|
||||
$lastSequence = null;
|
||||
|
||||
try {
|
||||
$lastSequence = $this->getDbh()->lastInsertId($sequenceName);
|
||||
} catch (\PDOException $e) {
|
||||
// in this case, the sequence name might be combined with the primary key name
|
||||
}
|
||||
|
||||
// here we check if for instance, it's something like table_primary_key_seq instead of table_id_seq
|
||||
// this could occur when you use some kind of import tool like pgloader
|
||||
if (!$lastSequence) {
|
||||
$primaryKeys = $this->getPrimaryKey($table);
|
||||
$pkName = array_shift($primaryKeys);
|
||||
$lastSequence = $this->getDbh()->lastInsertId($this->getQuotedName($table . '_' . $pkName . '_seq'));
|
||||
}
|
||||
|
||||
return $lastSequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the primary key(s) of the table, based on:
|
||||
* https://wiki.postgresql.org/wiki/Retrieve_primary_key_columns.
|
||||
*
|
||||
* @param string $tableName
|
||||
*
|
||||
* @return array[string]
|
||||
*/
|
||||
public function getPrimaryKey($tableName)
|
||||
{
|
||||
if (!isset($this->primaryKeys[$tableName])) {
|
||||
$primaryKey = [];
|
||||
$query = "SELECT a.attname
|
||||
FROM pg_index i
|
||||
JOIN pg_attribute a ON a.attrelid = i.indrelid
|
||||
AND a.attnum = ANY(i.indkey)
|
||||
WHERE i.indrelid = '$tableName'::regclass
|
||||
AND i.indisprimary";
|
||||
$stmt = $this->executeQuery($query, []);
|
||||
$columns = $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
foreach ($columns as $column) {
|
||||
$primaryKey []= $column['attname'];
|
||||
}
|
||||
$this->primaryKeys[$tableName] = $primaryKey;
|
||||
}
|
||||
|
||||
return $this->primaryKeys[$tableName];
|
||||
}
|
||||
}
|
||||
109
vendor/codeception/base/src/Codeception/Lib/Driver/SqlSrv.php
vendored
Normal file
109
vendor/codeception/base/src/Codeception/Lib/Driver/SqlSrv.php
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Driver;
|
||||
|
||||
class SqlSrv extends Db
|
||||
{
|
||||
public function getDb()
|
||||
{
|
||||
$matches = [];
|
||||
$matched = preg_match('~Database=(.*);?~s', $this->dsn, $matches);
|
||||
|
||||
if (!$matched) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
public function cleanup()
|
||||
{
|
||||
$this->dbh->exec(
|
||||
"
|
||||
DECLARE constraints_cursor CURSOR FOR SELECT name, parent_object_id FROM sys.foreign_keys;
|
||||
OPEN constraints_cursor
|
||||
DECLARE @constraint sysname;
|
||||
DECLARE @parent int;
|
||||
DECLARE @table nvarchar(128);
|
||||
FETCH NEXT FROM constraints_cursor INTO @constraint, @parent;
|
||||
WHILE (@@FETCH_STATUS <> -1)
|
||||
BEGIN
|
||||
SET @table = OBJECT_NAME(@parent)
|
||||
EXEC ('ALTER TABLE [' + @table + '] DROP CONSTRAINT [' + @constraint + ']')
|
||||
FETCH NEXT FROM constraints_cursor INTO @constraint, @parent;
|
||||
END
|
||||
DEALLOCATE constraints_cursor;"
|
||||
);
|
||||
|
||||
$this->dbh->exec(
|
||||
"
|
||||
DECLARE tables_cursor CURSOR FOR SELECT name FROM sysobjects WHERE type = 'U';
|
||||
OPEN tables_cursor DECLARE @tablename sysname;
|
||||
FETCH NEXT FROM tables_cursor INTO @tablename;
|
||||
WHILE (@@FETCH_STATUS <> -1)
|
||||
BEGIN
|
||||
EXEC ('DROP TABLE [' + @tablename + ']')
|
||||
FETCH NEXT FROM tables_cursor INTO @tablename;
|
||||
END
|
||||
DEALLOCATE tables_cursor;"
|
||||
);
|
||||
}
|
||||
|
||||
protected function generateWhereClause(array &$criteria)
|
||||
{
|
||||
if (empty($criteria)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$params = [];
|
||||
foreach ($criteria as $k => $v) {
|
||||
if ($v === null) {
|
||||
$params[] = $this->getQuotedName($k) . " IS NULL ";
|
||||
unset($criteria[$k]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strpos(strtolower($k), ' like') > 0) {
|
||||
$k = str_replace(' like', '', strtolower($k));
|
||||
$params[] = $this->getQuotedName($k) . " LIKE ? ";
|
||||
} else {
|
||||
$params[] = $this->getQuotedName($k) . " = ? ";
|
||||
}
|
||||
}
|
||||
|
||||
return 'WHERE ' . implode('AND ', $params);
|
||||
}
|
||||
|
||||
public function getQuotedName($name)
|
||||
{
|
||||
return '[' . str_replace('.', '].[', $name) . ']';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tableName
|
||||
*
|
||||
* @return array[string]
|
||||
*/
|
||||
public function getPrimaryKey($tableName)
|
||||
{
|
||||
if (!isset($this->primaryKeys[$tableName])) {
|
||||
$primaryKey = [];
|
||||
$query = "
|
||||
SELECT Col.Column_Name from
|
||||
INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab,
|
||||
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col
|
||||
WHERE
|
||||
Col.Constraint_Name = Tab.Constraint_Name
|
||||
AND Col.Table_Name = Tab.Table_Name
|
||||
AND Constraint_Type = 'PRIMARY KEY' AND Col.Table_Name = ?";
|
||||
$stmt = $this->executeQuery($query, [$tableName]);
|
||||
$columns = $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$primaryKey []= $column['Column_Name'];
|
||||
}
|
||||
$this->primaryKeys[$tableName] = $primaryKey;
|
||||
}
|
||||
|
||||
return $this->primaryKeys[$tableName];
|
||||
}
|
||||
}
|
||||
89
vendor/codeception/base/src/Codeception/Lib/Driver/Sqlite.php
vendored
Normal file
89
vendor/codeception/base/src/Codeception/Lib/Driver/Sqlite.php
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Driver;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Exception\ModuleException;
|
||||
|
||||
class Sqlite extends Db
|
||||
{
|
||||
protected $hasSnapshot = false;
|
||||
protected $filename = '';
|
||||
protected $con = null;
|
||||
|
||||
public function __construct($dsn, $user, $password, $options = null)
|
||||
{
|
||||
$filename = substr($dsn, 7);
|
||||
if ($filename === ':memory:') {
|
||||
throw new ModuleException(__CLASS__, ':memory: database is not supported');
|
||||
}
|
||||
|
||||
$this->filename = Configuration::projectDir() . $filename;
|
||||
$this->dsn = 'sqlite:' . $this->filename;
|
||||
parent::__construct($this->dsn, $user, $password, $options);
|
||||
}
|
||||
|
||||
public function cleanup()
|
||||
{
|
||||
$this->dbh = null;
|
||||
file_put_contents($this->filename, '');
|
||||
$this->dbh = self::connect($this->dsn, $this->user, $this->password);
|
||||
}
|
||||
|
||||
public function load($sql)
|
||||
{
|
||||
if ($this->hasSnapshot) {
|
||||
$this->dbh = null;
|
||||
file_put_contents($this->filename, file_get_contents($this->filename . '_snapshot'));
|
||||
$this->dbh = new \PDO($this->dsn, $this->user, $this->password);
|
||||
} else {
|
||||
if (file_exists($this->filename . '_snapshot')) {
|
||||
unlink($this->filename . '_snapshot');
|
||||
}
|
||||
parent::load($sql);
|
||||
copy($this->filename, $this->filename . '_snapshot');
|
||||
$this->hasSnapshot = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tableName
|
||||
*
|
||||
* @return array[string]
|
||||
*/
|
||||
public function getPrimaryKey($tableName)
|
||||
{
|
||||
if (!isset($this->primaryKeys[$tableName])) {
|
||||
if ($this->hasRowId($tableName)) {
|
||||
return $this->primaryKeys[$tableName] = ['_ROWID_'];
|
||||
}
|
||||
|
||||
$primaryKey = [];
|
||||
$query = 'PRAGMA table_info(' . $this->getQuotedName($tableName) . ')';
|
||||
$stmt = $this->executeQuery($query, []);
|
||||
$columns = $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
foreach ($columns as $column) {
|
||||
if ($column['pk'] !== '0') {
|
||||
$primaryKey []= $column['name'];
|
||||
}
|
||||
}
|
||||
|
||||
$this->primaryKeys[$tableName] = $primaryKey;
|
||||
}
|
||||
|
||||
return $this->primaryKeys[$tableName];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $tableName
|
||||
* @return bool
|
||||
*/
|
||||
private function hasRowId($tableName)
|
||||
{
|
||||
$params = ['type' => 'table', 'name' => $tableName];
|
||||
$select = $this->select('sql', 'sqlite_master', $params);
|
||||
$result = $this->executeQuery($select, $params);
|
||||
$sql = $result->fetchColumn(0);
|
||||
return strpos($sql, ') WITHOUT ROWID') === false;
|
||||
}
|
||||
}
|
||||
30
vendor/codeception/base/src/Codeception/Lib/Framework.php
vendored
Normal file
30
vendor/codeception/base/src/Codeception/Lib/Framework.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Codeception\Lib;
|
||||
|
||||
/**
|
||||
* Abstract module for PHP frameworks connected via Symfony BrowserKit components
|
||||
* Each framework is connected with it's own connector defined in \Codeception\Lib\Connector
|
||||
* Each module for framework should extend this class.
|
||||
*
|
||||
*/
|
||||
abstract class Framework extends InnerBrowser
|
||||
{
|
||||
/**
|
||||
* Returns a list of recognized domain names
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getInternalDomains()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function _beforeSuite($settings = [])
|
||||
{
|
||||
/**
|
||||
* reset internal domains before suite, because each suite can have a different configuration
|
||||
*/
|
||||
$this->internalDomains = null;
|
||||
}
|
||||
}
|
||||
78
vendor/codeception/base/src/Codeception/Lib/Friend.php
vendored
Normal file
78
vendor/codeception/base/src/Codeception/Lib/Friend.php
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
namespace Codeception\Lib;
|
||||
|
||||
use Codeception\Actor;
|
||||
use Codeception\Exception\TestRuntimeException;
|
||||
|
||||
class Friend
|
||||
{
|
||||
protected $name;
|
||||
protected $actor;
|
||||
protected $data = [];
|
||||
protected $multiSessionModules = [];
|
||||
|
||||
public function __construct($name, Actor $actor, $modules = [])
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->actor = $actor;
|
||||
|
||||
$this->multiSessionModules = array_filter($modules, function ($m) {
|
||||
return $m instanceof Interfaces\MultiSession;
|
||||
});
|
||||
|
||||
if (empty($this->multiSessionModules)) {
|
||||
throw new TestRuntimeException("No multisession modules used. Can't instantiate friend");
|
||||
}
|
||||
}
|
||||
|
||||
public function does($closure)
|
||||
{
|
||||
$currentUserData = [];
|
||||
|
||||
foreach ($this->multiSessionModules as $module) {
|
||||
$name = $module->_getName();
|
||||
$currentUserData[$name] = $module->_backupSession();
|
||||
if (empty($this->data[$name])) {
|
||||
$module->_initializeSession();
|
||||
$this->data[$name] = $module->_backupSession();
|
||||
continue;
|
||||
}
|
||||
$module->_loadSession($this->data[$name]);
|
||||
};
|
||||
|
||||
$this->actor->comment(strtoupper("{$this->name} does ---"));
|
||||
$ret = $closure($this->actor);
|
||||
$this->actor->comment(strtoupper("--- {$this->name} finished"));
|
||||
|
||||
foreach ($this->multiSessionModules as $module) {
|
||||
$name = $module->_getName();
|
||||
$this->data[$name] = $module->_backupSession();
|
||||
$module->_loadSession($currentUserData[$name]);
|
||||
};
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function isGoingTo($argumentation)
|
||||
{
|
||||
$this->actor->amGoingTo($argumentation);
|
||||
}
|
||||
|
||||
public function expects($prediction)
|
||||
{
|
||||
$this->actor->expect($prediction);
|
||||
}
|
||||
|
||||
public function expectsTo($prediction)
|
||||
{
|
||||
$this->actor->expectTo($prediction);
|
||||
}
|
||||
|
||||
public function leave()
|
||||
{
|
||||
foreach ($this->multiSessionModules as $module) {
|
||||
if (isset($this->data[$module->_getName()])) {
|
||||
$module->_closeSession($this->data[$module->_getName()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
208
vendor/codeception/base/src/Codeception/Lib/Generator/Actions.php
vendored
Normal file
208
vendor/codeception/base/src/Codeception/Lib/Generator/Actions.php
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Generator;
|
||||
|
||||
use Codeception\Codecept;
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Lib\Di;
|
||||
use Codeception\Lib\ModuleContainer;
|
||||
use Codeception\Util\Template;
|
||||
|
||||
class Actions
|
||||
{
|
||||
|
||||
protected $template = <<<EOF
|
||||
<?php //[STAMP] {{hash}}
|
||||
namespace {{namespace}}_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
// You should not change it manually as it will be overwritten on next build
|
||||
// @codingStandardsIgnoreFile
|
||||
|
||||
trait {{name}}Actions
|
||||
{
|
||||
/**
|
||||
* @return \Codeception\Scenario
|
||||
*/
|
||||
abstract protected function getScenario();
|
||||
|
||||
{{methods}}
|
||||
}
|
||||
|
||||
EOF;
|
||||
|
||||
|
||||
protected $methodTemplate = <<<EOF
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
{{doc}}
|
||||
* @see \{{module}}::{{method}}()
|
||||
*/
|
||||
public function {{action}}({{params}}) {
|
||||
return \$this->getScenario()->runStep(new \Codeception\Step\{{step}}('{{method}}', func_get_args()));
|
||||
}
|
||||
EOF;
|
||||
|
||||
protected $name;
|
||||
protected $settings;
|
||||
protected $modules = [];
|
||||
protected $actions;
|
||||
protected $numMethods = 0;
|
||||
|
||||
public function __construct($settings)
|
||||
{
|
||||
$this->name = $settings['actor'];
|
||||
$this->settings = $settings;
|
||||
$this->di = new Di();
|
||||
$modules = Configuration::modules($this->settings);
|
||||
$this->moduleContainer = new ModuleContainer($this->di, $settings);
|
||||
foreach ($modules as $moduleName) {
|
||||
$this->moduleContainer->create($moduleName);
|
||||
}
|
||||
$this->modules = $this->moduleContainer->all();
|
||||
$this->actions = $this->moduleContainer->getActions();
|
||||
}
|
||||
|
||||
|
||||
public function produce()
|
||||
{
|
||||
$namespace = rtrim($this->settings['namespace'], '\\');
|
||||
|
||||
$methods = [];
|
||||
$code = [];
|
||||
foreach ($this->actions as $action => $moduleName) {
|
||||
if (in_array($action, $methods)) {
|
||||
continue;
|
||||
}
|
||||
$class = new \ReflectionClass($this->modules[$moduleName]);
|
||||
$method = $class->getMethod($action);
|
||||
$code[] = $this->addMethod($method);
|
||||
$methods[] = $action;
|
||||
$this->numMethods++;
|
||||
}
|
||||
|
||||
return (new Template($this->template))
|
||||
->place('namespace', $namespace ? $namespace . '\\' : '')
|
||||
->place('hash', self::genHash($this->modules, $this->settings))
|
||||
->place('name', $this->name)
|
||||
->place('methods', implode("\n\n ", $code))
|
||||
->produce();
|
||||
}
|
||||
|
||||
protected function addMethod(\ReflectionMethod $refMethod)
|
||||
{
|
||||
$class = $refMethod->getDeclaringClass();
|
||||
$params = $this->getParamsString($refMethod);
|
||||
$module = $class->getName();
|
||||
|
||||
$body = '';
|
||||
$doc = $this->addDoc($class, $refMethod);
|
||||
$doc = str_replace('/**', '', $doc);
|
||||
$doc = trim(str_replace('*/', '', $doc));
|
||||
if (!$doc) {
|
||||
$doc = "*";
|
||||
}
|
||||
|
||||
$conditionalDoc = $doc . "\n * Conditional Assertion: Test won't be stopped on fail";
|
||||
|
||||
$methodTemplate = (new Template($this->methodTemplate))
|
||||
->place('module', $module)
|
||||
->place('method', $refMethod->name)
|
||||
->place('params', $params);
|
||||
|
||||
// generate conditional assertions
|
||||
if (0 === strpos($refMethod->name, 'see')) {
|
||||
$type = 'Assertion';
|
||||
$body .= $methodTemplate
|
||||
->place('doc', $conditionalDoc)
|
||||
->place('action', 'can' . ucfirst($refMethod->name))
|
||||
->place('step', 'ConditionalAssertion')
|
||||
->produce();
|
||||
|
||||
// generate negative assertion
|
||||
} elseif (0 === strpos($refMethod->name, 'dontSee')) {
|
||||
$type = 'Assertion';
|
||||
$body .= $methodTemplate
|
||||
->place('doc', $conditionalDoc)
|
||||
->place('action', str_replace('dont', 'cant', $refMethod->name))
|
||||
->place('step', 'ConditionalAssertion')
|
||||
->produce();
|
||||
} elseif (0 === strpos($refMethod->name, 'am')) {
|
||||
$type = 'Condition';
|
||||
} else {
|
||||
$type = 'Action';
|
||||
}
|
||||
|
||||
$body .= $methodTemplate
|
||||
->place('doc', $doc)
|
||||
->place('action', $refMethod->name)
|
||||
->place('step', $type)
|
||||
->produce();
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ReflectionMethod $refMethod
|
||||
* @return array
|
||||
*/
|
||||
protected function getParamsString(\ReflectionMethod $refMethod)
|
||||
{
|
||||
$params = [];
|
||||
foreach ($refMethod->getParameters() as $param) {
|
||||
if ($param->isOptional()) {
|
||||
$params[] = '$' . $param->name . ' = null';
|
||||
} else {
|
||||
$params[] = '$' . $param->name;
|
||||
};
|
||||
}
|
||||
return implode(', ', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ReflectionClass $class
|
||||
* @param \ReflectionMethod $refMethod
|
||||
* @return string
|
||||
*/
|
||||
protected function addDoc(\ReflectionClass $class, \ReflectionMethod $refMethod)
|
||||
{
|
||||
$doc = $refMethod->getDocComment();
|
||||
|
||||
if (!$doc) {
|
||||
$interfaces = $class->getInterfaces();
|
||||
foreach ($interfaces as $interface) {
|
||||
$i = new \ReflectionClass($interface->name);
|
||||
if ($i->hasMethod($refMethod->name)) {
|
||||
$doc = $i->getMethod($refMethod->name)->getDocComment();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$doc and $class->getParentClass()) {
|
||||
$parent = new \ReflectionClass($class->getParentClass()->name);
|
||||
if ($parent->hasMethod($refMethod->name)) {
|
||||
$doc = $parent->getMethod($refMethod->name)->getDocComment();
|
||||
return $doc;
|
||||
}
|
||||
return $doc;
|
||||
}
|
||||
return $doc;
|
||||
}
|
||||
|
||||
public static function genHash($modules, $settings)
|
||||
{
|
||||
$actions = [];
|
||||
foreach ($modules as $moduleName => $module) {
|
||||
$actions[$moduleName] = get_class_methods(get_class($module));
|
||||
}
|
||||
|
||||
return md5(Codecept::VERSION . serialize($actions) . serialize($settings['modules']));
|
||||
}
|
||||
|
||||
public function getNumMethods()
|
||||
{
|
||||
return $this->numMethods;
|
||||
}
|
||||
}
|
||||
197
vendor/codeception/base/src/Codeception/Lib/Generator/Actor.php
vendored
Normal file
197
vendor/codeception/base/src/Codeception/Lib/Generator/Actor.php
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Generator;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Lib\Di;
|
||||
use Codeception\Lib\ModuleContainer;
|
||||
use Codeception\Util\Template;
|
||||
|
||||
class Actor
|
||||
{
|
||||
protected $template = <<<EOF
|
||||
<?php
|
||||
{{hasNamespace}}
|
||||
|
||||
/**
|
||||
* Inherited Methods
|
||||
{{inheritedMethods}}
|
||||
*
|
||||
* @SuppressWarnings(PHPMD)
|
||||
*/
|
||||
class {{actor}} extends \Codeception\Actor
|
||||
{
|
||||
use _generated\{{actor}}Actions;
|
||||
|
||||
/**
|
||||
* Define custom actions here
|
||||
*/
|
||||
}
|
||||
|
||||
EOF;
|
||||
|
||||
protected $inheritedMethodTemplate = ' * @method {{return}} {{method}}({{params}})';
|
||||
|
||||
protected $settings;
|
||||
protected $modules;
|
||||
protected $actions;
|
||||
|
||||
public function __construct($settings)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
$this->di = new Di();
|
||||
$this->moduleContainer = new ModuleContainer($this->di, $settings);
|
||||
|
||||
$modules = Configuration::modules($this->settings);
|
||||
foreach ($modules as $moduleName) {
|
||||
$this->moduleContainer->create($moduleName);
|
||||
}
|
||||
|
||||
$this->modules = $this->moduleContainer->all();
|
||||
$this->actions = $this->moduleContainer->getActions();
|
||||
}
|
||||
|
||||
public function produce()
|
||||
{
|
||||
$namespace = rtrim($this->settings['namespace'], '\\');
|
||||
|
||||
if (!isset($this->settings['actor']) && isset($this->settings['class_name'])) {
|
||||
$this->settings['actor'] = $this->settings['class_name'];
|
||||
}
|
||||
|
||||
return (new Template($this->template))
|
||||
->place('hasNamespace', $namespace ? "namespace $namespace;" : '')
|
||||
->place('actor', $this->settings['actor'])
|
||||
->place('inheritedMethods', $this->prependAbstractActorDocBlocks())
|
||||
->produce();
|
||||
}
|
||||
|
||||
protected function prependAbstractActorDocBlocks()
|
||||
{
|
||||
$inherited = [];
|
||||
|
||||
$class = new \ReflectionClass('\Codeception\\Actor');
|
||||
$methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC);
|
||||
|
||||
foreach ($methods as $method) {
|
||||
if ($method->name == '__call') {
|
||||
continue;
|
||||
} // skipping magic
|
||||
if ($method->name == '__construct') {
|
||||
continue;
|
||||
} // skipping magic
|
||||
$returnType = 'void';
|
||||
if ($method->name == 'haveFriend') {
|
||||
$returnType = '\Codeception\Lib\Friend';
|
||||
}
|
||||
$params = $this->getParamsString($method);
|
||||
$inherited[] = (new Template($this->inheritedMethodTemplate))
|
||||
->place('method', $method->name)
|
||||
->place('params', $params)
|
||||
->place('return', $returnType)
|
||||
->produce();
|
||||
}
|
||||
|
||||
return implode("\n", $inherited);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ReflectionMethod $refMethod
|
||||
* @return array
|
||||
*/
|
||||
protected function getParamsString(\ReflectionMethod $refMethod)
|
||||
{
|
||||
$params = [];
|
||||
foreach ($refMethod->getParameters() as $param) {
|
||||
if ($param->isOptional()) {
|
||||
$params[] = '$' . $param->name . ' = '.$this->getDefaultValue($param);
|
||||
} else {
|
||||
$params[] = '$' . $param->name;
|
||||
};
|
||||
}
|
||||
return implode(', ', $params);
|
||||
}
|
||||
|
||||
public function getActorName()
|
||||
{
|
||||
return $this->settings['actor'];
|
||||
}
|
||||
|
||||
public function getModules()
|
||||
{
|
||||
return array_keys($this->modules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Infer default parameter from the reflection object and format it as PHP (code) string
|
||||
*
|
||||
* @param \ReflectionParameter $param
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getDefaultValue(\ReflectionParameter $param)
|
||||
{
|
||||
if ($param->isDefaultValueAvailable()) {
|
||||
if (method_exists($param, 'isDefaultValueConstant') && $param->isDefaultValueConstant()) {
|
||||
$constName = $param->getDefaultValueConstantName();
|
||||
if (false !== strpos($constName, '::')) {
|
||||
list($class, $const) = explode('::', $constName);
|
||||
if (in_array($class, ['self', 'static'])) {
|
||||
$constName = $param->getDeclaringClass()->getName().'::'.$const;
|
||||
}
|
||||
}
|
||||
|
||||
return $constName;
|
||||
}
|
||||
|
||||
return $this->phpEncodeValue($param->getDefaultValue());
|
||||
}
|
||||
|
||||
return 'null';
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP encoded a value
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function phpEncodeValue($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return $this->phpEncodeArray($value);
|
||||
}
|
||||
|
||||
if (is_string($value)) {
|
||||
return json_encode($value);
|
||||
}
|
||||
|
||||
return var_export($value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively PHP encode an array
|
||||
*
|
||||
* @param array $array
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function phpEncodeArray(array $array)
|
||||
{
|
||||
$isPlainArray = function (array $value) {
|
||||
return ((count($value) === 0)
|
||||
|| (
|
||||
(array_keys($value) === range(0, count($value) - 1))
|
||||
&& (0 === count(array_filter(array_keys($value), 'is_string'))))
|
||||
);
|
||||
};
|
||||
|
||||
if ($isPlainArray($array)) {
|
||||
return '['.implode(', ', array_map([$this, 'phpEncodeValue'], $array)).']';
|
||||
}
|
||||
|
||||
return '['.implode(', ', array_map(function ($key) use ($array) {
|
||||
return $this->phpEncodeValue($key).' => '.$this->phpEncodeValue($array[$key]);
|
||||
}, array_keys($array))).']';
|
||||
}
|
||||
}
|
||||
41
vendor/codeception/base/src/Codeception/Lib/Generator/Cept.php
vendored
Normal file
41
vendor/codeception/base/src/Codeception/Lib/Generator/Cept.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Generator;
|
||||
|
||||
use Codeception\Exception\ConfigurationException;
|
||||
use Codeception\Util\Template;
|
||||
|
||||
class Cept
|
||||
{
|
||||
|
||||
protected $template = <<<EOF
|
||||
<?php {{use}}
|
||||
\$I = new {{actor}}(\$scenario);
|
||||
\$I->wantTo('perform actions and see result');
|
||||
|
||||
EOF;
|
||||
|
||||
protected $settings;
|
||||
|
||||
public function __construct($settings)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
public function produce()
|
||||
{
|
||||
$actor = $this->settings['actor'];
|
||||
if (!$actor) {
|
||||
throw new ConfigurationException("Cept can't be created for suite without an actor. Add `actor: SomeTester` to suite config");
|
||||
}
|
||||
$use = '';
|
||||
if (! empty($this->settings['namespace'])) {
|
||||
$namespace = rtrim($this->settings['namespace'], '\\');
|
||||
$use = "use {$namespace}\\$actor;";
|
||||
}
|
||||
|
||||
return (new Template($this->template))
|
||||
->place('actor', $actor)
|
||||
->place('use', $use)
|
||||
->produce();
|
||||
}
|
||||
}
|
||||
69
vendor/codeception/base/src/Codeception/Lib/Generator/Cest.php
vendored
Normal file
69
vendor/codeception/base/src/Codeception/Lib/Generator/Cest.php
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Generator;
|
||||
|
||||
use Codeception\Exception\ConfigurationException;
|
||||
use Codeception\Util\Shared\Namespaces;
|
||||
use Codeception\Util\Template;
|
||||
|
||||
class Cest
|
||||
{
|
||||
use Shared\Classname;
|
||||
use Namespaces;
|
||||
|
||||
protected $template = <<<EOF
|
||||
<?php
|
||||
{{namespace}}
|
||||
|
||||
class {{name}}Cest
|
||||
{
|
||||
public function _before({{actor}} \$I)
|
||||
{
|
||||
}
|
||||
|
||||
public function _after({{actor}} \$I)
|
||||
{
|
||||
}
|
||||
|
||||
// tests
|
||||
public function tryToTest({{actor}} \$I)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
EOF;
|
||||
|
||||
protected $settings;
|
||||
protected $name;
|
||||
|
||||
public function __construct($className, $settings)
|
||||
{
|
||||
$this->name = $this->removeSuffix($className, 'Cest');
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
public function produce()
|
||||
{
|
||||
$actor = $this->settings['actor'];
|
||||
if (!$actor) {
|
||||
throw new ConfigurationException("Cept can't be created for suite without an actor. Add `actor: SomeTester` to suite config");
|
||||
}
|
||||
|
||||
if (array_key_exists('suite_namespace', $this->settings)) {
|
||||
$namespace = rtrim($this->settings['suite_namespace'], '\\');
|
||||
} else {
|
||||
$namespace = rtrim($this->settings['namespace'], '\\');
|
||||
}
|
||||
|
||||
$ns = $this->getNamespaceHeader($namespace.'\\'.$this->name);
|
||||
|
||||
if ($namespace) {
|
||||
$ns .= "use ".$this->settings['namespace'].'\\'.$actor.";";
|
||||
}
|
||||
|
||||
return (new Template($this->template))
|
||||
->place('name', $this->getShortClassName($this->name))
|
||||
->place('namespace', $ns)
|
||||
->place('actor', $actor)
|
||||
->produce();
|
||||
}
|
||||
}
|
||||
31
vendor/codeception/base/src/Codeception/Lib/Generator/Feature.php
vendored
Normal file
31
vendor/codeception/base/src/Codeception/Lib/Generator/Feature.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Generator;
|
||||
|
||||
use Codeception\Util\Template;
|
||||
|
||||
class Feature
|
||||
{
|
||||
protected $template = <<<EOF
|
||||
Feature: {{name}}
|
||||
In order to ...
|
||||
As a ...
|
||||
I need to ...
|
||||
|
||||
Scenario: try {{name}}
|
||||
|
||||
EOF;
|
||||
|
||||
protected $name;
|
||||
|
||||
public function __construct($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function produce()
|
||||
{
|
||||
return (new Template($this->template))
|
||||
->place('name', $this->name)
|
||||
->produce();
|
||||
}
|
||||
}
|
||||
152
vendor/codeception/base/src/Codeception/Lib/Generator/GherkinSnippets.php
vendored
Normal file
152
vendor/codeception/base/src/Codeception/Lib/Generator/GherkinSnippets.php
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Generator;
|
||||
|
||||
use Behat\Gherkin\Node\StepNode;
|
||||
use Codeception\Test\Loader\Gherkin;
|
||||
use Codeception\Util\Template;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
class GherkinSnippets
|
||||
{
|
||||
protected $template = <<<EOF
|
||||
/**
|
||||
* @{{type}} {{text}}
|
||||
*/
|
||||
public function {{methodName}}({{params}})
|
||||
{
|
||||
throw new \Codeception\Exception\Incomplete("Step `{{text}}` is not defined");
|
||||
}
|
||||
|
||||
EOF;
|
||||
|
||||
protected $snippets = [];
|
||||
protected $processed = [];
|
||||
protected $features = [];
|
||||
|
||||
public function __construct($settings, $test = null)
|
||||
{
|
||||
$loader = new Gherkin($settings);
|
||||
$pattern = $loader->getPattern();
|
||||
$path = $settings['path'];
|
||||
if (!empty($test)) {
|
||||
$path = $settings['path'].'/'.$test;
|
||||
if (preg_match($pattern, $test)) {
|
||||
$path = dirname($path);
|
||||
$pattern = basename($test);
|
||||
}
|
||||
}
|
||||
|
||||
$finder = Finder::create()
|
||||
->files()
|
||||
->sortByName()
|
||||
->in($path)
|
||||
->followLinks()
|
||||
->name($pattern);
|
||||
|
||||
foreach ($finder as $file) {
|
||||
$pathname = str_replace("//", "/", $file->getPathname());
|
||||
$loader->loadTests($pathname);
|
||||
}
|
||||
$availableSteps = $loader->getSteps();
|
||||
$allSteps = [];
|
||||
foreach ($availableSteps as $stepGroup) {
|
||||
$allSteps = array_merge($allSteps, $stepGroup);
|
||||
}
|
||||
foreach ($loader->getTests() as $test) {
|
||||
/** @var $test \Codeception\Test\Gherkin **/
|
||||
$steps = $test->getScenarioNode()->getSteps();
|
||||
if ($test->getFeatureNode()->hasBackground()) {
|
||||
$steps = array_merge($steps, $test->getFeatureNode()->getBackground()->getSteps());
|
||||
}
|
||||
foreach ($steps as $step) {
|
||||
$matched = false;
|
||||
$text = $step->getText();
|
||||
if (self::stepHasPyStringArgument($step)) {
|
||||
// pretend it is inline argument
|
||||
$text .= ' ""';
|
||||
}
|
||||
foreach (array_keys($allSteps) as $pattern) {
|
||||
if (preg_match($pattern, $text)) {
|
||||
$matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$matched) {
|
||||
$this->addSnippet($step);
|
||||
$file = str_ireplace($settings['path'], '', $test->getFeatureNode()->getFile());
|
||||
if (!in_array($file, $this->features)) {
|
||||
$this->features[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addSnippet(StepNode $step)
|
||||
{
|
||||
$args = [];
|
||||
$pattern = $step->getText();
|
||||
|
||||
// match numbers (not in quotes)
|
||||
if (preg_match_all('~([\d\.])(?=([^"]*"[^"]*")*[^"]*$)~', $pattern, $matches)) {
|
||||
foreach ($matches[1] as $num => $param) {
|
||||
$num++;
|
||||
$args[] = '$num' . $num;
|
||||
$pattern = str_replace($param, ":num$num", $pattern);
|
||||
}
|
||||
}
|
||||
|
||||
// match quoted string
|
||||
if (preg_match_all('~"(.*?)"~', $pattern, $matches)) {
|
||||
foreach ($matches[1] as $num => $param) {
|
||||
$num++;
|
||||
$args[] = '$arg' . $num;
|
||||
$pattern = str_replace('"'.$param.'"', ":arg$num", $pattern);
|
||||
}
|
||||
}
|
||||
// Has multiline argument at the end of step?
|
||||
if (self::stepHasPyStringArgument($step)) {
|
||||
$num = count($args) + 1;
|
||||
$pattern .= " :arg$num";
|
||||
$args[] = '$arg' . $num;
|
||||
}
|
||||
if (in_array($pattern, $this->processed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$methodName = preg_replace('~(\s+?|\'|\"|\W)~', '', ucwords(preg_replace('~"(.*?)"|\d+~', '', $step->getText())));
|
||||
if (empty($methodName)) {
|
||||
$methodName = 'step_' . substr(sha1($pattern), 0, 9);
|
||||
}
|
||||
|
||||
$this->snippets[] = (new Template($this->template))
|
||||
->place('type', $step->getKeywordType())
|
||||
->place('text', $pattern)
|
||||
->place('methodName', lcfirst($methodName))
|
||||
->place('params', implode(', ', $args))
|
||||
->produce();
|
||||
|
||||
$this->processed[] = $pattern;
|
||||
}
|
||||
|
||||
public function getSnippets()
|
||||
{
|
||||
return $this->snippets;
|
||||
}
|
||||
|
||||
public function getFeatures()
|
||||
{
|
||||
return $this->features;
|
||||
}
|
||||
|
||||
public static function stepHasPyStringArgument(StepNode $step)
|
||||
{
|
||||
if ($step->hasArguments()) {
|
||||
$stepArgs = $step->getArguments();
|
||||
if ($stepArgs[count($stepArgs) - 1]->getNodeType() == "PyString") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
63
vendor/codeception/base/src/Codeception/Lib/Generator/Group.php
vendored
Normal file
63
vendor/codeception/base/src/Codeception/Lib/Generator/Group.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Generator;
|
||||
|
||||
use Codeception\Util\Shared\Namespaces;
|
||||
use Codeception\Util\Template;
|
||||
|
||||
class Group
|
||||
{
|
||||
use Namespaces;
|
||||
use Shared\Classname;
|
||||
|
||||
protected $template = <<<EOF
|
||||
<?php
|
||||
namespace {{namespace}};
|
||||
|
||||
use \Codeception\Event\TestEvent;
|
||||
/**
|
||||
* Group class is Codeception Extension which is allowed to handle to all internal events.
|
||||
* This class itself can be used to listen events for test execution of one particular group.
|
||||
* It may be especially useful to create fixtures data, prepare server, etc.
|
||||
*
|
||||
* INSTALLATION:
|
||||
*
|
||||
* To use this group extension, include it to "extensions" option of global Codeception config.
|
||||
*/
|
||||
|
||||
class {{class}} extends \Codeception\Platform\Group
|
||||
{
|
||||
public static \$group = '{{groupName}}';
|
||||
|
||||
public function _before(TestEvent \$e)
|
||||
{
|
||||
}
|
||||
|
||||
public function _after(TestEvent \$e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
EOF;
|
||||
|
||||
protected $name;
|
||||
protected $namespace;
|
||||
protected $settings;
|
||||
|
||||
public function __construct($settings, $name)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
$this->name = $name;
|
||||
$this->namespace = $this->getNamespaceString($this->settings['namespace'] . '\\Group\\' . $name);
|
||||
}
|
||||
|
||||
public function produce()
|
||||
{
|
||||
$ns = $this->getNamespaceString($this->settings['namespace'] . '\\' . $this->name);
|
||||
return (new Template($this->template))
|
||||
->place('class', ucfirst($this->name))
|
||||
->place('name', $this->name)
|
||||
->place('namespace', $this->namespace)
|
||||
->place('groupName', strtolower($this->name))
|
||||
->produce();
|
||||
}
|
||||
}
|
||||
45
vendor/codeception/base/src/Codeception/Lib/Generator/Helper.php
vendored
Normal file
45
vendor/codeception/base/src/Codeception/Lib/Generator/Helper.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Generator;
|
||||
|
||||
use Codeception\Util\Shared\Namespaces;
|
||||
use Codeception\Util\Template;
|
||||
|
||||
class Helper
|
||||
{
|
||||
use Namespaces;
|
||||
|
||||
protected $template = <<<EOF
|
||||
<?php
|
||||
{{namespace}}
|
||||
// here you can define custom actions
|
||||
// all public methods declared in helper class will be available in \$I
|
||||
|
||||
class {{name}} extends \\Codeception\\Module
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
EOF;
|
||||
|
||||
protected $namespace;
|
||||
protected $name;
|
||||
|
||||
public function __construct($name, $namespace = '')
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function produce()
|
||||
{
|
||||
return (new Template($this->template))
|
||||
->place('namespace', $this->getNamespaceHeader($this->namespace . '\\Helper\\' . $this->name))
|
||||
->place('name', $this->getShortClassName($this->name))
|
||||
->produce();
|
||||
}
|
||||
|
||||
public function getHelperName()
|
||||
{
|
||||
return rtrim('\\' . $this->namespace, '\\') . '\\Helper\\' . $this->name;
|
||||
}
|
||||
}
|
||||
94
vendor/codeception/base/src/Codeception/Lib/Generator/PageObject.php
vendored
Normal file
94
vendor/codeception/base/src/Codeception/Lib/Generator/PageObject.php
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Generator;
|
||||
|
||||
use Codeception\Util\Shared\Namespaces;
|
||||
use Codeception\Util\Template;
|
||||
|
||||
class PageObject
|
||||
{
|
||||
use Namespaces;
|
||||
use Shared\Classname;
|
||||
|
||||
protected $template = <<<EOF
|
||||
<?php
|
||||
namespace {{namespace}};
|
||||
|
||||
class {{class}}
|
||||
{
|
||||
// include url of current page
|
||||
public static \$URL = '';
|
||||
|
||||
/**
|
||||
* Declare UI map for this page here. CSS or XPath allowed.
|
||||
* public static \$usernameField = '#username';
|
||||
* public static \$formSubmitButton = "#mainForm input[type=submit]";
|
||||
*/
|
||||
|
||||
/**
|
||||
* Basic route example for your current URL
|
||||
* You can append any additional parameter to URL
|
||||
* and use it in tests like: Page\\Edit::route('/123-post');
|
||||
*/
|
||||
public static function route(\$param)
|
||||
{
|
||||
return static::\$URL.\$param;
|
||||
}
|
||||
|
||||
{{actions}}
|
||||
}
|
||||
|
||||
EOF;
|
||||
|
||||
protected $actionsTemplate = <<<EOF
|
||||
/**
|
||||
* @var \\{{actorClass}};
|
||||
*/
|
||||
protected \${{actor}};
|
||||
|
||||
public function __construct(\\{{actorClass}} \$I)
|
||||
{
|
||||
\$this->{{actor}} = \$I;
|
||||
}
|
||||
|
||||
EOF;
|
||||
|
||||
protected $actions = '';
|
||||
protected $settings;
|
||||
protected $name;
|
||||
protected $namespace;
|
||||
|
||||
public function __construct($settings, $name)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
$this->name = $this->getShortClassName($name);
|
||||
$this->namespace = $this->getNamespaceString($this->settings['namespace'] . '\\Page\\' . $name);
|
||||
}
|
||||
|
||||
public function produce()
|
||||
{
|
||||
return (new Template($this->template))
|
||||
->place('namespace', $this->namespace)
|
||||
->place('actions', $this->produceActions())
|
||||
->place('class', $this->name)
|
||||
->produce();
|
||||
}
|
||||
|
||||
protected function produceActions()
|
||||
{
|
||||
if (!isset($this->settings['actor'])) {
|
||||
return ''; // global pageobject
|
||||
}
|
||||
|
||||
$actor = lcfirst($this->settings['actor']);
|
||||
$actorClass = $this->settings['actor'];
|
||||
if (!empty($this->settings['namespace'])) {
|
||||
$actorClass = rtrim($this->settings['namespace'], '\\') . '\\' . $actorClass;
|
||||
}
|
||||
|
||||
return (new Template($this->actionsTemplate))
|
||||
->place('actorClass', $actorClass)
|
||||
->place('actor', $actor)
|
||||
->place('pageObject', $this->name)
|
||||
->produce();
|
||||
}
|
||||
}
|
||||
11
vendor/codeception/base/src/Codeception/Lib/Generator/Shared/Classname.php
vendored
Normal file
11
vendor/codeception/base/src/Codeception/Lib/Generator/Shared/Classname.php
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Generator\Shared;
|
||||
|
||||
trait Classname
|
||||
{
|
||||
protected function removeSuffix($classname, $suffix)
|
||||
{
|
||||
$classname = preg_replace('~\.php$~', '', $classname);
|
||||
return preg_replace("~$suffix$~", '', $classname);
|
||||
}
|
||||
}
|
||||
68
vendor/codeception/base/src/Codeception/Lib/Generator/StepObject.php
vendored
Normal file
68
vendor/codeception/base/src/Codeception/Lib/Generator/StepObject.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Generator;
|
||||
|
||||
use Codeception\Exception\ConfigurationException;
|
||||
use Codeception\Util\Shared\Namespaces;
|
||||
use Codeception\Util\Template;
|
||||
|
||||
class StepObject
|
||||
{
|
||||
use Namespaces;
|
||||
use Shared\Classname;
|
||||
|
||||
protected $template = <<<EOF
|
||||
<?php
|
||||
namespace {{namespace}};
|
||||
|
||||
class {{name}} extends {{actorClass}}
|
||||
{
|
||||
{{actions}}
|
||||
}
|
||||
EOF;
|
||||
|
||||
protected $actionTemplate = <<<EOF
|
||||
|
||||
public function {{action}}()
|
||||
{
|
||||
\$I = \$this;
|
||||
}
|
||||
|
||||
EOF;
|
||||
|
||||
protected $settings;
|
||||
protected $name;
|
||||
protected $actions = '';
|
||||
|
||||
public function __construct($settings, $name)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
$this->name = $this->getShortClassName($name);
|
||||
$this->namespace = $this->getNamespaceString($this->settings['namespace'] . '\\Step\\' . $name);
|
||||
}
|
||||
|
||||
public function produce()
|
||||
{
|
||||
$actor = $this->settings['actor'];
|
||||
if (!$actor) {
|
||||
throw new ConfigurationException("Steps can't be created for suite without an actor");
|
||||
}
|
||||
$ns = $this->getNamespaceString($this->settings['namespace'] . '\\' . $actor . '\\' . $this->name);
|
||||
$ns = ltrim($ns, '\\');
|
||||
|
||||
$extended = '\\' . ltrim('\\' . $this->settings['namespace'] . '\\' . $actor, '\\');
|
||||
|
||||
return (new Template($this->template))
|
||||
->place('namespace', $this->namespace)
|
||||
->place('name', $this->name)
|
||||
->place('actorClass', $extended)
|
||||
->place('actions', $this->actions)
|
||||
->produce();
|
||||
}
|
||||
|
||||
public function createAction($action)
|
||||
{
|
||||
$this->actions .= (new Template($this->actionTemplate))
|
||||
->place('action', $action)
|
||||
->produce();
|
||||
}
|
||||
}
|
||||
76
vendor/codeception/base/src/Codeception/Lib/Generator/Test.php
vendored
Normal file
76
vendor/codeception/base/src/Codeception/Lib/Generator/Test.php
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Generator;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Util\Shared\Namespaces;
|
||||
use Codeception\Util\Template;
|
||||
|
||||
class Test
|
||||
{
|
||||
use Namespaces;
|
||||
use Shared\Classname;
|
||||
|
||||
protected $template = <<<EOF
|
||||
<?php
|
||||
{{namespace}}
|
||||
class {{name}}Test extends \Codeception\Test\Unit
|
||||
{
|
||||
{{tester}}
|
||||
protected function _before()
|
||||
{
|
||||
}
|
||||
|
||||
protected function _after()
|
||||
{
|
||||
}
|
||||
|
||||
// tests
|
||||
public function testSomeFeature()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
EOF;
|
||||
|
||||
protected $testerTemplate = <<<EOF
|
||||
/**
|
||||
* @var \{{actorClass}}
|
||||
*/
|
||||
protected \${{actor}};
|
||||
|
||||
EOF;
|
||||
|
||||
|
||||
protected $settings;
|
||||
protected $name;
|
||||
|
||||
public function __construct($settings, $name)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
$this->name = $this->removeSuffix($name, 'Test');
|
||||
}
|
||||
|
||||
public function produce()
|
||||
{
|
||||
$actor = $this->settings['actor'];
|
||||
if ($this->settings['namespace']) {
|
||||
$actor = $this->settings['namespace'] . '\\' . $actor;
|
||||
}
|
||||
|
||||
$ns = $this->getNamespaceHeader($this->settings['namespace'] . '\\' . $this->name);
|
||||
|
||||
$tester = '';
|
||||
if ($this->settings['actor']) {
|
||||
$tester = (new Template($this->testerTemplate))
|
||||
->place('actorClass', $actor)
|
||||
->place('actor', lcfirst(Configuration::config()['actor_suffix']))
|
||||
->produce();
|
||||
}
|
||||
|
||||
return (new Template($this->template))
|
||||
->place('namespace', $ns)
|
||||
->place('name', $this->getShortClassName($this->name))
|
||||
->place('tester', $tester)
|
||||
->produce();
|
||||
}
|
||||
}
|
||||
133
vendor/codeception/base/src/Codeception/Lib/GroupManager.php
vendored
Normal file
133
vendor/codeception/base/src/Codeception/Lib/GroupManager.php
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
namespace Codeception\Lib;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Test\Interfaces\Reported;
|
||||
use Codeception\Test\Descriptor;
|
||||
use Codeception\TestInterface;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
|
||||
/**
|
||||
* Loads information for groups from external sources (config, filesystem)
|
||||
*/
|
||||
class GroupManager
|
||||
{
|
||||
protected $configuredGroups;
|
||||
protected $testsInGroups = [];
|
||||
|
||||
public function __construct(array $groups)
|
||||
{
|
||||
$this->configuredGroups = $groups;
|
||||
$this->loadGroupsByPattern();
|
||||
$this->loadConfiguredGroupSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* proceeds group names with asterisk:
|
||||
*
|
||||
* ```
|
||||
* "tests/_log/g_*" => [
|
||||
* "tests/_log/group_1",
|
||||
* "tests/_log/group_2",
|
||||
* "tests/_log/group_3",
|
||||
* ]
|
||||
* ```
|
||||
*/
|
||||
protected function loadGroupsByPattern()
|
||||
{
|
||||
foreach ($this->configuredGroups as $group => $pattern) {
|
||||
if (strpos($group, '*') === false) {
|
||||
continue;
|
||||
}
|
||||
$files = Finder::create()->files()
|
||||
->name(basename($pattern))
|
||||
->sortByName()
|
||||
->in(Configuration::projectDir().dirname($pattern));
|
||||
|
||||
$i = 1;
|
||||
foreach ($files as $file) {
|
||||
/** @var SplFileInfo $file * */
|
||||
$this->configuredGroups[str_replace('*', $i, $group)] = dirname($pattern).DIRECTORY_SEPARATOR.$file->getRelativePathname();
|
||||
$i++;
|
||||
}
|
||||
unset($this->configuredGroups[$group]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadConfiguredGroupSettings()
|
||||
{
|
||||
foreach ($this->configuredGroups as $group => $tests) {
|
||||
$this->testsInGroups[$group] = [];
|
||||
if (is_array($tests)) {
|
||||
foreach ($tests as $test) {
|
||||
$file = str_replace(['/', '\\'], [DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR], $test);
|
||||
$this->testsInGroups[$group][] = Configuration::projectDir() . $file;
|
||||
}
|
||||
} elseif (is_file(Configuration::projectDir() . $tests)) {
|
||||
$handle = @fopen(Configuration::projectDir() . $tests, "r");
|
||||
if ($handle) {
|
||||
while (($test = fgets($handle, 4096)) !== false) {
|
||||
// if the current line is blank then we need to move to the next line
|
||||
// otherwise the current codeception directory becomes part of the group
|
||||
// which causes every single test to run
|
||||
if (trim($test) === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$file = trim(Configuration::projectDir() . $test);
|
||||
$file = str_replace(['/', '\\'], [DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR], $file);
|
||||
$this->testsInGroups[$group][] = $file;
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function groupsForTest(\PHPUnit\Framework\Test $test)
|
||||
{
|
||||
$groups = [];
|
||||
$filename = Descriptor::getTestFileName($test);
|
||||
if ($test instanceof TestInterface) {
|
||||
$groups = $test->getMetadata()->getGroups();
|
||||
}
|
||||
if ($test instanceof Reported) {
|
||||
$info = $test->getReportFields();
|
||||
if (isset($info['class'])) {
|
||||
$groups = array_merge($groups, \PHPUnit\Util\Test::getGroups($info['class'], $info['name']));
|
||||
}
|
||||
$filename = str_replace(['\\\\', '//'], ['\\', '/'], $info['file']);
|
||||
}
|
||||
if ($test instanceof \PHPUnit\Framework\TestCase) {
|
||||
$groups = array_merge($groups, \PHPUnit\Util\Test::getGroups(get_class($test), $test->getName(false)));
|
||||
}
|
||||
if ($test instanceof \PHPUnit\Framework\TestSuite\DataProvider) {
|
||||
$firstTest = $test->testAt(0);
|
||||
if ($firstTest != false && $firstTest instanceof TestInterface) {
|
||||
$groups = array_merge($groups, $firstTest->getMetadata()->getGroups());
|
||||
$filename = Descriptor::getTestFileName($firstTest);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->testsInGroups as $group => $tests) {
|
||||
foreach ($tests as $testPattern) {
|
||||
if ($filename == $testPattern) {
|
||||
$groups[] = $group;
|
||||
}
|
||||
if (strpos($filename . ':' . $test->getName(false), $testPattern) === 0) {
|
||||
$groups[] = $group;
|
||||
}
|
||||
if ($test instanceof \PHPUnit\Framework\TestSuite\DataProvider) {
|
||||
$firstTest = $test->testAt(0);
|
||||
if ($firstTest != false && $firstTest instanceof TestInterface) {
|
||||
if (strpos($filename . ':' . $firstTest->getName(false), $testPattern) === 0) {
|
||||
$groups[] = $group;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return array_unique($groups);
|
||||
}
|
||||
}
|
||||
1957
vendor/codeception/base/src/Codeception/Lib/InnerBrowser.php
vendored
Normal file
1957
vendor/codeception/base/src/Codeception/Lib/InnerBrowser.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
vendor/codeception/base/src/Codeception/Lib/Interfaces/API.php
vendored
Normal file
9
vendor/codeception/base/src/Codeception/Lib/Interfaces/API.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
/**
|
||||
* Modules for API testing
|
||||
*/
|
||||
interface API
|
||||
{
|
||||
}
|
||||
13
vendor/codeception/base/src/Codeception/Lib/Interfaces/ActiveRecord.php
vendored
Normal file
13
vendor/codeception/base/src/Codeception/Lib/Interfaces/ActiveRecord.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface ActiveRecord extends ORM
|
||||
{
|
||||
public function haveRecord($model, $attributes = []);
|
||||
|
||||
public function seeRecord($model, $attributes = []);
|
||||
|
||||
public function dontSeeRecord($model, $attributes = []);
|
||||
|
||||
public function grabRecord($model, $attributes = []);
|
||||
}
|
||||
11
vendor/codeception/base/src/Codeception/Lib/Interfaces/ConflictsWithModule.php
vendored
Normal file
11
vendor/codeception/base/src/Codeception/Lib/Interfaces/ConflictsWithModule.php
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface ConflictsWithModule
|
||||
{
|
||||
/**
|
||||
* Returns class name or interface of module which can conflict with current.
|
||||
* @return string
|
||||
*/
|
||||
public function _conflicts();
|
||||
}
|
||||
13
vendor/codeception/base/src/Codeception/Lib/Interfaces/DataMapper.php
vendored
Normal file
13
vendor/codeception/base/src/Codeception/Lib/Interfaces/DataMapper.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface DataMapper extends ORM, DoctrineProvider
|
||||
{
|
||||
public function haveInRepository($entity, array $data);
|
||||
|
||||
public function seeInRepository($entity, $params = []);
|
||||
|
||||
public function dontSeeInRepository($entity, $params = []);
|
||||
|
||||
public function grabFromRepository($entity, $field, $params = []);
|
||||
}
|
||||
84
vendor/codeception/base/src/Codeception/Lib/Interfaces/Db.php
vendored
Normal file
84
vendor/codeception/base/src/Codeception/Lib/Interfaces/Db.php
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface Db
|
||||
{
|
||||
/**
|
||||
* Asserts that a row with the given column values exists.
|
||||
* Provide table name and column values.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->seeInDatabase('users', ['name' => 'Davert', 'email' => 'davert@mail.com']);
|
||||
* ```
|
||||
* Fails if no such user found.
|
||||
*
|
||||
* Comparison expressions can be used as well:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->seeInDatabase('posts', ['num_comments >=' => '0']);
|
||||
* $I->seeInDatabase('users', ['email like' => 'miles@davis.com']);
|
||||
* ```
|
||||
*
|
||||
* Supported operators: `<`, `>`, `>=`, `<=`, `!=`, `like`.
|
||||
*
|
||||
*
|
||||
* @param string $table
|
||||
* @param array $criteria
|
||||
*/
|
||||
public function seeInDatabase($table, $criteria = []);
|
||||
|
||||
/**
|
||||
* Effect is opposite to ->seeInDatabase
|
||||
*
|
||||
* Asserts that there is no record with the given column values in a database.
|
||||
* Provide table name and column values.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->dontSeeInDatabase('users', ['name' => 'Davert', 'email' => 'davert@mail.com']);
|
||||
* ```
|
||||
* Fails if such user was found.
|
||||
*
|
||||
* Comparison expressions can be used as well:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->dontSeeInDatabase('posts', ['num_comments >=' => '0']);
|
||||
* $I->dontSeeInDatabase('users', ['email like' => 'miles%']);
|
||||
* ```
|
||||
*
|
||||
* Supported operators: `<`, `>`, `>=`, `<=`, `!=`, `like`.
|
||||
*
|
||||
* @param string $table
|
||||
* @param array $criteria
|
||||
*/
|
||||
public function dontSeeInDatabase($table, $criteria = []);
|
||||
|
||||
/**
|
||||
* Fetches a single column value from a database.
|
||||
* Provide table name, desired column and criteria.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $mail = $I->grabFromDatabase('users', 'email', array('name' => 'Davert'));
|
||||
* ```
|
||||
* Comparison expressions can be used as well:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $post = $I->grabFromDatabase('posts', ['num_comments >=' => 100]);
|
||||
* $user = $I->grabFromDatabase('users', ['email like' => 'miles%']);
|
||||
* ```
|
||||
*
|
||||
* Supported operators: `<`, `>`, `>=`, `<=`, `!=`, `like`.
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $column
|
||||
* @param array $criteria
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function grabFromDatabase($table, $column, $criteria = []);
|
||||
}
|
||||
15
vendor/codeception/base/src/Codeception/Lib/Interfaces/DependsOnModule.php
vendored
Normal file
15
vendor/codeception/base/src/Codeception/Lib/Interfaces/DependsOnModule.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface DependsOnModule
|
||||
{
|
||||
/**
|
||||
* Specifies class or module which is required for current one.
|
||||
*
|
||||
* THis method should return array with key as class name and value as error message
|
||||
* [className => errorMessage
|
||||
* ]
|
||||
* @return mixed
|
||||
*/
|
||||
public function _depends();
|
||||
}
|
||||
7
vendor/codeception/base/src/Codeception/Lib/Interfaces/DoctrineProvider.php
vendored
Normal file
7
vendor/codeception/base/src/Codeception/Lib/Interfaces/DoctrineProvider.php
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface DoctrineProvider
|
||||
{
|
||||
public function _getEntityManager();
|
||||
}
|
||||
32
vendor/codeception/base/src/Codeception/Lib/Interfaces/ElementLocator.php
vendored
Normal file
32
vendor/codeception/base/src/Codeception/Lib/Interfaces/ElementLocator.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface ElementLocator
|
||||
{
|
||||
/**
|
||||
* Locates element using available Codeception locator types:
|
||||
*
|
||||
* * XPath
|
||||
* * CSS
|
||||
* * Strict Locator
|
||||
*
|
||||
* Use it in Helpers or GroupObject or Extension classes:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $els = $this->getModule('{{MODULE_NAME}}')->_findElements('.items');
|
||||
* $els = $this->getModule('{{MODULE_NAME}}')->_findElements(['name' => 'username']);
|
||||
*
|
||||
* $editLinks = $this->getModule('{{MODULE_NAME}}')->_findElements(['link' => 'Edit']);
|
||||
* // now you can iterate over $editLinks and check that all them have valid hrefs
|
||||
* ```
|
||||
*
|
||||
* WebDriver module returns `Facebook\WebDriver\Remote\RemoteWebElement` instances
|
||||
* PhpBrowser and Framework modules return `Symfony\Component\DomCrawler\Crawler` instances
|
||||
*
|
||||
* @api
|
||||
* @param $locator
|
||||
* @return array of interactive elements
|
||||
*/
|
||||
public function _findElements($locator);
|
||||
}
|
||||
15
vendor/codeception/base/src/Codeception/Lib/Interfaces/MultiSession.php
vendored
Normal file
15
vendor/codeception/base/src/Codeception/Lib/Interfaces/MultiSession.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface MultiSession
|
||||
{
|
||||
public function _initializeSession();
|
||||
|
||||
public function _loadSession($session);
|
||||
|
||||
public function _backupSession();
|
||||
|
||||
public function _closeSession($session = null);
|
||||
|
||||
public function _getName();
|
||||
}
|
||||
6
vendor/codeception/base/src/Codeception/Lib/Interfaces/ORM.php
vendored
Normal file
6
vendor/codeception/base/src/Codeception/Lib/Interfaces/ORM.php
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface ORM
|
||||
{
|
||||
}
|
||||
16
vendor/codeception/base/src/Codeception/Lib/Interfaces/PageSourceSaver.php
vendored
Normal file
16
vendor/codeception/base/src/Codeception/Lib/Interfaces/PageSourceSaver.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface PageSourceSaver
|
||||
{
|
||||
/**
|
||||
* Saves page source of to a file
|
||||
*
|
||||
* ```php
|
||||
* $this->getModule('{{MODULE_NAME}}')->_savePageSource(codecept_output_dir().'page.html');
|
||||
* ```
|
||||
* @api
|
||||
* @param $filename
|
||||
*/
|
||||
public function _savePageSource($filename);
|
||||
}
|
||||
25
vendor/codeception/base/src/Codeception/Lib/Interfaces/PartedModule.php
vendored
Normal file
25
vendor/codeception/base/src/Codeception/Lib/Interfaces/PartedModule.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
/**
|
||||
* Interface PartedModule
|
||||
*
|
||||
* Module implementing this interface can be loaded partly.
|
||||
* Parts can be defined by marking methods with `@part` annotations.
|
||||
* Part of modules can be loaded by specifying part (or several parts) in config:
|
||||
*
|
||||
* ```
|
||||
* modules:
|
||||
* enabled: [MyModule]
|
||||
* config:
|
||||
* MyModule:
|
||||
* part: usefulActions
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* @package Codeception\Lib\Interfaces
|
||||
*/
|
||||
interface PartedModule
|
||||
{
|
||||
public function _parts();
|
||||
}
|
||||
52
vendor/codeception/base/src/Codeception/Lib/Interfaces/Queue.php
vendored
Normal file
52
vendor/codeception/base/src/Codeception/Lib/Interfaces/Queue.php
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface Queue
|
||||
{
|
||||
|
||||
/**
|
||||
* Connect to the queueing server.
|
||||
* @param array $config
|
||||
* @return
|
||||
*/
|
||||
public function openConnection($config);
|
||||
|
||||
/**
|
||||
* Post/Put a message on to the queue server
|
||||
*
|
||||
* @param string $message Message Body to be send
|
||||
* @param string $queue Queue Name
|
||||
*/
|
||||
public function addMessageToQueue($message, $queue);
|
||||
|
||||
/**
|
||||
* Return a list of queues/tubes on the queueing server
|
||||
*
|
||||
* @return array Array of Queues
|
||||
*/
|
||||
public function getQueues();
|
||||
|
||||
/**
|
||||
* Count the current number of messages on the queue.
|
||||
*
|
||||
* @param $queue Queue Name
|
||||
*
|
||||
* @return int Count
|
||||
*/
|
||||
public function getMessagesCurrentCountOnQueue($queue);
|
||||
|
||||
/**
|
||||
* Count the total number of messages on the queue.
|
||||
*
|
||||
* @param $queue Queue Name
|
||||
*
|
||||
* @return int Count
|
||||
*/
|
||||
public function getMessagesTotalCountOnQueue($queue);
|
||||
|
||||
public function clearQueue($queue);
|
||||
|
||||
public function getRequiredConfig();
|
||||
|
||||
public function getDefaultConfig();
|
||||
}
|
||||
41
vendor/codeception/base/src/Codeception/Lib/Interfaces/Remote.php
vendored
Normal file
41
vendor/codeception/base/src/Codeception/Lib/Interfaces/Remote.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface Remote
|
||||
{
|
||||
/**
|
||||
* Changes the subdomain for the 'url' configuration parameter.
|
||||
* Does not open a page; use `amOnPage` for that.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // If config is: 'http://mysite.com'
|
||||
* // or config is: 'http://www.mysite.com'
|
||||
* // or config is: 'http://company.mysite.com'
|
||||
*
|
||||
* $I->amOnSubdomain('user');
|
||||
* $I->amOnPage('/');
|
||||
* // moves to http://user.mysite.com/
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $subdomain
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function amOnSubdomain($subdomain);
|
||||
|
||||
/**
|
||||
* Open web page at the given absolute URL and sets its hostname as the base host.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->amOnUrl('http://codeception.com');
|
||||
* $I->amOnPage('/quickstart'); // moves to http://codeception.com/quickstart
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
public function amOnUrl($url);
|
||||
|
||||
public function _getUrl();
|
||||
}
|
||||
11
vendor/codeception/base/src/Codeception/Lib/Interfaces/RequiresPackage.php
vendored
Normal file
11
vendor/codeception/base/src/Codeception/Lib/Interfaces/RequiresPackage.php
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface RequiresPackage
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns list of classes and corresponding packages required for this module
|
||||
*/
|
||||
public function _requires();
|
||||
}
|
||||
16
vendor/codeception/base/src/Codeception/Lib/Interfaces/ScreenshotSaver.php
vendored
Normal file
16
vendor/codeception/base/src/Codeception/Lib/Interfaces/ScreenshotSaver.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface ScreenshotSaver
|
||||
{
|
||||
/**
|
||||
* Saves screenshot of current page to a file
|
||||
*
|
||||
* ```php
|
||||
* $this->getModule('{{MODULE_NAME}}')->_saveScreenshot(codecept_output_dir().'screenshot_1.png');
|
||||
* ```
|
||||
* @api
|
||||
* @param $filename
|
||||
*/
|
||||
public function _saveScreenshot($filename);
|
||||
}
|
||||
58
vendor/codeception/base/src/Codeception/Lib/Interfaces/SessionSnapshot.php
vendored
Normal file
58
vendor/codeception/base/src/Codeception/Lib/Interfaces/SessionSnapshot.php
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface SessionSnapshot
|
||||
{
|
||||
/**
|
||||
* Saves current cookies into named snapshot in order to restore them in other tests
|
||||
* This is useful to save session state between tests.
|
||||
* For example, if user needs log in to site for each test this scenario can be executed once
|
||||
* while other tests can just restore saved cookies.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // inside AcceptanceTester class:
|
||||
*
|
||||
* public function login()
|
||||
* {
|
||||
* // if snapshot exists - skipping login
|
||||
* if ($I->loadSessionSnapshot('login')) return;
|
||||
*
|
||||
* // logging in
|
||||
* $I->amOnPage('/login');
|
||||
* $I->fillField('name', 'jon');
|
||||
* $I->fillField('password', '123345');
|
||||
* $I->click('Login');
|
||||
*
|
||||
* // saving snapshot
|
||||
* $I->saveSessionSnapshot('login');
|
||||
* }
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function saveSessionSnapshot($name);
|
||||
|
||||
/**
|
||||
* Loads cookies from a saved snapshot.
|
||||
* Allows to reuse same session across tests without additional login.
|
||||
*
|
||||
* See [saveSessionSnapshot](#saveSessionSnapshot)
|
||||
*
|
||||
* @param $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function loadSessionSnapshot($name);
|
||||
|
||||
/**
|
||||
* Deletes session snapshot.
|
||||
*
|
||||
* See [saveSessionSnapshot](#saveSessionSnapshot)
|
||||
*
|
||||
* @param $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function deleteSessionSnapshot($name);
|
||||
}
|
||||
983
vendor/codeception/base/src/Codeception/Lib/Interfaces/Web.php
vendored
Normal file
983
vendor/codeception/base/src/Codeception/Lib/Interfaces/Web.php
vendored
Normal file
@@ -0,0 +1,983 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Interfaces;
|
||||
|
||||
interface Web
|
||||
{
|
||||
/**
|
||||
* Opens the page for the given relative URI.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // opens front page
|
||||
* $I->amOnPage('/');
|
||||
* // opens /register page
|
||||
* $I->amOnPage('/register');
|
||||
* ```
|
||||
*
|
||||
* @param string $page
|
||||
*/
|
||||
public function amOnPage($page);
|
||||
|
||||
/**
|
||||
* Checks that the current page contains the given string (case insensitive).
|
||||
*
|
||||
* You can specify a specific HTML element (via CSS or XPath) as the second
|
||||
* parameter to only search within that element.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->see('Logout'); // I can suppose user is logged in
|
||||
* $I->see('Sign Up', 'h1'); // I can suppose it's a signup page
|
||||
* $I->see('Sign Up', '//body/h1'); // with XPath
|
||||
* $I->see('Sign Up', ['css' => 'body h1']); // with strict CSS locator
|
||||
* ```
|
||||
*
|
||||
* Note that the search is done after stripping all HTML tags from the body,
|
||||
* so `$I->see('strong')` will return true for strings like:
|
||||
*
|
||||
* - `<p>I am Stronger than thou</p>`
|
||||
* - `<script>document.createElement('strong');</script>`
|
||||
*
|
||||
* But will *not* be true for strings like:
|
||||
*
|
||||
* - `<strong>Home</strong>`
|
||||
* - `<div class="strong">Home</strong>`
|
||||
* - `<!-- strong -->`
|
||||
*
|
||||
* For checking the raw source code, use `seeInSource()`.
|
||||
*
|
||||
* @param string $text
|
||||
* @param string $selector optional
|
||||
*/
|
||||
public function see($text, $selector = null);
|
||||
|
||||
/**
|
||||
* Checks that the current page doesn't contain the text specified (case insensitive).
|
||||
* Give a locator as the second parameter to match a specific region.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->dontSee('Login'); // I can suppose user is already logged in
|
||||
* $I->dontSee('Sign Up','h1'); // I can suppose it's not a signup page
|
||||
* $I->dontSee('Sign Up','//body/h1'); // with XPath
|
||||
* $I->dontSee('Sign Up', ['css' => 'body h1']); // with strict CSS locator
|
||||
* ```
|
||||
*
|
||||
* Note that the search is done after stripping all HTML tags from the body,
|
||||
* so `$I->dontSee('strong')` will fail on strings like:
|
||||
*
|
||||
* - `<p>I am Stronger than thou</p>`
|
||||
* - `<script>document.createElement('strong');</script>`
|
||||
*
|
||||
* But will ignore strings like:
|
||||
*
|
||||
* - `<strong>Home</strong>`
|
||||
* - `<div class="strong">Home</strong>`
|
||||
* - `<!-- strong -->`
|
||||
*
|
||||
* For checking the raw source code, use `seeInSource()`.
|
||||
*
|
||||
* @param string $text
|
||||
* @param string $selector optional
|
||||
*/
|
||||
public function dontSee($text, $selector = null);
|
||||
|
||||
/**
|
||||
* Checks that the current page contains the given string in its
|
||||
* raw source code.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeInSource('<h1>Green eggs & ham</h1>');
|
||||
* ```
|
||||
*
|
||||
* @param $raw
|
||||
*/
|
||||
public function seeInSource($raw);
|
||||
|
||||
/**
|
||||
* Checks that the current page contains the given string in its
|
||||
* raw source code.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->dontSeeInSource('<h1>Green eggs & ham</h1>');
|
||||
* ```
|
||||
*
|
||||
* @param $raw
|
||||
*/
|
||||
public function dontSeeInSource($raw);
|
||||
|
||||
/**
|
||||
* Submits the given form on the page, with the given form
|
||||
* values. Pass the form field's values as an array in the second
|
||||
* parameter.
|
||||
*
|
||||
* Although this function can be used as a short-hand version of
|
||||
* `fillField()`, `selectOption()`, `click()` etc. it has some important
|
||||
* differences:
|
||||
*
|
||||
* * Only field *names* may be used, not CSS/XPath selectors nor field labels
|
||||
* * If a field is sent to this function that does *not* exist on the page,
|
||||
* it will silently be added to the HTTP request. This is helpful for testing
|
||||
* some types of forms, but be aware that you will *not* get an exception
|
||||
* like you would if you called `fillField()` or `selectOption()` with
|
||||
* a missing field.
|
||||
*
|
||||
* Fields that are not provided will be filled by their values from the page,
|
||||
* or from any previous calls to `fillField()`, `selectOption()` etc.
|
||||
* You don't need to click the 'Submit' button afterwards.
|
||||
* This command itself triggers the request to form's action.
|
||||
*
|
||||
* You can optionally specify which button's value to include
|
||||
* in the request with the last parameter (as an alternative to
|
||||
* explicitly setting its value in the second parameter), as
|
||||
* button values are not otherwise included in the request.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->submitForm('#login', [
|
||||
* 'login' => 'davert',
|
||||
* 'password' => '123456'
|
||||
* ]);
|
||||
* // or
|
||||
* $I->submitForm('#login', [
|
||||
* 'login' => 'davert',
|
||||
* 'password' => '123456'
|
||||
* ], 'submitButtonName');
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* For example, given this sample "Sign Up" form:
|
||||
*
|
||||
* ``` html
|
||||
* <form action="/sign_up">
|
||||
* Login:
|
||||
* <input type="text" name="user[login]" /><br/>
|
||||
* Password:
|
||||
* <input type="password" name="user[password]" /><br/>
|
||||
* Do you agree to our terms?
|
||||
* <input type="checkbox" name="user[agree]" /><br/>
|
||||
* Select pricing plan:
|
||||
* <select name="plan">
|
||||
* <option value="1">Free</option>
|
||||
* <option value="2" selected="selected">Paid</option>
|
||||
* </select>
|
||||
* <input type="submit" name="submitButton" value="Submit" />
|
||||
* </form>
|
||||
* ```
|
||||
*
|
||||
* You could write the following to submit it:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->submitForm(
|
||||
* '#userForm',
|
||||
* [
|
||||
* 'user' => [
|
||||
* 'login' => 'Davert',
|
||||
* 'password' => '123456',
|
||||
* 'agree' => true
|
||||
* ]
|
||||
* ],
|
||||
* 'submitButton'
|
||||
* );
|
||||
* ```
|
||||
* Note that "2" will be the submitted value for the "plan" field, as it is
|
||||
* the selected option.
|
||||
*
|
||||
* You can also emulate a JavaScript submission by not specifying any
|
||||
* buttons in the third parameter to submitForm.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->submitForm(
|
||||
* '#userForm',
|
||||
* [
|
||||
* 'user' => [
|
||||
* 'login' => 'Davert',
|
||||
* 'password' => '123456',
|
||||
* 'agree' => true
|
||||
* ]
|
||||
* ]
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* This function works well when paired with `seeInFormFields()`
|
||||
* for quickly testing CRUD interfaces and form validation logic.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $form = [
|
||||
* 'field1' => 'value',
|
||||
* 'field2' => 'another value',
|
||||
* 'checkbox1' => true,
|
||||
* // ...
|
||||
* ];
|
||||
* $I->submitForm('#my-form', $form, 'submitButton');
|
||||
* // $I->amOnPage('/path/to/form-page') may be needed
|
||||
* $I->seeInFormFields('#my-form', $form);
|
||||
* ```
|
||||
*
|
||||
* Parameter values can be set to arrays for multiple input fields
|
||||
* of the same name, or multi-select combo boxes. For checkboxes,
|
||||
* you can use either the string value or boolean `true`/`false` which will
|
||||
* be replaced by the checkbox's value in the DOM.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->submitForm('#my-form', [
|
||||
* 'field1' => 'value',
|
||||
* 'checkbox' => [
|
||||
* 'value of first checkbox',
|
||||
* 'value of second checkbox',
|
||||
* ],
|
||||
* 'otherCheckboxes' => [
|
||||
* true,
|
||||
* false,
|
||||
* false
|
||||
* ],
|
||||
* 'multiselect' => [
|
||||
* 'first option value',
|
||||
* 'second option value'
|
||||
* ]
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* Mixing string and boolean values for a checkbox's value is not supported
|
||||
* and may produce unexpected results.
|
||||
*
|
||||
* Field names ending in `[]` must be passed without the trailing square
|
||||
* bracket characters, and must contain an array for its value. This allows
|
||||
* submitting multiple values with the same name, consider:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* // This will NOT work correctly
|
||||
* $I->submitForm('#my-form', [
|
||||
* 'field[]' => 'value',
|
||||
* 'field[]' => 'another value', // 'field[]' is already a defined key
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* The solution is to pass an array value:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* // This way both values are submitted
|
||||
* $I->submitForm('#my-form', [
|
||||
* 'field' => [
|
||||
* 'value',
|
||||
* 'another value',
|
||||
* ]
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* @param $selector
|
||||
* @param $params
|
||||
* @param $button
|
||||
*/
|
||||
public function submitForm($selector, array $params, $button = null);
|
||||
|
||||
/**
|
||||
* Perform a click on a link or a button, given by a locator.
|
||||
* If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.
|
||||
* For buttons, the "value" attribute, "name" attribute, and inner text are searched.
|
||||
* For links, the link text is searched.
|
||||
* For images, the "alt" attribute and inner text of any parent links are searched.
|
||||
*
|
||||
* The second parameter is a context (CSS or XPath locator) to narrow the search.
|
||||
*
|
||||
* Note that if the locator matches a button of type `submit`, the form will be submitted.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // simple link
|
||||
* $I->click('Logout');
|
||||
* // button of form
|
||||
* $I->click('Submit');
|
||||
* // CSS button
|
||||
* $I->click('#form input[type=submit]');
|
||||
* // XPath
|
||||
* $I->click('//form/*[@type=submit]');
|
||||
* // link in context
|
||||
* $I->click('Logout', '#nav');
|
||||
* // using strict locator
|
||||
* $I->click(['link' => 'Login']);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $link
|
||||
* @param $context
|
||||
*/
|
||||
public function click($link, $context = null);
|
||||
|
||||
/**
|
||||
* Checks that there's a link with the specified text.
|
||||
* Give a full URL as the second parameter to match links with that exact URL.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeLink('Logout'); // matches <a href="#">Logout</a>
|
||||
* $I->seeLink('Logout','/logout'); // matches <a href="/logout">Logout</a>
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $text
|
||||
* @param string $url optional
|
||||
*/
|
||||
public function seeLink($text, $url = null);
|
||||
|
||||
/**
|
||||
* Checks that the page doesn't contain a link with the given string.
|
||||
* If the second parameter is given, only links with a matching "href" attribute will be checked.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->dontSeeLink('Logout'); // I suppose user is not logged in
|
||||
* $I->dontSeeLink('Checkout now', '/store/cart.php');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $text
|
||||
* @param string $url optional
|
||||
*/
|
||||
public function dontSeeLink($text, $url = null);
|
||||
|
||||
/**
|
||||
* Checks that current URI contains the given string.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // to match: /home/dashboard
|
||||
* $I->seeInCurrentUrl('home');
|
||||
* // to match: /users/1
|
||||
* $I->seeInCurrentUrl('/users/');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $uri
|
||||
*/
|
||||
public function seeInCurrentUrl($uri);
|
||||
|
||||
/**
|
||||
* Checks that the current URL is equal to the given string.
|
||||
* Unlike `seeInCurrentUrl`, this only matches the full URL.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // to match root url
|
||||
* $I->seeCurrentUrlEquals('/');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $uri
|
||||
*/
|
||||
public function seeCurrentUrlEquals($uri);
|
||||
|
||||
/**
|
||||
* Checks that the current URL matches the given regular expression.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // to match root url
|
||||
* $I->seeCurrentUrlMatches('~$/users/(\d+)~');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $uri
|
||||
*/
|
||||
public function seeCurrentUrlMatches($uri);
|
||||
|
||||
/**
|
||||
* Checks that the current URI doesn't contain the given string.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->dontSeeInCurrentUrl('/users/');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $uri
|
||||
*/
|
||||
public function dontSeeInCurrentUrl($uri);
|
||||
|
||||
/**
|
||||
* Checks that the current URL doesn't equal the given string.
|
||||
* Unlike `dontSeeInCurrentUrl`, this only matches the full URL.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // current url is not root
|
||||
* $I->dontSeeCurrentUrlEquals('/');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $uri
|
||||
*/
|
||||
public function dontSeeCurrentUrlEquals($uri);
|
||||
|
||||
/**
|
||||
* Checks that current url doesn't match the given regular expression.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // to match root url
|
||||
* $I->dontSeeCurrentUrlMatches('~$/users/(\d+)~');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $uri
|
||||
*/
|
||||
public function dontSeeCurrentUrlMatches($uri);
|
||||
|
||||
/**
|
||||
* Executes the given regular expression against the current URI and returns the first capturing group.
|
||||
* If no parameters are provided, the full URI is returned.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $user_id = $I->grabFromCurrentUrl('~$/user/(\d+)/~');
|
||||
* $uri = $I->grabFromCurrentUrl();
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $uri optional
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function grabFromCurrentUrl($uri = null);
|
||||
|
||||
/**
|
||||
* Checks that the specified checkbox is checked.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms
|
||||
* $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form.
|
||||
* $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $checkbox
|
||||
*/
|
||||
public function seeCheckboxIsChecked($checkbox);
|
||||
|
||||
/**
|
||||
* Check that the specified checkbox is unchecked.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms
|
||||
* $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form.
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $checkbox
|
||||
*/
|
||||
public function dontSeeCheckboxIsChecked($checkbox);
|
||||
|
||||
/**
|
||||
* Checks that the given input field or textarea *equals* (i.e. not just contains) the given value.
|
||||
* Fields are matched by label text, the "name" attribute, CSS, or XPath.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeInField('Body','Type your comment here');
|
||||
* $I->seeInField('form textarea[name=body]','Type your comment here');
|
||||
* $I->seeInField('form input[type=hidden]','hidden_value');
|
||||
* $I->seeInField('#searchform input','Search');
|
||||
* $I->seeInField('//form/*[@name=search]','Search');
|
||||
* $I->seeInField(['name' => 'search'], 'Search');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $field
|
||||
* @param $value
|
||||
*/
|
||||
public function seeInField($field, $value);
|
||||
|
||||
/**
|
||||
* Checks that an input field or textarea doesn't contain the given value.
|
||||
* For fuzzy locators, the field is matched by label text, CSS and XPath.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->dontSeeInField('Body','Type your comment here');
|
||||
* $I->dontSeeInField('form textarea[name=body]','Type your comment here');
|
||||
* $I->dontSeeInField('form input[type=hidden]','hidden_value');
|
||||
* $I->dontSeeInField('#searchform input','Search');
|
||||
* $I->dontSeeInField('//form/*[@name=search]','Search');
|
||||
* $I->dontSeeInField(['name' => 'search'], 'Search');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $field
|
||||
* @param $value
|
||||
*/
|
||||
public function dontSeeInField($field, $value);
|
||||
|
||||
/**
|
||||
* Checks if the array of form parameters (name => value) are set on the form matched with the
|
||||
* passed selector.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeInFormFields('form[name=myform]', [
|
||||
* 'input1' => 'value',
|
||||
* 'input2' => 'other value',
|
||||
* ]);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* For multi-select elements, or to check values of multiple elements with the same name, an
|
||||
* array may be passed:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeInFormFields('.form-class', [
|
||||
* 'multiselect' => [
|
||||
* 'value1',
|
||||
* 'value2',
|
||||
* ],
|
||||
* 'checkbox[]' => [
|
||||
* 'a checked value',
|
||||
* 'another checked value',
|
||||
* ],
|
||||
* ]);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* Additionally, checkbox values can be checked with a boolean.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeInFormFields('#form-id', [
|
||||
* 'checkbox1' => true, // passes if checked
|
||||
* 'checkbox2' => false, // passes if unchecked
|
||||
* ]);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* Pair this with submitForm for quick testing magic.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $form = [
|
||||
* 'field1' => 'value',
|
||||
* 'field2' => 'another value',
|
||||
* 'checkbox1' => true,
|
||||
* // ...
|
||||
* ];
|
||||
* $I->submitForm('//form[@id=my-form]', $form, 'submitButton');
|
||||
* // $I->amOnPage('/path/to/form-page') may be needed
|
||||
* $I->seeInFormFields('//form[@id=my-form]', $form);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $formSelector
|
||||
* @param $params
|
||||
*/
|
||||
public function seeInFormFields($formSelector, array $params);
|
||||
|
||||
/**
|
||||
* Checks if the array of form parameters (name => value) are not set on the form matched with
|
||||
* the passed selector.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->dontSeeInFormFields('form[name=myform]', [
|
||||
* 'input1' => 'non-existent value',
|
||||
* 'input2' => 'other non-existent value',
|
||||
* ]);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* To check that an element hasn't been assigned any one of many values, an array can be passed
|
||||
* as the value:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->dontSeeInFormFields('.form-class', [
|
||||
* 'fieldName' => [
|
||||
* 'This value shouldn\'t be set',
|
||||
* 'And this value shouldn\'t be set',
|
||||
* ],
|
||||
* ]);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* Additionally, checkbox values can be checked with a boolean.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->dontSeeInFormFields('#form-id', [
|
||||
* 'checkbox1' => true, // fails if checked
|
||||
* 'checkbox2' => false, // fails if unchecked
|
||||
* ]);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $formSelector
|
||||
* @param $params
|
||||
*/
|
||||
public function dontSeeInFormFields($formSelector, array $params);
|
||||
|
||||
/**
|
||||
* Selects an option in a select tag or in radio button group.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->selectOption('form select[name=account]', 'Premium');
|
||||
* $I->selectOption('form input[name=payment]', 'Monthly');
|
||||
* $I->selectOption('//form/select[@name=account]', 'Monthly');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* Provide an array for the second argument to select multiple options:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->selectOption('Which OS do you use?', array('Windows','Linux'));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* Or provide an associative array for the second argument to specifically define which selection method should be used:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->selectOption('Which OS do you use?', array('text' => 'Windows')); // Only search by text 'Windows'
|
||||
* $I->selectOption('Which OS do you use?', array('value' => 'windows')); // Only search by value 'windows'
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $select
|
||||
* @param $option
|
||||
*/
|
||||
public function selectOption($select, $option);
|
||||
|
||||
/**
|
||||
* Ticks a checkbox. For radio buttons, use the `selectOption` method instead.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->checkOption('#agree');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $option
|
||||
*/
|
||||
public function checkOption($option);
|
||||
|
||||
/**
|
||||
* Unticks a checkbox.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->uncheckOption('#notify');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $option
|
||||
*/
|
||||
public function uncheckOption($option);
|
||||
|
||||
/**
|
||||
* Fills a text field or textarea with the given string.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->fillField("//input[@type='text']", "Hello World!");
|
||||
* $I->fillField(['name' => 'email'], 'jon@mail.com');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $field
|
||||
* @param $value
|
||||
*/
|
||||
public function fillField($field, $value);
|
||||
|
||||
/**
|
||||
* Attaches a file relative to the Codeception `_data` directory to the given file upload field.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // file is stored in 'tests/_data/prices.xls'
|
||||
* $I->attachFile('input[@type="file"]', 'prices.xls');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $field
|
||||
* @param $filename
|
||||
*/
|
||||
public function attachFile($field, $filename);
|
||||
|
||||
/**
|
||||
* Finds and returns the text contents of the given element.
|
||||
* If a fuzzy locator is used, the element is found using CSS, XPath,
|
||||
* and by matching the full page source by regular expression.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $heading = $I->grabTextFrom('h1');
|
||||
* $heading = $I->grabTextFrom('descendant-or-self::h1');
|
||||
* $value = $I->grabTextFrom('~<input value=(.*?)]~sgi'); // match with a regex
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $cssOrXPathOrRegex
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function grabTextFrom($cssOrXPathOrRegex);
|
||||
|
||||
/**
|
||||
* Finds the value for the given form field.
|
||||
* If a fuzzy locator is used, the field is found by field name, CSS, and XPath.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $name = $I->grabValueFrom('Name');
|
||||
* $name = $I->grabValueFrom('input[name=username]');
|
||||
* $name = $I->grabValueFrom('descendant-or-self::form/descendant::input[@name = 'username']');
|
||||
* $name = $I->grabValueFrom(['name' => 'username']);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $field
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function grabValueFrom($field);
|
||||
|
||||
|
||||
/**
|
||||
* Grabs the value of the given attribute value from the given element.
|
||||
* Fails if element is not found.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->grabAttributeFrom('#tooltip', 'title');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* @param $cssOrXpath
|
||||
* @param $attribute
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function grabAttributeFrom($cssOrXpath, $attribute);
|
||||
|
||||
/**
|
||||
* Grabs either the text content, or attribute values, of nodes
|
||||
* matched by $cssOrXpath and returns them as an array.
|
||||
*
|
||||
* ```html
|
||||
* <a href="#first">First</a>
|
||||
* <a href="#second">Second</a>
|
||||
* <a href="#third">Third</a>
|
||||
* ```
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* // would return ['First', 'Second', 'Third']
|
||||
* $aLinkText = $I->grabMultiple('a');
|
||||
*
|
||||
* // would return ['#first', '#second', '#third']
|
||||
* $aLinks = $I->grabMultiple('a', 'href');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $cssOrXpath
|
||||
* @param $attribute
|
||||
* @return string[]
|
||||
*/
|
||||
public function grabMultiple($cssOrXpath, $attribute = null);
|
||||
|
||||
/**
|
||||
* Checks that the given element exists on the page and is visible.
|
||||
* You can also specify expected attributes of this element.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeElement('.error');
|
||||
* $I->seeElement('//form/input[1]');
|
||||
* $I->seeElement('input', ['name' => 'login']);
|
||||
* $I->seeElement('input', ['value' => '123456']);
|
||||
*
|
||||
* // strict locator in first arg, attributes in second
|
||||
* $I->seeElement(['css' => 'form input'], ['name' => 'login']);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $selector
|
||||
* @param array $attributes
|
||||
* @return
|
||||
*/
|
||||
public function seeElement($selector, $attributes = []);
|
||||
|
||||
/**
|
||||
* Checks that the given element is invisible or not present on the page.
|
||||
* You can also specify expected attributes of this element.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->dontSeeElement('.error');
|
||||
* $I->dontSeeElement('//form/input[1]');
|
||||
* $I->dontSeeElement('input', ['name' => 'login']);
|
||||
* $I->dontSeeElement('input', ['value' => '123456']);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $selector
|
||||
* @param array $attributes
|
||||
*/
|
||||
public function dontSeeElement($selector, $attributes = []);
|
||||
|
||||
/**
|
||||
* Checks that there are a certain number of elements matched by the given locator on the page.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeNumberOfElements('tr', 10);
|
||||
* $I->seeNumberOfElements('tr', [0,10]); // between 0 and 10 elements
|
||||
* ?>
|
||||
* ```
|
||||
* @param $selector
|
||||
* @param mixed $expected int or int[]
|
||||
*/
|
||||
public function seeNumberOfElements($selector, $expected);
|
||||
|
||||
/**
|
||||
* Checks that the given option is selected.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeOptionIsSelected('#form input[name=payment]', 'Visa');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $selector
|
||||
* @param $optionText
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function seeOptionIsSelected($selector, $optionText);
|
||||
|
||||
/**
|
||||
* Checks that the given option is not selected.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->dontSeeOptionIsSelected('#form input[name=payment]', 'Visa');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $selector
|
||||
* @param $optionText
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function dontSeeOptionIsSelected($selector, $optionText);
|
||||
|
||||
/**
|
||||
* Checks that the page title contains the given string.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeInTitle('Blog - Post #1');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $title
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function seeInTitle($title);
|
||||
|
||||
/**
|
||||
* Checks that the page title does not contain the given string.
|
||||
*
|
||||
* @param $title
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function dontSeeInTitle($title);
|
||||
|
||||
/**
|
||||
* Checks that a cookie with the given name is set.
|
||||
* You can set additional cookie params like `domain`, `path` as array passed in last argument.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeCookie('PHPSESSID');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $cookie
|
||||
* @param array $params
|
||||
* @return mixed
|
||||
*/
|
||||
public function seeCookie($cookie, array $params = []);
|
||||
|
||||
/**
|
||||
* Checks that there isn't a cookie with the given name.
|
||||
* You can set additional cookie params like `domain`, `path` as array passed in last argument.
|
||||
*
|
||||
* @param $cookie
|
||||
*
|
||||
* @param array $params
|
||||
* @return mixed
|
||||
*/
|
||||
public function dontSeeCookie($cookie, array $params = []);
|
||||
|
||||
/**
|
||||
* Sets a cookie with the given name and value.
|
||||
* You can set additional cookie params like `domain`, `path`, `expires`, `secure` in array passed as last argument.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->setCookie('PHPSESSID', 'el4ukv0kqbvoirg7nkp4dncpk3');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $name
|
||||
* @param $val
|
||||
* @param array $params
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function setCookie($name, $val, array $params = []);
|
||||
|
||||
/**
|
||||
* Unsets cookie with the given name.
|
||||
* You can set additional cookie params like `domain`, `path` in array passed as last argument.
|
||||
*
|
||||
* @param $cookie
|
||||
*
|
||||
* @param array $params
|
||||
* @return mixed
|
||||
*/
|
||||
public function resetCookie($cookie, array $params = []);
|
||||
|
||||
/**
|
||||
* Grabs a cookie value.
|
||||
* You can set additional cookie params like `domain`, `path` in array passed as last argument.
|
||||
*
|
||||
* @param $cookie
|
||||
*
|
||||
* @param array $params
|
||||
* @return mixed
|
||||
*/
|
||||
public function grabCookie($cookie, array $params = []);
|
||||
|
||||
/**
|
||||
* Grabs current page source code.
|
||||
*
|
||||
* @return string Current page source code.
|
||||
*/
|
||||
public function grabPageSource();
|
||||
}
|
||||
504
vendor/codeception/base/src/Codeception/Lib/ModuleContainer.php
vendored
Normal file
504
vendor/codeception/base/src/Codeception/Lib/ModuleContainer.php
vendored
Normal file
@@ -0,0 +1,504 @@
|
||||
<?php
|
||||
namespace Codeception\Lib;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Exception\ConfigurationException;
|
||||
use Codeception\Exception\ModuleConflictException;
|
||||
use Codeception\Exception\ModuleException;
|
||||
use Codeception\Exception\ModuleRequireException;
|
||||
use Codeception\Lib\Interfaces\ConflictsWithModule;
|
||||
use Codeception\Lib\Interfaces\DependsOnModule;
|
||||
use Codeception\Lib\Interfaces\PartedModule;
|
||||
use Codeception\Util\Annotation;
|
||||
|
||||
/**
|
||||
* Class ModuleContainer
|
||||
* @package Codeception\Lib
|
||||
*/
|
||||
class ModuleContainer
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
const MODULE_NAMESPACE = '\\Codeception\\Module\\';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @var Di
|
||||
*/
|
||||
private $di;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $modules = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $active = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $actions = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Di $di
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(Di $di, $config)
|
||||
{
|
||||
$this->di = $di;
|
||||
$this->di->set($this);
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a module.
|
||||
*
|
||||
* @param string $moduleName
|
||||
* @param bool $active
|
||||
* @return \Codeception\Module
|
||||
* @throws \Codeception\Exception\ConfigurationException
|
||||
* @throws \Codeception\Exception\ModuleException
|
||||
* @throws \Codeception\Exception\ModuleRequireException
|
||||
* @throws \Codeception\Exception\InjectionException
|
||||
*/
|
||||
public function create($moduleName, $active = true)
|
||||
{
|
||||
$this->active[$moduleName] = $active;
|
||||
|
||||
$moduleClass = $this->getModuleClass($moduleName);
|
||||
if (!class_exists($moduleClass)) {
|
||||
throw new ConfigurationException("Module $moduleName could not be found and loaded");
|
||||
}
|
||||
|
||||
$config = $this->getModuleConfig($moduleName);
|
||||
|
||||
if (empty($config) && !$active) {
|
||||
// For modules that are a dependency of other modules we want to skip the validation of the config.
|
||||
// This config validation is performed in \Codeception\Module::__construct().
|
||||
// Explicitly setting $config to null skips this validation.
|
||||
$config = null;
|
||||
}
|
||||
|
||||
$this->modules[$moduleName] = $module = $this->di->instantiate($moduleClass, [$this, $config], false);
|
||||
|
||||
if ($this->moduleHasDependencies($module)) {
|
||||
$this->injectModuleDependencies($moduleName, $module);
|
||||
}
|
||||
|
||||
// If module is not active its actions should not be included in the actor class
|
||||
$actions = $active ? $this->getActionsForModule($module, $config) : [];
|
||||
|
||||
foreach ($actions as $action) {
|
||||
$this->actions[$action] = $moduleName;
|
||||
};
|
||||
|
||||
return $module;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a module have dependencies?
|
||||
*
|
||||
* @param \Codeception\Module $module
|
||||
* @return bool
|
||||
*/
|
||||
private function moduleHasDependencies($module)
|
||||
{
|
||||
if (!$module instanceof DependsOnModule) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $module->_depends();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions of a module.
|
||||
*
|
||||
* @param \Codeception\Module $module
|
||||
* @param array $config
|
||||
* @return array
|
||||
*/
|
||||
private function getActionsForModule($module, $config)
|
||||
{
|
||||
$reflectionClass = new \ReflectionClass($module);
|
||||
|
||||
// Only public methods can be actions
|
||||
$methods = $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC);
|
||||
|
||||
// Should this module be loaded partially?
|
||||
$configuredParts = null;
|
||||
if ($module instanceof PartedModule && isset($config['part'])) {
|
||||
$configuredParts = is_array($config['part']) ? $config['part'] : [$config['part']];
|
||||
}
|
||||
|
||||
$actions = [];
|
||||
foreach ($methods as $method) {
|
||||
if ($this->includeMethodAsAction($module, $method, $configuredParts)) {
|
||||
$actions[] = $method->name;
|
||||
}
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should a method be included as an action?
|
||||
*
|
||||
* @param \Codeception\Module $module
|
||||
* @param \ReflectionMethod $method
|
||||
* @param array|null $configuredParts
|
||||
* @return bool
|
||||
*/
|
||||
private function includeMethodAsAction($module, $method, $configuredParts = null)
|
||||
{
|
||||
// Filter out excluded actions
|
||||
if ($module::$excludeActions && in_array($method->name, $module::$excludeActions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keep only the $onlyActions if they are specified
|
||||
if ($module::$onlyActions && !in_array($method->name, $module::$onlyActions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do not include inherited actions if the static $includeInheritedActions property is set to false.
|
||||
// However, if an inherited action is also specified in the static $onlyActions property
|
||||
// it should be included as an action.
|
||||
if (!$module::$includeInheritedActions &&
|
||||
!in_array($method->name, $module::$onlyActions) &&
|
||||
$method->getDeclaringClass()->getName() != get_class($module)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do not include hidden methods, methods with a name starting with an underscore
|
||||
if (strpos($method->name, '_') === 0) {
|
||||
return false;
|
||||
};
|
||||
|
||||
// If a part is configured for the module, only include actions from that part
|
||||
if ($configuredParts) {
|
||||
$moduleParts = Annotation::forMethod($module, $method->name)->fetchAll('part');
|
||||
if (!array_uintersect($moduleParts, $configuredParts, 'strcasecmp')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the module a helper?
|
||||
*
|
||||
* @param string $moduleName
|
||||
* @return bool
|
||||
*/
|
||||
private function isHelper($moduleName)
|
||||
{
|
||||
return strpos($moduleName, '\\') !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fully qualified class name for a module.
|
||||
*
|
||||
* @param string $moduleName
|
||||
* @return string
|
||||
*/
|
||||
private function getModuleClass($moduleName)
|
||||
{
|
||||
if ($this->isHelper($moduleName)) {
|
||||
return $moduleName;
|
||||
}
|
||||
|
||||
return self::MODULE_NAMESPACE . $moduleName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a module instantiated in this ModuleContainer?
|
||||
*
|
||||
* @param string $moduleName
|
||||
* @return bool
|
||||
*/
|
||||
public function hasModule($moduleName)
|
||||
{
|
||||
return isset($this->modules[$moduleName]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a module from this ModuleContainer.
|
||||
*
|
||||
* @param string $moduleName
|
||||
* @return \Codeception\Module
|
||||
* @throws \Codeception\Exception\ModuleException
|
||||
*/
|
||||
public function getModule($moduleName)
|
||||
{
|
||||
if (!$this->hasModule($moduleName)) {
|
||||
throw new ModuleException(__CLASS__, "Module $moduleName couldn't be connected");
|
||||
}
|
||||
|
||||
return $this->modules[$moduleName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the module for an action.
|
||||
*
|
||||
* @param string $action
|
||||
* @return \Codeception\Module|null This method returns null if there is no module for $action
|
||||
*/
|
||||
public function moduleForAction($action)
|
||||
{
|
||||
if (!isset($this->actions[$action])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->modules[$this->actions[$action]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all actions.
|
||||
*
|
||||
* @return array An array with actions as keys and module names as values.
|
||||
*/
|
||||
public function getActions()
|
||||
{
|
||||
return $this->actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all modules.
|
||||
*
|
||||
* @return array An array with module names as keys and modules as values.
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
return $this->modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock a module in this ModuleContainer.
|
||||
*
|
||||
* @param string $moduleName
|
||||
* @param object $mock
|
||||
*/
|
||||
public function mock($moduleName, $mock)
|
||||
{
|
||||
$this->modules[$moduleName] = $mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject the dependencies of a module.
|
||||
*
|
||||
* @param string $moduleName
|
||||
* @param \Codeception\Lib\Interfaces\DependsOnModule $module
|
||||
* @throws \Codeception\Exception\ModuleException
|
||||
* @throws \Codeception\Exception\ModuleRequireException
|
||||
*/
|
||||
private function injectModuleDependencies($moduleName, DependsOnModule $module)
|
||||
{
|
||||
$this->checkForMissingDependencies($moduleName, $module);
|
||||
|
||||
if (!method_exists($module, '_inject')) {
|
||||
throw new ModuleException($module, 'Module requires method _inject to be defined to accept dependencies');
|
||||
}
|
||||
|
||||
$dependencies = array_map(function ($dependency) {
|
||||
return $this->create($dependency, false);
|
||||
}, $this->getConfiguredDependencies($moduleName));
|
||||
|
||||
call_user_func_array([$module, '_inject'], $dependencies);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for missing dependencies.
|
||||
*
|
||||
* @param string $moduleName
|
||||
* @param \Codeception\Lib\Interfaces\DependsOnModule $module
|
||||
* @throws \Codeception\Exception\ModuleException
|
||||
* @throws \Codeception\Exception\ModuleRequireException
|
||||
*/
|
||||
private function checkForMissingDependencies($moduleName, DependsOnModule $module)
|
||||
{
|
||||
$dependencies = $this->getModuleDependencies($module);
|
||||
$configuredDependenciesCount = count($this->getConfiguredDependencies($moduleName));
|
||||
|
||||
if ($configuredDependenciesCount < count($dependencies)) {
|
||||
$missingDependency = array_keys($dependencies)[$configuredDependenciesCount];
|
||||
|
||||
$message = sprintf(
|
||||
"\nThis module depends on %s\n\n\n%s",
|
||||
$missingDependency,
|
||||
$this->getErrorMessageForDependency($module, $missingDependency)
|
||||
);
|
||||
|
||||
throw new ModuleRequireException($moduleName, $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dependencies of a module.
|
||||
*
|
||||
* @param \Codeception\Lib\Interfaces\DependsOnModule $module
|
||||
* @return array
|
||||
* @throws \Codeception\Exception\ModuleException
|
||||
*/
|
||||
private function getModuleDependencies(DependsOnModule $module)
|
||||
{
|
||||
$depends = $module->_depends();
|
||||
|
||||
if (!$depends) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!is_array($depends)) {
|
||||
$message = sprintf("Method _depends of module '%s' must return an array", get_class($module));
|
||||
throw new ModuleException($module, $message);
|
||||
}
|
||||
|
||||
return $depends;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured dependencies for a module.
|
||||
*
|
||||
* @param string $moduleName
|
||||
* @return array
|
||||
*/
|
||||
private function getConfiguredDependencies($moduleName)
|
||||
{
|
||||
$config = $this->getModuleConfig($moduleName);
|
||||
|
||||
if (!isset($config['depends'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return is_array($config['depends']) ? $config['depends'] : [$config['depends']];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error message for a module dependency that is missing.
|
||||
*
|
||||
* @param \Codeception\Module $module
|
||||
* @param string $missingDependency
|
||||
* @return string
|
||||
*/
|
||||
private function getErrorMessageForDependency($module, $missingDependency)
|
||||
{
|
||||
$depends = $module->_depends();
|
||||
|
||||
return $depends[$missingDependency];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration for a module.
|
||||
*
|
||||
* A module with name $moduleName can be configured at two paths in a configuration file:
|
||||
* - modules.config.$moduleName
|
||||
* - modules.enabled.$moduleName
|
||||
*
|
||||
* This method checks both locations for configuration. If there is configuration at both locations
|
||||
* this method merges them, where the configuration at modules.enabled.$moduleName takes precedence
|
||||
* over modules.config.$moduleName if the same parameters are configured at both locations.
|
||||
*
|
||||
* @param string $moduleName
|
||||
* @return array
|
||||
*/
|
||||
private function getModuleConfig($moduleName)
|
||||
{
|
||||
$config = isset($this->config['modules']['config'][$moduleName])
|
||||
? $this->config['modules']['config'][$moduleName]
|
||||
: [];
|
||||
|
||||
if (!isset($this->config['modules']['enabled'])) {
|
||||
return $config;
|
||||
}
|
||||
|
||||
if (!is_array($this->config['modules']['enabled'])) {
|
||||
return $config;
|
||||
}
|
||||
|
||||
foreach ($this->config['modules']['enabled'] as $enabledModuleConfig) {
|
||||
if (!is_array($enabledModuleConfig)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$enabledModuleName = key($enabledModuleConfig);
|
||||
if ($enabledModuleName === $moduleName) {
|
||||
return Configuration::mergeConfigs(reset($enabledModuleConfig), $config);
|
||||
}
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are conflicting modules in this ModuleContainer.
|
||||
*
|
||||
* @throws \Codeception\Exception\ModuleConflictException
|
||||
*/
|
||||
public function validateConflicts()
|
||||
{
|
||||
$canConflict = [];
|
||||
foreach ($this->modules as $moduleName => $module) {
|
||||
$parted = $module instanceof PartedModule && $module->_getConfig('part');
|
||||
|
||||
if ($this->active[$moduleName] && !$parted) {
|
||||
$canConflict[] = $module;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($canConflict as $module) {
|
||||
foreach ($canConflict as $otherModule) {
|
||||
$this->validateConflict($module, $otherModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the modules passed as arguments to this method conflict with each other.
|
||||
*
|
||||
* @param \Codeception\Module $module
|
||||
* @param \Codeception\Module $otherModule
|
||||
* @throws \Codeception\Exception\ModuleConflictException
|
||||
*/
|
||||
private function validateConflict($module, $otherModule)
|
||||
{
|
||||
if ($module === $otherModule || !$module instanceof ConflictsWithModule) {
|
||||
return;
|
||||
}
|
||||
|
||||
$conflicts = $this->normalizeConflictSpecification($module->_conflicts());
|
||||
if ($otherModule instanceof $conflicts) {
|
||||
throw new ModuleConflictException($module, $otherModule);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the return value of ConflictsWithModule::_conflicts() to a class name.
|
||||
* This is necessary because it can return a module name instead of the name of a class or interface.
|
||||
*
|
||||
* @param string $conflicts
|
||||
* @return string
|
||||
*/
|
||||
private function normalizeConflictSpecification($conflicts)
|
||||
{
|
||||
if (interface_exists($conflicts) || class_exists($conflicts)) {
|
||||
return $conflicts;
|
||||
}
|
||||
|
||||
if ($this->hasModule($conflicts)) {
|
||||
return $this->getModule($conflicts);
|
||||
}
|
||||
|
||||
return $conflicts;
|
||||
}
|
||||
}
|
||||
32
vendor/codeception/base/src/Codeception/Lib/Notification.php
vendored
Normal file
32
vendor/codeception/base/src/Codeception/Lib/Notification.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace Codeception\Lib;
|
||||
|
||||
class Notification
|
||||
{
|
||||
protected static $messages = [];
|
||||
|
||||
public static function warning($message, $location)
|
||||
{
|
||||
self::$messages[] = 'WARNING: ' . self::formatMessage($message, $location);
|
||||
}
|
||||
|
||||
public static function deprecate($message, $location = '')
|
||||
{
|
||||
self::$messages[] = 'DEPRECATION: ' . self::formatMessage($message, $location);
|
||||
}
|
||||
|
||||
private static function formatMessage($message, $location = '')
|
||||
{
|
||||
if ($location) {
|
||||
return "<bold>$message</bold> <info>$location</info>";
|
||||
}
|
||||
return $message;
|
||||
}
|
||||
|
||||
public static function all()
|
||||
{
|
||||
$messages = self::$messages;
|
||||
self::$messages = [];
|
||||
return $messages;
|
||||
}
|
||||
}
|
||||
99
vendor/codeception/base/src/Codeception/Lib/ParamsLoader.php
vendored
Normal file
99
vendor/codeception/base/src/Codeception/Lib/ParamsLoader.php
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
namespace Codeception\Lib;
|
||||
|
||||
use Codeception\Exception\ConfigurationException;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class ParamsLoader
|
||||
{
|
||||
protected $paramStorage;
|
||||
protected $paramsFile;
|
||||
|
||||
public function load($paramStorage)
|
||||
{
|
||||
$this->paramsFile = null;
|
||||
$this->paramStorage = $paramStorage;
|
||||
|
||||
if (is_array($paramStorage)) {
|
||||
return $this->loadArray();
|
||||
}
|
||||
|
||||
if ($paramStorage === 'env' || $paramStorage === 'environment') {
|
||||
return $this->loadEnvironmentVars();
|
||||
}
|
||||
|
||||
$this->paramsFile = codecept_absolute_path($paramStorage);
|
||||
if (!file_exists($this->paramsFile)) {
|
||||
throw new ConfigurationException("Params file {$this->paramsFile} not found");
|
||||
}
|
||||
|
||||
try {
|
||||
if (preg_match('~\.yml$~', $paramStorage)) {
|
||||
return $this->loadYamlFile();
|
||||
}
|
||||
|
||||
if (preg_match('~\.ini$~', $paramStorage)) {
|
||||
return $this->loadIniFile();
|
||||
}
|
||||
|
||||
if (preg_match('~\.php$~', $paramStorage)) {
|
||||
return $this->loadPhpFile();
|
||||
}
|
||||
|
||||
if (preg_match('~(\.env(\.|$))~', $paramStorage)) {
|
||||
return $this->loadDotEnvFile();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw new ConfigurationException("Failed loading params from $paramStorage\n" . $e->getMessage());
|
||||
}
|
||||
|
||||
throw new ConfigurationException("Params can't be loaded from `$paramStorage`.");
|
||||
}
|
||||
|
||||
public function loadArray()
|
||||
{
|
||||
return $this->paramStorage;
|
||||
}
|
||||
|
||||
protected function loadIniFile()
|
||||
{
|
||||
return parse_ini_file($this->paramsFile);
|
||||
}
|
||||
|
||||
protected function loadPhpFile()
|
||||
{
|
||||
return require $this->paramsFile;
|
||||
}
|
||||
|
||||
protected function loadYamlFile()
|
||||
{
|
||||
$params = Yaml::parse(file_get_contents($this->paramsFile));
|
||||
if (isset($params['parameters'])) { // Symfony style
|
||||
$params = $params['parameters'];
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
|
||||
protected function loadDotEnvFile()
|
||||
{
|
||||
if (class_exists('Dotenv\Dotenv')) {
|
||||
$dotEnv = new \Dotenv\Dotenv(codecept_root_dir(), $this->paramStorage);
|
||||
$dotEnv->load();
|
||||
return $_SERVER;
|
||||
} elseif (class_exists('Symfony\Component\Dotenv\Dotenv')) {
|
||||
$dotEnv = new \Symfony\Component\Dotenv\Dotenv();
|
||||
$dotEnv->load(codecept_root_dir($this->paramStorage));
|
||||
return $_SERVER;
|
||||
}
|
||||
|
||||
throw new ConfigurationException(
|
||||
"`vlucas/phpdotenv` library is required to parse .env files.\n" .
|
||||
"Please install it via composer: composer require vlucas/phpdotenv"
|
||||
);
|
||||
}
|
||||
|
||||
protected function loadEnvironmentVars()
|
||||
{
|
||||
return $_SERVER;
|
||||
}
|
||||
}
|
||||
212
vendor/codeception/base/src/Codeception/Lib/Parser.php
vendored
Normal file
212
vendor/codeception/base/src/Codeception/Lib/Parser.php
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
namespace Codeception\Lib;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Exception\TestParseException;
|
||||
use Codeception\Scenario;
|
||||
use Codeception\Step;
|
||||
use Codeception\Test\Metadata;
|
||||
|
||||
class Parser
|
||||
{
|
||||
/**
|
||||
* @var Scenario
|
||||
*/
|
||||
protected $scenario;
|
||||
/**
|
||||
* @var Metadata
|
||||
*/
|
||||
protected $metadata;
|
||||
protected $code;
|
||||
|
||||
public function __construct(Scenario $scenario, Metadata $metadata)
|
||||
{
|
||||
$this->scenario = $scenario;
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
|
||||
public function prepareToRun($code)
|
||||
{
|
||||
$this->parseFeature($code);
|
||||
$this->parseScenarioOptions($code);
|
||||
}
|
||||
|
||||
public function parseFeature($code)
|
||||
{
|
||||
$matches = [];
|
||||
$code = $this->stripComments($code);
|
||||
$res = preg_match("~\\\$I->wantTo\\(\s*?['\"](.*?)['\"]\s*?\\);~", $code, $matches);
|
||||
if ($res) {
|
||||
$this->scenario->setFeature($matches[1]);
|
||||
return;
|
||||
}
|
||||
$res = preg_match("~\\\$I->wantToTest\\(['\"](.*?)['\"]\\);~", $code, $matches);
|
||||
if ($res) {
|
||||
$this->scenario->setFeature("test " . $matches[1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public function parseScenarioOptions($code)
|
||||
{
|
||||
$this->metadata->setParamsFromAnnotations($this->matchComments($code));
|
||||
}
|
||||
|
||||
public function parseSteps($code)
|
||||
{
|
||||
// parse per line
|
||||
$friends = [];
|
||||
$lines = explode("\n", $code);
|
||||
$isFriend = false;
|
||||
foreach ($lines as $line) {
|
||||
// friends
|
||||
if (preg_match("~\\\$I->haveFriend\((.*?)\);~", $line, $matches)) {
|
||||
$friends[] = trim($matches[1], '\'"');
|
||||
}
|
||||
// friend's section start
|
||||
if (preg_match("~\\\$(.*?)->does\(~", $line, $matches)) {
|
||||
$friend = $matches[1];
|
||||
if (!in_array($friend, $friends)) {
|
||||
continue;
|
||||
}
|
||||
$isFriend = true;
|
||||
$this->addCommentStep("\n----- $friend does -----");
|
||||
continue;
|
||||
}
|
||||
|
||||
// actions
|
||||
if (preg_match("~\\\$I->(.*)\((.*?)\);~", $line, $matches)) {
|
||||
$this->addStep($matches);
|
||||
}
|
||||
|
||||
// friend's section ends
|
||||
if ($isFriend && strpos($line, '}') !== false) {
|
||||
$this->addCommentStep("-------- back to me\n");
|
||||
$isFriend = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function addStep($matches)
|
||||
{
|
||||
list($m, $action, $params) = $matches;
|
||||
if (in_array($action, ['wantTo', 'wantToTest'])) {
|
||||
return;
|
||||
}
|
||||
$this->scenario->addStep(new Step\Action($action, explode(',', $params)));
|
||||
}
|
||||
|
||||
protected function addCommentStep($comment)
|
||||
{
|
||||
$this->scenario->addStep(new \Codeception\Step\Comment($comment, []));
|
||||
}
|
||||
|
||||
public static function validate($file)
|
||||
{
|
||||
$config = Configuration::config();
|
||||
if (empty($config['settings']['lint'])) { // lint disabled in config
|
||||
return;
|
||||
}
|
||||
if (!function_exists('exec')) {
|
||||
//exec function is disabled #3324
|
||||
return;
|
||||
}
|
||||
exec("php -l " . escapeshellarg($file) . " 2>&1", $output, $code);
|
||||
if ($code !== 0) {
|
||||
throw new TestParseException($file, implode("\n", $output));
|
||||
}
|
||||
}
|
||||
|
||||
public static function load($file)
|
||||
{
|
||||
if (PHP_MAJOR_VERSION < 7) {
|
||||
self::validate($file);
|
||||
}
|
||||
try {
|
||||
self::includeFile($file);
|
||||
} catch (\ParseError $e) {
|
||||
throw new TestParseException($file, $e->getMessage(), $e->getLine());
|
||||
} catch (\Exception $e) {
|
||||
// file is valid otherwise
|
||||
}
|
||||
}
|
||||
|
||||
public static function getClassesFromFile($file)
|
||||
{
|
||||
$sourceCode = file_get_contents($file);
|
||||
$classes = [];
|
||||
$tokens = token_get_all($sourceCode);
|
||||
$tokenCount = count($tokens);
|
||||
$namespace = '';
|
||||
|
||||
for ($i = 0; $i < $tokenCount; $i++) {
|
||||
if ($tokens[$i][0] === T_NAMESPACE) {
|
||||
$namespace = '';
|
||||
for ($j = $i + 1; $j < $tokenCount; $j++) {
|
||||
if ($tokens[$j][0] === T_STRING) {
|
||||
$namespace .= $tokens[$j][1] . '\\';
|
||||
} else {
|
||||
if ($tokens[$j] === '{' || $tokens[$j] === ';') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($tokens[$i][0] === T_CLASS) {
|
||||
if (!isset($tokens[$i - 2])) {
|
||||
$classes[] = $namespace . $tokens[$i + 2][1];
|
||||
continue;
|
||||
}
|
||||
if ($tokens[$i - 2][0] === T_NEW) {
|
||||
continue;
|
||||
}
|
||||
if ($tokens[$i - 1][0] === T_WHITESPACE and $tokens[$i - 2][0] === T_DOUBLE_COLON) {
|
||||
continue;
|
||||
}
|
||||
if ($tokens[$i - 1][0] === T_DOUBLE_COLON) {
|
||||
continue;
|
||||
}
|
||||
$classes[] = $namespace . $tokens[$i + 2][1];
|
||||
}
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Include in different scope to prevent included file from affecting $file variable
|
||||
*/
|
||||
private static function includeFile($file)
|
||||
{
|
||||
include_once $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $code
|
||||
* @return mixed
|
||||
*/
|
||||
protected function stripComments($code)
|
||||
{
|
||||
$code = preg_replace('~\/\/.*?$~m', '', $code); // remove inline comments
|
||||
$code = preg_replace('~\/*\*.*?\*\/~ms', '', $code);
|
||||
return $code; // remove block comment
|
||||
}
|
||||
|
||||
protected function matchComments($code)
|
||||
{
|
||||
$matches = [];
|
||||
$comments = '';
|
||||
$hasLineComment = preg_match_all('~\/\/(.*?)$~m', $code, $matches);
|
||||
if ($hasLineComment) {
|
||||
foreach ($matches[1] as $line) {
|
||||
$comments .= $line."\n";
|
||||
}
|
||||
}
|
||||
$hasBlockComment = preg_match('~\/*\*(.*?)\*\/~ms', $code, $matches);
|
||||
if ($hasBlockComment) {
|
||||
$comments .= $matches[1]."\n";
|
||||
}
|
||||
return $comments;
|
||||
}
|
||||
}
|
||||
3
vendor/codeception/base/src/Codeception/Lib/README.md
vendored
Normal file
3
vendor/codeception/base/src/Codeception/Lib/README.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Internal Libraries
|
||||
|
||||
Various classes that Codeception core and modules are relying on.
|
||||
122
vendor/codeception/base/src/Codeception/Lib/Shared/LaravelCommon.php
vendored
Normal file
122
vendor/codeception/base/src/Codeception/Lib/Shared/LaravelCommon.php
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
namespace Codeception\Lib\Shared;
|
||||
|
||||
/**
|
||||
* Common functions for Laravel family
|
||||
*
|
||||
* @package Codeception\Lib\Shared
|
||||
*/
|
||||
trait LaravelCommon
|
||||
{
|
||||
/**
|
||||
* Add a binding to the Laravel service container.
|
||||
* (https://laravel.com/docs/master/container)
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->haveBinding('My\Interface', 'My\Implementation');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $abstract
|
||||
* @param $concrete
|
||||
*/
|
||||
public function haveBinding($abstract, $concrete)
|
||||
{
|
||||
$this->client->haveBinding($abstract, $concrete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a singleton binding to the Laravel service container.
|
||||
* (https://laravel.com/docs/master/container)
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->haveSingleton('My\Interface', 'My\Singleton');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $abstract
|
||||
* @param $concrete
|
||||
*/
|
||||
public function haveSingleton($abstract, $concrete)
|
||||
{
|
||||
$this->client->haveBinding($abstract, $concrete, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a contextual binding to the Laravel service container.
|
||||
* (https://laravel.com/docs/master/container)
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->haveContextualBinding('My\Class', '$variable', 'value');
|
||||
*
|
||||
* // This is similar to the following in your Laravel application
|
||||
* $app->when('My\Class')
|
||||
* ->needs('$variable')
|
||||
* ->give('value');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $concrete
|
||||
* @param $abstract
|
||||
* @param $implementation
|
||||
*/
|
||||
public function haveContextualBinding($concrete, $abstract, $implementation)
|
||||
{
|
||||
$this->client->haveContextualBinding($concrete, $abstract, $implementation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an instance binding to the Laravel service container.
|
||||
* (https://laravel.com/docs/master/container)
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->haveInstance('My\Class', new My\Class());
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $abstract
|
||||
* @param $instance
|
||||
*/
|
||||
public function haveInstance($abstract, $instance)
|
||||
{
|
||||
$this->client->haveInstance($abstract, $instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a handler than can be used to modify the Laravel application object after it is initialized.
|
||||
* The Laravel application object will be passed as an argument to the handler.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->haveApplicationHandler(function($app) {
|
||||
* $app->make('config')->set(['test_value' => '10']);
|
||||
* });
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $handler
|
||||
*/
|
||||
public function haveApplicationHandler($handler)
|
||||
{
|
||||
$this->client->haveApplicationHandler($handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the registered application handlers.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->clearApplicationHandlers();
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
public function clearApplicationHandlers()
|
||||
{
|
||||
$this->client->clearApplicationHandlers();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user