init
This commit is contained in:
125
vendor/codeception/base/src/Codeception/Util/ActionSequence.php
vendored
Normal file
125
vendor/codeception/base/src/Codeception/Util/ActionSequence.php
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
use Codeception\Step\Action;
|
||||
|
||||
/**
|
||||
* Class for defining an array actions to be executed inside `performOn` of WebDriver
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* (new ActionSequence)->click('do')->click('undo');
|
||||
* ActionSequence::build()->click('do')->click('undo');
|
||||
* ```
|
||||
*
|
||||
* @method $this see([optional])
|
||||
* @method $this dontSee([optional])
|
||||
* @method $this seeElement([optional])
|
||||
* @method $this dontSeeElement([optional])
|
||||
* @method $this click([optional])
|
||||
* @method $this wait([optional])
|
||||
* @method $this waitForElementChange([optional])
|
||||
* @method $this waitForElement([optional])
|
||||
* @method $this waitForElementVisible([optional])
|
||||
* @method $this waitForElementNotVisible([optional])
|
||||
* @method $this waitForText([optional])
|
||||
* @method $this submitForm([optional])
|
||||
* @method $this seeLink([optional])
|
||||
* @method $this dontSeeLink([optional])
|
||||
* @method $this seeCheckboxIsChecked([optional])
|
||||
* @method $this dontSeeCheckboxIsChecked([optional])
|
||||
* @method $this seeInField([optional])
|
||||
* @method $this dontSeeInField([optional])
|
||||
* @method $this seeInFormFields([optional])
|
||||
* @method $this dontSeeInFormFields([optional])
|
||||
* @method $this selectOption([optional])
|
||||
* @method $this checkOption([optional])
|
||||
* @method $this uncheckOption([optional])
|
||||
* @method $this fillField([optional])
|
||||
* @method $this attachFile([optional])
|
||||
* @method $this seeNumberOfElements([optional])
|
||||
* @method $this seeOptionIsSelected([optional])
|
||||
* @method $this dontSeeOptionIsSelected([optional])
|
||||
*/
|
||||
class ActionSequence
|
||||
{
|
||||
protected $actions = [];
|
||||
|
||||
/**
|
||||
* Creates an instance
|
||||
* @return ActionSequence
|
||||
*/
|
||||
public static function build()
|
||||
{
|
||||
return new self;
|
||||
}
|
||||
|
||||
public function __call($action, $arguments)
|
||||
{
|
||||
$this->addAction($action, $arguments);
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function addAction($action, $arguments)
|
||||
{
|
||||
if (!is_array($arguments)) {
|
||||
$arguments = [$arguments];
|
||||
}
|
||||
$this->actions[] = new Action($action, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates action sequence from associative array,
|
||||
* where key is action, and value is action arguments
|
||||
*
|
||||
* @param array $actions
|
||||
* @return $this
|
||||
*/
|
||||
public function fromArray(array $actions)
|
||||
{
|
||||
foreach ($actions as $action => $arguments) {
|
||||
$this->addAction($action, $arguments);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of logged actions as associative array
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes sequence of action as methods of passed object.
|
||||
*
|
||||
* @param $context
|
||||
*/
|
||||
public function run($context)
|
||||
{
|
||||
foreach ($this->actions as $step) {
|
||||
/** @var $step Action **/
|
||||
codecept_debug("- $step");
|
||||
try {
|
||||
call_user_func_array([$context, $step->getAction()], $step->getArguments());
|
||||
} catch (\Exception $e) {
|
||||
$class = get_class($e); // rethrow exception for a specific action
|
||||
throw new $class($e->getMessage() . "\nat $step");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
$actionsLog = [];
|
||||
|
||||
foreach ($this->actions as $step) {
|
||||
$args = str_replace('"', "'", $step->getArgumentsAsString(20));
|
||||
$actionsLog[] = $step->getAction() . ": $args";
|
||||
}
|
||||
|
||||
return implode(', ', $actionsLog);
|
||||
}
|
||||
}
|
||||
175
vendor/codeception/base/src/Codeception/Util/Annotation.php
vendored
Normal file
175
vendor/codeception/base/src/Codeception/Util/Annotation.php
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
/**
|
||||
* Simple annotation parser. Take only key-value annotations for methods or class.
|
||||
*/
|
||||
class Annotation
|
||||
{
|
||||
protected static $reflectedClasses = [];
|
||||
protected static $regex = '/@%s(?:[ \t]*(.*?))?[ \t]*\r?$/m';
|
||||
protected static $lastReflected = null;
|
||||
|
||||
/**
|
||||
* @var \ReflectionClass
|
||||
*/
|
||||
protected $reflectedClass;
|
||||
|
||||
protected $currentReflectedItem;
|
||||
|
||||
/**
|
||||
* Grabs annotation values.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* Annotation::forClass('MyTestCase')->fetch('guy');
|
||||
* Annotation::forClass('MyTestCase')->method('testData')->fetch('depends');
|
||||
* Annotation::forClass('MyTestCase')->method('testData')->fetchAll('depends');
|
||||
*
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $class
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public static function forClass($class)
|
||||
{
|
||||
if (is_object($class)) {
|
||||
$class = get_class($class);
|
||||
}
|
||||
|
||||
if (!isset(static::$reflectedClasses[$class])) {
|
||||
static::$reflectedClasses[$class] = new \ReflectionClass($class);
|
||||
}
|
||||
|
||||
return new static(static::$reflectedClasses[$class]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $method
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public static function forMethod($class, $method)
|
||||
{
|
||||
return self::forClass($class)->method($method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses raw comment for annotations
|
||||
*
|
||||
* @param $docblock
|
||||
* @param $annotation
|
||||
* @return array
|
||||
*/
|
||||
public static function fetchAnnotationsFromDocblock($annotation, $docblock)
|
||||
{
|
||||
if (preg_match_all(sprintf(self::$regex, $annotation), $docblock, $matched)) {
|
||||
return $matched[1];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all available annotations
|
||||
*
|
||||
* @param $docblock
|
||||
* @return array
|
||||
*/
|
||||
public static function fetchAllAnnotationsFromDocblock($docblock)
|
||||
{
|
||||
$annotations = [];
|
||||
if (!preg_match_all(sprintf(self::$regex, '(\w+)'), $docblock, $matched)) {
|
||||
return $annotations;
|
||||
}
|
||||
foreach ($matched[1] as $k => $annotation) {
|
||||
if (!isset($annotations[$annotation])) {
|
||||
$annotations[$annotation] = [];
|
||||
}
|
||||
$annotations[$annotation][] = $matched[2][$k];
|
||||
};
|
||||
return $annotations;
|
||||
}
|
||||
|
||||
|
||||
public function __construct(\ReflectionClass $class)
|
||||
{
|
||||
$this->currentReflectedItem = $this->reflectedClass = $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $method
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function method($method)
|
||||
{
|
||||
$this->currentReflectedItem = $this->reflectedClass->getMethod($method);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $annotation
|
||||
* @return null
|
||||
*/
|
||||
public function fetch($annotation)
|
||||
{
|
||||
$docBlock = $this->currentReflectedItem->getDocComment();
|
||||
if (preg_match(sprintf(self::$regex, $annotation), $docBlock, $matched)) {
|
||||
return $matched[1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $annotation
|
||||
* @return array
|
||||
*/
|
||||
public function fetchAll($annotation)
|
||||
{
|
||||
$docBlock = $this->currentReflectedItem->getDocComment();
|
||||
if (preg_match_all(sprintf(self::$regex, $annotation), $docBlock, $matched)) {
|
||||
return $matched[1];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
public function raw()
|
||||
{
|
||||
return $this->currentReflectedItem->getDocComment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an associative array value of annotation
|
||||
* Either JSON or Doctrine-annotation style allowed
|
||||
* Returns null if not a valid array data
|
||||
*
|
||||
* @param $annotation
|
||||
* @return array|mixed|string
|
||||
*/
|
||||
public static function arrayValue($annotation)
|
||||
{
|
||||
$annotation = trim($annotation);
|
||||
$openingBrace = substr($annotation, 0, 1);
|
||||
|
||||
// json-style data format
|
||||
if (in_array($openingBrace, ['{', '['])) {
|
||||
return json_decode($annotation, true);
|
||||
}
|
||||
|
||||
// doctrine-style data format
|
||||
if ($openingBrace === '(') {
|
||||
preg_match_all('~(\w+)\s*?=\s*?"(.*?)"\s*?[,)]~', $annotation, $matches, PREG_SET_ORDER);
|
||||
$data = [];
|
||||
foreach ($matches as $item) {
|
||||
$data[$item[1]] = $item[2];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
148
vendor/codeception/base/src/Codeception/Util/ArrayContainsComparator.php
vendored
Normal file
148
vendor/codeception/base/src/Codeception/Util/ArrayContainsComparator.php
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
class ArrayContainsComparator
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $haystack = [];
|
||||
|
||||
public function __construct($haystack)
|
||||
{
|
||||
$this->haystack = $haystack;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getHaystack()
|
||||
{
|
||||
return $this->haystack;
|
||||
}
|
||||
|
||||
public function containsArray(array $needle)
|
||||
{
|
||||
return $needle == $this->arrayIntersectRecursive($needle, $this->haystack);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author nleippe@integr8ted.com
|
||||
* @author tiger.seo@gmail.com
|
||||
* @link http://www.php.net/manual/en/function.array-intersect-assoc.php#39822
|
||||
*
|
||||
* @param mixed $arr1
|
||||
* @param mixed $arr2
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
private function arrayIntersectRecursive($arr1, $arr2)
|
||||
{
|
||||
if (!is_array($arr1) || !is_array($arr2)) {
|
||||
return false;
|
||||
}
|
||||
// if it is not an associative array we do not compare keys
|
||||
if ($this->arrayIsSequential($arr1) && $this->arrayIsSequential($arr2)) {
|
||||
return $this->sequentialArrayIntersect($arr1, $arr2);
|
||||
}
|
||||
return $this->associativeArrayIntersect($arr1, $arr2);
|
||||
}
|
||||
|
||||
/**
|
||||
* This array has sequential keys?
|
||||
*
|
||||
* @param array $array
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function arrayIsSequential(array $array)
|
||||
{
|
||||
return array_keys($array) === range(0, count($array) - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arr1
|
||||
* @param array $arr2
|
||||
* @return array
|
||||
*/
|
||||
private function sequentialArrayIntersect(array $arr1, array $arr2)
|
||||
{
|
||||
$ret = [];
|
||||
|
||||
// Do not match the same item of $arr2 against multiple items of $arr1
|
||||
$matchedKeys = [];
|
||||
foreach ($arr1 as $key1 => $value1) {
|
||||
foreach ($arr2 as $key2 => $value2) {
|
||||
if (isset($matchedKeys[$key2])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$return = $this->arrayIntersectRecursive($value1, $value2);
|
||||
if ($return !== false && $return == $value1) {
|
||||
$ret[$key1] = $return;
|
||||
$matchedKeys[$key2] = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ($this->isEqualValue($value1, $value2)) {
|
||||
$ret[$key1] = $value1;
|
||||
$matchedKeys[$key2] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arr1
|
||||
* @param array $arr2
|
||||
*
|
||||
* @return array|bool|null
|
||||
*/
|
||||
private function associativeArrayIntersect(array $arr1, array $arr2)
|
||||
{
|
||||
$commonKeys = array_intersect(array_keys($arr1), array_keys($arr2));
|
||||
|
||||
$ret = [];
|
||||
foreach ($commonKeys as $key) {
|
||||
$return = $this->arrayIntersectRecursive($arr1[$key], $arr2[$key]);
|
||||
if ($return) {
|
||||
$ret[$key] = $return;
|
||||
continue;
|
||||
}
|
||||
if ($this->isEqualValue($arr1[$key], $arr2[$key])) {
|
||||
$ret[$key] = $arr1[$key];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($commonKeys)) {
|
||||
foreach ($arr2 as $arr) {
|
||||
$return = $this->arrayIntersectRecursive($arr1, $arr);
|
||||
if ($return && $return == $arr1) {
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($ret) < min(count($arr1), count($arr2))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
private function isEqualValue($val1, $val2)
|
||||
{
|
||||
if (is_numeric($val1)) {
|
||||
$val1 = (string) $val1;
|
||||
}
|
||||
|
||||
if (is_numeric($val2)) {
|
||||
$val2 = (string) $val2;
|
||||
}
|
||||
|
||||
return $val1 === $val2;
|
||||
}
|
||||
}
|
||||
164
vendor/codeception/base/src/Codeception/Util/Autoload.php
vendored
Normal file
164
vendor/codeception/base/src/Codeception/Util/Autoload.php
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
/**
|
||||
* Autoloader, which is fully compatible with PSR-4,
|
||||
* and can be used to autoload your `Helper`, `Page`, and `Step` classes.
|
||||
*/
|
||||
class Autoload
|
||||
{
|
||||
protected static $registered = false;
|
||||
/**
|
||||
* An associative array where the key is a namespace prefix and the value
|
||||
* is an array of base directories for classes in that namespace.
|
||||
* @var array
|
||||
*/
|
||||
protected static $map = [];
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a base directory for a namespace prefix.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* // app\Codeception\UserHelper will be loaded from '/path/to/helpers/UserHelper.php'
|
||||
* Autoload::addNamespace('app\Codeception', '/path/to/helpers');
|
||||
*
|
||||
* // LoginPage will be loaded from '/path/to/pageobjects/LoginPage.php'
|
||||
* Autoload::addNamespace('', '/path/to/pageobjects');
|
||||
*
|
||||
* Autoload::addNamespace('app\Codeception', '/path/to/controllers');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $prefix The namespace prefix.
|
||||
* @param string $base_dir A base directory for class files in the namespace.
|
||||
* @param bool $prepend If true, prepend the base directory to the stack instead of appending it;
|
||||
* this causes it to be searched first rather than last.
|
||||
* @return void
|
||||
*/
|
||||
public static function addNamespace($prefix, $base_dir, $prepend = false)
|
||||
{
|
||||
if (!self::$registered) {
|
||||
spl_autoload_register([__CLASS__, 'load']);
|
||||
self::$registered = true;
|
||||
}
|
||||
|
||||
// normalize namespace prefix
|
||||
$prefix = trim($prefix, '\\') . '\\';
|
||||
|
||||
// normalize the base directory with a trailing separator
|
||||
$base_dir = rtrim($base_dir, '/') . DIRECTORY_SEPARATOR;
|
||||
$base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . '/';
|
||||
|
||||
// initialize the namespace prefix array
|
||||
if (isset(self::$map[$prefix]) === false) {
|
||||
self::$map[$prefix] = [];
|
||||
}
|
||||
|
||||
// retain the base directory for the namespace prefix
|
||||
if ($prepend) {
|
||||
array_unshift(self::$map[$prefix], $base_dir);
|
||||
} else {
|
||||
array_push(self::$map[$prefix], $base_dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use self::addNamespace() instead.
|
||||
*/
|
||||
public static function register($namespace, $suffix, $path)
|
||||
{
|
||||
self::addNamespace($namespace, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use self::addNamespace() instead.
|
||||
*/
|
||||
public static function registerSuffix($suffix, $path)
|
||||
{
|
||||
self::addNamespace('', $path);
|
||||
}
|
||||
|
||||
public static function load($class)
|
||||
{
|
||||
// the current namespace prefix
|
||||
$prefix = $class;
|
||||
|
||||
// work backwards through the namespace names of the fully-qualified class name to find a mapped file name
|
||||
while (false !== ($pos = strrpos($prefix, '\\'))) {
|
||||
// retain the trailing namespace separator in the prefix
|
||||
$prefix = substr($class, 0, $pos + 1);
|
||||
|
||||
// the rest is the relative class name
|
||||
$relative_class = substr($class, $pos + 1);
|
||||
|
||||
// try to load a mapped file for the prefix and relative class
|
||||
$mapped_file = self::loadMappedFile($prefix, $relative_class);
|
||||
if ($mapped_file) {
|
||||
return $mapped_file;
|
||||
}
|
||||
|
||||
// remove the trailing namespace separator for the next iteration of strrpos()
|
||||
$prefix = rtrim($prefix, '\\');
|
||||
}
|
||||
|
||||
// fix for empty prefix
|
||||
if (isset(self::$map['\\']) && ($class[0] != '\\')) {
|
||||
return self::load('\\' . $class);
|
||||
}
|
||||
|
||||
// backwards compatibility with old autoloader
|
||||
// :TODO: it should be removed
|
||||
if (strpos($class, '\\') !== false) {
|
||||
$relative_class = substr(strrchr($class, '\\'), 1); // Foo\Bar\ClassName -> ClassName
|
||||
$mapped_file = self::loadMappedFile('\\', $relative_class);
|
||||
if ($mapped_file) {
|
||||
return $mapped_file;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the mapped file for a namespace prefix and relative class.
|
||||
*
|
||||
* @param string $prefix The namespace prefix.
|
||||
* @param string $relative_class The relative class name.
|
||||
* @return mixed Boolean false if no mapped file can be loaded, or the name of the mapped file that was loaded.
|
||||
*/
|
||||
protected static function loadMappedFile($prefix, $relative_class)
|
||||
{
|
||||
if (!isset(self::$map[$prefix])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (self::$map[$prefix] as $base_dir) {
|
||||
$file = $base_dir
|
||||
. str_replace('\\', '/', $relative_class)
|
||||
. '.php';
|
||||
|
||||
// 'static' is for testing purposes
|
||||
if (static::requireFile($file)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static function requireFile($file)
|
||||
{
|
||||
if (file_exists($file)) {
|
||||
require_once $file;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
50
vendor/codeception/base/src/Codeception/Util/Debug.php
vendored
Normal file
50
vendor/codeception/base/src/Codeception/Util/Debug.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
use Codeception\Lib\Console\Output;
|
||||
|
||||
/**
|
||||
* This class is used only when Codeception is executed in `--debug` mode.
|
||||
* In other cases method of this class won't be seen.
|
||||
*/
|
||||
class Debug
|
||||
{
|
||||
/**
|
||||
* @var Output null
|
||||
*/
|
||||
protected static $output = null;
|
||||
|
||||
public static function setOutput(Output $output)
|
||||
{
|
||||
self::$output = $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints data to screen. Message can be any time of data
|
||||
*
|
||||
* @param $message
|
||||
*/
|
||||
public static function debug($message)
|
||||
{
|
||||
if (!self::$output) {
|
||||
return;
|
||||
}
|
||||
self::$output->debug($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses execution and waits for user input to proceed.
|
||||
*/
|
||||
public static function pause()
|
||||
{
|
||||
if (!self::$output) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$output->writeln("<info>The execution has been paused. Press ENTER to continue</info>");
|
||||
|
||||
if (trim(fgets(STDIN)) != chr(13)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
90
vendor/codeception/base/src/Codeception/Util/FileSystem.php
vendored
Normal file
90
vendor/codeception/base/src/Codeception/Util/FileSystem.php
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
/**
|
||||
* Set of functions to work with Filesystem
|
||||
*
|
||||
*/
|
||||
class FileSystem
|
||||
{
|
||||
/**
|
||||
* @param $path
|
||||
*/
|
||||
public static function doEmptyDir($path)
|
||||
{
|
||||
/** @var $iterator \RecursiveIteratorIterator|\SplFileObject[] */
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($path),
|
||||
\RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
|
||||
foreach ($iterator as $path) {
|
||||
$basename = basename((string)$path);
|
||||
if ($basename === '.' || $basename === '..' || $basename === '.gitignore') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($path->isDir()) {
|
||||
rmdir((string)$path);
|
||||
} else {
|
||||
unlink((string)$path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $dir
|
||||
* @return bool
|
||||
*/
|
||||
public static function deleteDir($dir)
|
||||
{
|
||||
if (!file_exists($dir)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_dir($dir) || is_link($dir)) {
|
||||
return @unlink($dir);
|
||||
}
|
||||
|
||||
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
|
||||
$dir = str_replace('/', '\\', $dir);
|
||||
exec('rd /s /q "'.$dir.'"');
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (scandir($dir) as $item) {
|
||||
if ($item === '.' || $item === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!self::deleteDir($dir . DIRECTORY_SEPARATOR . $item)) {
|
||||
chmod($dir . DIRECTORY_SEPARATOR . $item, 0777);
|
||||
if (!self::deleteDir($dir . DIRECTORY_SEPARATOR . $item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return @rmdir($dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $src
|
||||
* @param $dst
|
||||
*/
|
||||
public static function copyDir($src, $dst)
|
||||
{
|
||||
$dir = opendir($src);
|
||||
@mkdir($dst);
|
||||
while (false !== ($file = readdir($dir))) {
|
||||
if (($file != '.') && ($file != '..')) {
|
||||
if (is_dir($src . DIRECTORY_SEPARATOR . $file)) {
|
||||
self::copyDir($src . DIRECTORY_SEPARATOR . $file, $dst . DIRECTORY_SEPARATOR . $file);
|
||||
} else {
|
||||
copy($src . DIRECTORY_SEPARATOR . $file, $dst . DIRECTORY_SEPARATOR . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($dir);
|
||||
}
|
||||
}
|
||||
44
vendor/codeception/base/src/Codeception/Util/Fixtures.php
vendored
Normal file
44
vendor/codeception/base/src/Codeception/Util/Fixtures.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
/**
|
||||
* Really basic class to store data in global array and use it in Cests/Tests.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Fixtures::add('user1', ['name' => 'davert']);
|
||||
* Fixtures::get('user1');
|
||||
* Fixtures::exists('user1');
|
||||
*
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
class Fixtures
|
||||
{
|
||||
protected static $fixtures = [];
|
||||
|
||||
public static function add($name, $data)
|
||||
{
|
||||
self::$fixtures[$name] = $data;
|
||||
}
|
||||
|
||||
public static function get($name)
|
||||
{
|
||||
if (!self::exists($name)) {
|
||||
throw new \RuntimeException("$name not found in fixtures");
|
||||
}
|
||||
|
||||
return self::$fixtures[$name];
|
||||
}
|
||||
|
||||
public static function cleanup()
|
||||
{
|
||||
self::$fixtures = [];
|
||||
}
|
||||
|
||||
public static function exists($name)
|
||||
{
|
||||
return isset(self::$fixtures[$name]);
|
||||
}
|
||||
}
|
||||
162
vendor/codeception/base/src/Codeception/Util/HttpCode.php
vendored
Normal file
162
vendor/codeception/base/src/Codeception/Util/HttpCode.php
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
/**
|
||||
* Class containing constants of HTTP Status Codes
|
||||
* and method to print HTTP code with its description.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* use \Codeception\Util\HttpCode;
|
||||
*
|
||||
* // using REST, PhpBrowser, or any Framework module
|
||||
* $I->seeResponseCodeIs(HttpCode::OK);
|
||||
* $I->dontSeeResponseCodeIs(HttpCode::NOT_FOUND);
|
||||
* ```
|
||||
*
|
||||
*
|
||||
*/
|
||||
class HttpCode
|
||||
{
|
||||
const SWITCHING_PROTOCOLS = 101;
|
||||
const PROCESSING = 102; // RFC2518
|
||||
const OK = 200;
|
||||
const CREATED = 201;
|
||||
const ACCEPTED = 202;
|
||||
const NON_AUTHORITATIVE_INFORMATION = 203;
|
||||
const NO_CONTENT = 204;
|
||||
const RESET_CONTENT = 205;
|
||||
const PARTIAL_CONTENT = 206;
|
||||
const MULTI_STATUS = 207; // RFC4918
|
||||
const ALREADY_REPORTED = 208; // RFC5842
|
||||
const IM_USED = 226; // RFC3229
|
||||
const MULTIPLE_CHOICES = 300;
|
||||
const MOVED_PERMANENTLY = 301;
|
||||
const FOUND = 302;
|
||||
const SEE_OTHER = 303;
|
||||
const NOT_MODIFIED = 304;
|
||||
const USE_PROXY = 305;
|
||||
const RESERVED = 306;
|
||||
const TEMPORARY_REDIRECT = 307;
|
||||
const PERMANENTLY_REDIRECT = 308; // RFC7238
|
||||
const BAD_REQUEST = 400;
|
||||
const UNAUTHORIZED = 401;
|
||||
const PAYMENT_REQUIRED = 402;
|
||||
const FORBIDDEN = 403;
|
||||
const NOT_FOUND = 404;
|
||||
const METHOD_NOT_ALLOWED = 405;
|
||||
const NOT_ACCEPTABLE = 406;
|
||||
const PROXY_AUTHENTICATION_REQUIRED = 407;
|
||||
const REQUEST_TIMEOUT = 408;
|
||||
const CONFLICT = 409;
|
||||
const GONE = 410;
|
||||
const LENGTH_REQUIRED = 411;
|
||||
const PRECONDITION_FAILED = 412;
|
||||
const REQUEST_ENTITY_TOO_LARGE = 413;
|
||||
const REQUEST_URI_TOO_LONG = 414;
|
||||
const UNSUPPORTED_MEDIA_TYPE = 415;
|
||||
const REQUESTED_RANGE_NOT_SATISFIABLE = 416;
|
||||
const EXPECTATION_FAILED = 417;
|
||||
const I_AM_A_TEAPOT = 418; // RFC2324
|
||||
const UNPROCESSABLE_ENTITY = 422; // RFC4918
|
||||
const LOCKED = 423; // RFC4918
|
||||
const FAILED_DEPENDENCY = 424; // RFC4918
|
||||
const RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL = 425; // RFC2817
|
||||
const UPGRADE_REQUIRED = 426; // RFC2817
|
||||
const PRECONDITION_REQUIRED = 428; // RFC6585
|
||||
const TOO_MANY_REQUESTS = 429; // RFC6585
|
||||
const REQUEST_HEADER_FIELDS_TOO_LARGE = 431; // RFC6585
|
||||
const INTERNAL_SERVER_ERROR = 500;
|
||||
const NOT_IMPLEMENTED = 501;
|
||||
const BAD_GATEWAY = 502;
|
||||
const SERVICE_UNAVAILABLE = 503;
|
||||
const GATEWAY_TIMEOUT = 504;
|
||||
const VERSION_NOT_SUPPORTED = 505;
|
||||
const VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL = 506; // RFC2295
|
||||
const INSUFFICIENT_STORAGE = 507; // RFC4918
|
||||
const LOOP_DETECTED = 508; // RFC5842
|
||||
const NOT_EXTENDED = 510; // RFC2774
|
||||
const NETWORK_AUTHENTICATION_REQUIRED = 511; // RFC6585
|
||||
|
||||
private static $codes = [
|
||||
100 => 'Continue',
|
||||
102 => 'Processing',
|
||||
200 => 'OK',
|
||||
201 => 'Created',
|
||||
202 => 'Accepted',
|
||||
203 => 'Non-Authoritative Information',
|
||||
204 => 'No Content',
|
||||
205 => 'Reset Content',
|
||||
206 => 'Partial Content',
|
||||
207 => 'Multi-Status',
|
||||
208 => 'Already Reported',
|
||||
226 => 'IM Used',
|
||||
300 => 'Multiple Choices',
|
||||
301 => 'Moved Permanently',
|
||||
302 => 'Found',
|
||||
303 => 'See Other',
|
||||
304 => 'Not Modified',
|
||||
305 => 'Use Proxy',
|
||||
307 => 'Temporary Redirect',
|
||||
308 => 'Permanent Redirect',
|
||||
400 => 'Bad Request',
|
||||
401 => 'Unauthorized',
|
||||
402 => 'Payment Required',
|
||||
403 => 'Forbidden',
|
||||
404 => 'Not Found',
|
||||
405 => 'Method Not Allowed',
|
||||
406 => 'Not Acceptable',
|
||||
407 => 'Proxy Authentication Required',
|
||||
408 => 'Request Timeout',
|
||||
409 => 'Conflict',
|
||||
410 => 'Gone',
|
||||
411 => 'Length Required',
|
||||
412 => 'Precondition Failed',
|
||||
413 => 'Request Entity Too Large',
|
||||
414 => 'Request-URI Too Long',
|
||||
415 => 'Unsupported Media Type',
|
||||
416 => 'Requested Range Not Satisfiable',
|
||||
417 => 'Expectation Failed',
|
||||
421 => 'Misdirected Request',
|
||||
422 => 'Unprocessable Entity',
|
||||
423 => 'Locked',
|
||||
424 => 'Failed Dependency',
|
||||
426 => 'Upgrade Required',
|
||||
428 => 'Precondition Required',
|
||||
429 => 'Too Many Requests',
|
||||
431 => 'Request Header Fields Too Large',
|
||||
500 => 'Internal Server Error',
|
||||
501 => 'Not Implemented',
|
||||
502 => 'Bad Gateway',
|
||||
503 => 'Service Unavailable',
|
||||
504 => 'Gateway Timeout',
|
||||
505 => 'HTTP Version Not Supported',
|
||||
506 => 'Variant Also Negotiates',
|
||||
507 => 'Insufficient Storage',
|
||||
508 => 'Loop Detected',
|
||||
510 => 'Not Extended',
|
||||
511 => 'Network Authentication Required'
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns string with HTTP code and its description
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* HttpCode::getDescription(200); // '200 (OK)'
|
||||
* HttpCode::getDescription(401); // '401 (Unauthorized)'
|
||||
* ```
|
||||
*
|
||||
* @param $code
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getDescription($code)
|
||||
{
|
||||
if (isset(self::$codes[$code])) {
|
||||
return sprintf('%d (%s)', $code, self::$codes[$code]);
|
||||
}
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
136
vendor/codeception/base/src/Codeception/Util/JsonArray.php
vendored
Normal file
136
vendor/codeception/base/src/Codeception/Util/JsonArray.php
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
use Flow\JSONPath\JSONPath;
|
||||
use InvalidArgumentException;
|
||||
use DOMDocument;
|
||||
|
||||
class JsonArray
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $jsonArray = [];
|
||||
|
||||
/**
|
||||
* @var DOMDocument
|
||||
*/
|
||||
protected $jsonXml = null;
|
||||
|
||||
public function __construct($jsonString)
|
||||
{
|
||||
if (!is_string($jsonString)) {
|
||||
throw new InvalidArgumentException('$jsonString param must be a string.');
|
||||
}
|
||||
|
||||
$jsonDecode = json_decode($jsonString, true);
|
||||
|
||||
if (!is_array($jsonDecode)) {
|
||||
$jsonDecode = [$jsonDecode];
|
||||
}
|
||||
|
||||
$this->jsonArray = $jsonDecode;
|
||||
|
||||
if (JSON_ERROR_NONE !== json_last_error()) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf(
|
||||
"Invalid json: %s. System message: %s.",
|
||||
$jsonString,
|
||||
json_last_error_msg()
|
||||
),
|
||||
json_last_error()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function toXml()
|
||||
{
|
||||
if ($this->jsonXml) {
|
||||
return $this->jsonXml;
|
||||
}
|
||||
|
||||
$root = 'root';
|
||||
$jsonArray = $this->jsonArray;
|
||||
if (count($jsonArray) == 1) {
|
||||
$value = reset($jsonArray);
|
||||
if (is_array($value)) {
|
||||
$root = key($jsonArray);
|
||||
$jsonArray = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$dom = new DOMDocument('1.0', 'UTF-8');
|
||||
$dom->formatOutput = false;
|
||||
$root = $dom->createElement($root);
|
||||
$dom->appendChild($root);
|
||||
$this->arrayToXml($dom, $root, $jsonArray);
|
||||
$this->jsonXml = $dom;
|
||||
return $dom;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->jsonArray;
|
||||
}
|
||||
|
||||
public function filterByXPath($xpath)
|
||||
{
|
||||
$path = new \DOMXPath($this->toXml());
|
||||
return $path->query($xpath);
|
||||
}
|
||||
|
||||
public function filterByJsonPath($jsonPath)
|
||||
{
|
||||
if (!class_exists('Flow\JSONPath\JSONPath')) {
|
||||
throw new \Exception('JSONPath library not installed. Please add `flow/jsonpath` to composer.json');
|
||||
}
|
||||
return (new JSONPath($this->jsonArray))->find($jsonPath)->data();
|
||||
}
|
||||
|
||||
public function getXmlString()
|
||||
{
|
||||
return $this->toXml()->saveXML();
|
||||
}
|
||||
|
||||
public function containsArray(array $needle)
|
||||
{
|
||||
return (new ArrayContainsComparator($this->jsonArray))->containsArray($needle);
|
||||
}
|
||||
|
||||
private function arrayToXml(\DOMDocument $doc, \DOMNode $node, $array)
|
||||
{
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$subNode = $doc->createElement($node->nodeName);
|
||||
$node->parentNode->appendChild($subNode);
|
||||
} else {
|
||||
try {
|
||||
$subNode = $doc->createElement($key);
|
||||
} catch (\Exception $e) {
|
||||
$key = $this->getValidTagNameForInvalidKey($key);
|
||||
$subNode = $doc->createElement($key);
|
||||
}
|
||||
$node->appendChild($subNode);
|
||||
}
|
||||
if (is_array($value)) {
|
||||
$this->arrayToXml($doc, $subNode, $value);
|
||||
} else {
|
||||
$subNode->nodeValue = htmlspecialchars((string)$value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getValidTagNameForInvalidKey($key)
|
||||
{
|
||||
static $map = [];
|
||||
if (!isset($map[$key])) {
|
||||
$tagName = 'invalidTag' . (count($map) + 1);
|
||||
$map[$key] = $tagName;
|
||||
codecept_debug($tagName . ' is "' . $key . '"');
|
||||
}
|
||||
return $map[$key];
|
||||
}
|
||||
}
|
||||
208
vendor/codeception/base/src/Codeception/Util/JsonType.php
vendored
Normal file
208
vendor/codeception/base/src/Codeception/Util/JsonType.php
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
/**
|
||||
* JsonType matches JSON structures against templates.
|
||||
* You can specify the type of fields in JSON or add additional validation rules.
|
||||
*
|
||||
* JsonType is used by REST module in `seeResponseMatchesJsonType` and `dontSeeResponseMatchesJsonType` methods.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $jsonType = new JsonType(['name' => 'davert', 'id' => 1]);
|
||||
* $jsonType->matches([
|
||||
* 'name' => 'string:!empty',
|
||||
* 'id' => 'integer:>0|string:>0',
|
||||
* ]); // => true
|
||||
*
|
||||
* $jsonType->matches([
|
||||
* 'id' => 'string',
|
||||
* ]); // => `id: 1` is not of type string
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* Class JsonType
|
||||
* @package Codeception\Util
|
||||
*/
|
||||
class JsonType
|
||||
{
|
||||
protected $jsonArray;
|
||||
|
||||
protected static $customFilters = [];
|
||||
|
||||
/**
|
||||
* Creates instance of JsonType
|
||||
* Pass an array or `\Codeception\Util\JsonArray` with data.
|
||||
* If non-associative array is passed - the very first element of it will be used for matching.
|
||||
*
|
||||
* @param $jsonArray array|\Codeception\Util\JsonArray
|
||||
*/
|
||||
public function __construct($jsonArray)
|
||||
{
|
||||
if ($jsonArray instanceof JsonArray) {
|
||||
$jsonArray = $jsonArray->toArray();
|
||||
}
|
||||
$this->jsonArray = $jsonArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds custom filter to JsonType list.
|
||||
* You should specify a name and parameters of a filter.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* JsonType::addCustomFilter('slug', function($value) {
|
||||
* return strpos(' ', $value) !== false;
|
||||
* });
|
||||
* // => use it as 'string:slug'
|
||||
|
||||
*
|
||||
* // add custom function to matcher with `len($val)` syntax
|
||||
* // parameter matching patterns should be valid regex and start with `/` char
|
||||
* JsonType::addCustomFilter('/len\((.*?)\)/', function($value, $len) {
|
||||
* return strlen($value) == $len;
|
||||
* });
|
||||
* // use it as 'string:len(5)'
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $name
|
||||
* @param callable $callable
|
||||
*/
|
||||
public static function addCustomFilter($name, callable $callable)
|
||||
{
|
||||
static::$customFilters[$name] = $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all custom filters
|
||||
*/
|
||||
public static function cleanCustomFilters()
|
||||
{
|
||||
static::$customFilters = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks data against passed JsonType.
|
||||
* If matching fails function returns a string with a message describing failure.
|
||||
* On success returns `true`.
|
||||
*
|
||||
* @param array $jsonType
|
||||
* @return bool|string
|
||||
*/
|
||||
public function matches(array $jsonType)
|
||||
{
|
||||
if (array_key_exists(0, $this->jsonArray) && is_array($this->jsonArray[0])) {
|
||||
// a list of items
|
||||
$msg = '';
|
||||
foreach ($this->jsonArray as $array) {
|
||||
$res = $this->typeComparison($array, $jsonType);
|
||||
if ($res !== true) {
|
||||
$msg .= "\n" . $res;
|
||||
}
|
||||
}
|
||||
if ($msg) {
|
||||
return $msg;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return $this->typeComparison($this->jsonArray, $jsonType);
|
||||
}
|
||||
|
||||
protected function typeComparison($data, $jsonType)
|
||||
{
|
||||
foreach ($jsonType as $key => $type) {
|
||||
if (!array_key_exists($key, $data)) {
|
||||
return "Key `$key` doesn't exist in " . json_encode($data);
|
||||
}
|
||||
if (is_array($jsonType[$key])) {
|
||||
$message = $this->typeComparison($data[$key], $jsonType[$key]);
|
||||
if (is_string($message)) {
|
||||
return $message;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
$matchTypes = preg_split("#(?![^]\(]*\))\|#", $type);
|
||||
$matched = false;
|
||||
$currentType = strtolower(gettype($data[$key]));
|
||||
if ($currentType == 'double') {
|
||||
$currentType = 'float';
|
||||
}
|
||||
foreach ($matchTypes as $matchType) {
|
||||
$filters = preg_split("#(?![^]\(]*\))\:#", $matchType);
|
||||
$expectedType = trim(strtolower(array_shift($filters)));
|
||||
|
||||
if ($expectedType != $currentType) {
|
||||
continue;
|
||||
}
|
||||
$matched = true;
|
||||
|
||||
foreach ($filters as $filter) {
|
||||
$matched = $matched && $this->matchFilter($filter, $data[$key]);
|
||||
}
|
||||
if ($matched) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$matched) {
|
||||
return sprintf("`$key: %s` is of type `$type`", var_export($data[$key], true));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function matchFilter($filter, $value)
|
||||
{
|
||||
$filter = trim($filter);
|
||||
if (strpos($filter, '!') === 0) {
|
||||
return !$this->matchFilter(substr($filter, 1), $value);
|
||||
}
|
||||
|
||||
// apply custom filters
|
||||
foreach (static::$customFilters as $customFilter => $callable) {
|
||||
if (strpos($customFilter, '/') === 0) {
|
||||
if (preg_match($customFilter, $filter, $matches)) {
|
||||
array_shift($matches);
|
||||
return call_user_func_array($callable, array_merge([$value], $matches));
|
||||
}
|
||||
}
|
||||
if ($customFilter == $filter) {
|
||||
return $callable($value);
|
||||
}
|
||||
}
|
||||
|
||||
if (strpos($filter, '=') === 0) {
|
||||
return $value == substr($filter, 1);
|
||||
}
|
||||
if ($filter === 'url') {
|
||||
return filter_var($value, FILTER_VALIDATE_URL);
|
||||
}
|
||||
if ($filter === 'date') {
|
||||
return preg_match(
|
||||
'/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(?:Z|(\+|-)([\d|:]*))?$/',
|
||||
$value
|
||||
);
|
||||
}
|
||||
if ($filter === 'email') { // from http://emailregex.com/
|
||||
// @codingStandardsIgnoreStart
|
||||
return preg_match('/^(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){255,})(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){65,}@)(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22))(?:\.(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-[a-z0-9]+)*)|(?:\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\]))$/iD', $value);
|
||||
// @codingStandardsIgnoreEnd
|
||||
}
|
||||
if ($filter === 'empty') {
|
||||
return empty($value);
|
||||
}
|
||||
if (preg_match('~^regex\((.*?)\)$~', $filter, $matches)) {
|
||||
return preg_match($matches[1], $value);
|
||||
}
|
||||
if (preg_match('~^>([\d\.]+)$~', $filter, $matches)) {
|
||||
return (float)$value > (float)$matches[1];
|
||||
}
|
||||
if (preg_match('~^<([\d\.]+)$~', $filter, $matches)) {
|
||||
return (float)$value < (float)$matches[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
400
vendor/codeception/base/src/Codeception/Util/Locator.php
vendored
Normal file
400
vendor/codeception/base/src/Codeception/Util/Locator.php
vendored
Normal file
@@ -0,0 +1,400 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
use Facebook\WebDriver\WebDriverBy;
|
||||
use Symfony\Component\CssSelector\CssSelectorConverter;
|
||||
use Symfony\Component\CssSelector\Exception\ParseException;
|
||||
use Symfony\Component\CssSelector\XPath\Translator;
|
||||
|
||||
/**
|
||||
* Set of useful functions for using CSS and XPath locators.
|
||||
* Please check them before writing complex functional or acceptance tests.
|
||||
*
|
||||
*/
|
||||
class Locator
|
||||
{
|
||||
/**
|
||||
* Applies OR operator to any number of CSS or XPath selectors.
|
||||
* You can mix up CSS and XPath selectors here.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* use \Codeception\Util\Locator;
|
||||
*
|
||||
* $I->see('Title', Locator::combine('h1','h2','h3'));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* This will search for `Title` text in either `h1`, `h2`, or `h3` tag.
|
||||
* You can also combine CSS selector with XPath locator:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* use \Codeception\Util\Locator;
|
||||
*
|
||||
* $I->fillField(Locator::combine('form input[type=text]','//form/textarea[2]'), 'qwerty');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* As a result the Locator will produce a mixed XPath value that will be used in fillField action.
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @param $selector1
|
||||
* @param $selector2
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function combine($selector1, $selector2)
|
||||
{
|
||||
$selectors = func_get_args();
|
||||
foreach ($selectors as $k => $v) {
|
||||
$selectors[$k] = self::toXPath($v);
|
||||
if (!$selectors[$k]) {
|
||||
throw new \Exception("$v is invalid CSS or XPath");
|
||||
}
|
||||
}
|
||||
return implode(' | ', $selectors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the *a* element with given URL
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* use \Codeception\Util\Locator;
|
||||
*
|
||||
* $I->see('Log In', Locator::href('/login.php'));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @param $url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function href($url)
|
||||
{
|
||||
return sprintf('//a[@href=normalize-space(%s)]', Translator::getXpathLiteral($url));
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the element with given tab index
|
||||
*
|
||||
* Do you often use the `TAB` key to navigate through the web page? How do your site respond to this navigation?
|
||||
* You could try to match elements by their tab position using `tabIndex` method of `Locator` class.
|
||||
* ```php
|
||||
* <?php
|
||||
* use \Codeception\Util\Locator;
|
||||
*
|
||||
* $I->fillField(Locator::tabIndex(1), 'davert');
|
||||
* $I->fillField(Locator::tabIndex(2) , 'qwerty');
|
||||
* $I->click('Login');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @param $index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function tabIndex($index)
|
||||
{
|
||||
return sprintf('//*[@tabindex = normalize-space(%d)]', $index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches option by text:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* use Codeception\Util\Locator;
|
||||
*
|
||||
* $I->seeElement(Locator::option('Male'), '#select-gender');
|
||||
* ```
|
||||
*
|
||||
* @param $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function option($value)
|
||||
{
|
||||
return sprintf('//option[.=normalize-space("%s")]', $value);
|
||||
}
|
||||
|
||||
protected static function toXPath($selector)
|
||||
{
|
||||
try {
|
||||
$xpath = (new CssSelectorConverter())->toXPath($selector);
|
||||
return $xpath;
|
||||
} catch (ParseException $e) {
|
||||
if (self::isXPath($selector)) {
|
||||
return $selector;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds element by it's attribute(s)
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* use \Codeception\Util\Locator;
|
||||
*
|
||||
* $I->seeElement(Locator::find('img', ['title' => 'diagram']));
|
||||
* ```
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @param $element
|
||||
* @param $attributes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function find($element, array $attributes)
|
||||
{
|
||||
$operands = [];
|
||||
foreach ($attributes as $attribute => $value) {
|
||||
if (is_int($attribute)) {
|
||||
$operands[] = '@' . $value;
|
||||
} else {
|
||||
$operands[] = '@' . $attribute . ' = ' . Translator::getXpathLiteral($value);
|
||||
}
|
||||
}
|
||||
return sprintf('//%s[%s]', $element, implode(' and ', $operands));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that provided string is CSS selector
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Locator::isCSS('#user .hello') => true
|
||||
* Locator::isCSS('body') => true
|
||||
* Locator::isCSS('//body/p/user') => false
|
||||
* ```
|
||||
*
|
||||
* @param $selector
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isCSS($selector)
|
||||
{
|
||||
try {
|
||||
(new CssSelectorConverter())->toXPath($selector);
|
||||
} catch (ParseException $e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that locator is an XPath
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Locator::isXPath('#user .hello') => false
|
||||
* Locator::isXPath('body') => false
|
||||
* Locator::isXPath('//body/p/user') => true
|
||||
* ```
|
||||
*
|
||||
* @param $locator
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isXPath($locator)
|
||||
{
|
||||
$document = new \DOMDocument('1.0', 'UTF-8');
|
||||
$xpath = new \DOMXPath($document);
|
||||
return @$xpath->evaluate($locator, $document) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $locator
|
||||
* @return bool
|
||||
*/
|
||||
public static function isPrecise($locator)
|
||||
{
|
||||
if (is_array($locator)) {
|
||||
return true;
|
||||
}
|
||||
if ($locator instanceof WebDriverBy) {
|
||||
return true;
|
||||
}
|
||||
if (Locator::isID($locator)) {
|
||||
return true;
|
||||
}
|
||||
if (strpos($locator, '//') === 0) {
|
||||
return true; // simple xpath check
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a string is valid CSS ID
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Locator::isID('#user') => true
|
||||
* Locator::isID('body') => false
|
||||
* Locator::isID('//body/p/user') => false
|
||||
* ```
|
||||
*
|
||||
* @param $id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isID($id)
|
||||
{
|
||||
return (bool)preg_match('~^#[\w\.\-\[\]\=\^\~\:]+$~', $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a string is valid CSS class
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Locator::isClass('.hello') => true
|
||||
* Locator::isClass('body') => false
|
||||
* Locator::isClass('//body/p/user') => false
|
||||
* ```
|
||||
*
|
||||
* @param $class
|
||||
* @return bool
|
||||
*/
|
||||
public static function isClass($class)
|
||||
{
|
||||
return (bool)preg_match('~^\.[\w\.\-\[\]\=\^\~\:]+$~', $class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates an element containing a text inside.
|
||||
* Either CSS or XPath locator can be passed, however they will be converted to XPath.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* use Codeception\Util\Locator;
|
||||
*
|
||||
* Locator::contains('label', 'Name'); // label containing name
|
||||
* Locator::contains('div[@contenteditable=true]', 'hello world');
|
||||
* ```
|
||||
*
|
||||
* @param $element
|
||||
* @param $text
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function contains($element, $text)
|
||||
{
|
||||
$text = Translator::getXpathLiteral($text);
|
||||
return sprintf('%s[%s]', self::toXPath($element), "contains(., $text)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates element at position.
|
||||
* Either CSS or XPath locator can be passed as locator,
|
||||
* position is an integer. If a negative value is provided, counting starts from the last element.
|
||||
* First element has index 1
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* use Codeception\Util\Locator;
|
||||
*
|
||||
* Locator::elementAt('//table/tr', 2); // second row
|
||||
* Locator::elementAt('//table/tr', -1); // last row
|
||||
* Locator::elementAt('table#grind>tr', -2); // previous than last row
|
||||
* ```
|
||||
*
|
||||
* @param string $element CSS or XPath locator
|
||||
* @param int $position xpath index
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function elementAt($element, $position)
|
||||
{
|
||||
if (is_int($position) && $position < 0) {
|
||||
$position++; // -1 points to the last element
|
||||
$position = 'last()-'.abs($position);
|
||||
}
|
||||
if ($position === 0) {
|
||||
throw new \InvalidArgumentException(
|
||||
'0 is not valid element position. XPath expects first element to have index 1'
|
||||
);
|
||||
}
|
||||
return sprintf('(%s)[position()=%s]', self::toXPath($element), $position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates first element of group elements.
|
||||
* Either CSS or XPath locator can be passed as locator,
|
||||
* Equal to `Locator::elementAt($locator, 1)`
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* use Codeception\Util\Locator;
|
||||
*
|
||||
* Locator::firstElement('//table/tr');
|
||||
* ```
|
||||
*
|
||||
* @param $element
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function firstElement($element)
|
||||
{
|
||||
return self::elementAt($element, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates last element of group elements.
|
||||
* Either CSS or XPath locator can be passed as locator,
|
||||
* Equal to `Locator::elementAt($locator, -1)`
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* use Codeception\Util\Locator;
|
||||
*
|
||||
* Locator::lastElement('//table/tr');
|
||||
* ```
|
||||
*
|
||||
* @param $element
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function lastElement($element)
|
||||
{
|
||||
return self::elementAt($element, 'last()');
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms strict locator, \Facebook\WebDriver\WebDriverBy into a string represenation
|
||||
*
|
||||
* @param $selector
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function humanReadableString($selector)
|
||||
{
|
||||
if (is_string($selector)) {
|
||||
return "'$selector'";
|
||||
}
|
||||
if (is_array($selector)) {
|
||||
$type = strtolower(key($selector));
|
||||
$locator = $selector[$type];
|
||||
return "$type '$locator'";
|
||||
}
|
||||
if (class_exists('\Facebook\WebDriver\WebDriverBy')) {
|
||||
if ($selector instanceof WebDriverBy) {
|
||||
$type = $selector->getMechanism();
|
||||
$locator = $selector->getValue();
|
||||
return "$type '$locator'";
|
||||
}
|
||||
}
|
||||
throw new \InvalidArgumentException("Unrecognized selector");
|
||||
}
|
||||
}
|
||||
245
vendor/codeception/base/src/Codeception/Util/Maybe.php
vendored
Normal file
245
vendor/codeception/base/src/Codeception/Util/Maybe.php
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
/**
|
||||
* Class to represent any type of content.
|
||||
* This class can act as an object, array, or string.
|
||||
* Method or property calls to this class won't cause any errors.
|
||||
*
|
||||
* Maybe was used in Codeception 1.x to represent data on parsing step.
|
||||
* Not widely used in 2.0 anymore, but left for compatibility.
|
||||
*
|
||||
* For instance, you may use `Codeception\Util\Maybe` as a test dummies.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $user = new Maybe;
|
||||
* $user->posts->comments->count();
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
class Maybe implements \ArrayAccess, \Iterator, \JsonSerializable
|
||||
{
|
||||
protected $position = 0;
|
||||
protected $val = null;
|
||||
protected $assocArray = null;
|
||||
|
||||
public function __construct($val = null)
|
||||
{
|
||||
$this->val = $val;
|
||||
if (is_array($this->val)) {
|
||||
$this->assocArray = $this->isAssocArray($this->val);
|
||||
}
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
private function isAssocArray($arr)
|
||||
{
|
||||
return array_keys($arr) !== range(0, count($arr) - 1);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
if ($this->val === null) {
|
||||
return "?";
|
||||
}
|
||||
if (is_scalar($this->val)) {
|
||||
return (string)$this->val;
|
||||
}
|
||||
|
||||
if (is_object($this->val) && method_exists($this->val, '__toString')) {
|
||||
return $this->val->__toString();
|
||||
}
|
||||
|
||||
return $this->val;
|
||||
}
|
||||
|
||||
public function __get($key)
|
||||
{
|
||||
if ($this->val === null) {
|
||||
return new Maybe();
|
||||
}
|
||||
|
||||
if (is_object($this->val)) {
|
||||
if (isset($this->val->{$key}) || property_exists($this->val, $key)) {
|
||||
return $this->val->{$key};
|
||||
}
|
||||
}
|
||||
|
||||
return $this->val->key;
|
||||
}
|
||||
|
||||
public function __set($key, $val)
|
||||
{
|
||||
if ($this->val === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_object($this->val)) {
|
||||
$this->val->{$key} = $val;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->val->key = $val;
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if ($this->val === null) {
|
||||
return new Maybe();
|
||||
}
|
||||
return call_user_func_array([$this->val, $method], $args);
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
if (is_object($this->val)) {
|
||||
$this->val = clone $this->val;
|
||||
}
|
||||
}
|
||||
|
||||
public function __unset($key)
|
||||
{
|
||||
if (is_object($this->val)) {
|
||||
if (isset($this->val->{$key}) || property_exists($this->val, $key)) {
|
||||
unset($this->val->{$key});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
if (is_array($this->val) || ($this->val instanceof \ArrayAccess)) {
|
||||
return isset($this->val[$offset]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
if (is_array($this->val) || ($this->val instanceof \ArrayAccess)) {
|
||||
return $this->val[$offset];
|
||||
}
|
||||
return new Maybe();
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
if (is_array($this->val) || ($this->val instanceof \ArrayAccess)) {
|
||||
$this->val[$offset] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
if (is_array($this->val) || ($this->val instanceof \ArrayAccess)) {
|
||||
unset($this->val[$offset]);
|
||||
}
|
||||
}
|
||||
|
||||
public function __value()
|
||||
{
|
||||
$val = $this->val;
|
||||
if (is_array($val)) {
|
||||
foreach ($val as $k => $v) {
|
||||
if ($v instanceof self) {
|
||||
$v = $v->__value();
|
||||
}
|
||||
$val[$k] = $v;
|
||||
}
|
||||
}
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Return the current element
|
||||
* @link http://php.net/manual/en/iterator.current.php
|
||||
* @return mixed Can return any type.
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
if (!is_array($this->val)) {
|
||||
return null;
|
||||
}
|
||||
if ($this->assocArray) {
|
||||
$keys = array_keys($this->val);
|
||||
return $this->val[$keys[$this->position]];
|
||||
}
|
||||
|
||||
return $this->val[$this->position];
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Move forward to next element
|
||||
* @link http://php.net/manual/en/iterator.next.php
|
||||
* @return void Any returned value is ignored.
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
++$this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Return the key of the current element
|
||||
* @link http://php.net/manual/en/iterator.key.php
|
||||
* @return mixed scalar on success, or null on failure.
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
if ($this->assocArray) {
|
||||
$keys = array_keys($this->val);
|
||||
return $keys[$this->position];
|
||||
}
|
||||
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Checks if current position is valid
|
||||
* @link http://php.net/manual/en/iterator.valid.php
|
||||
* @return boolean The return value will be casted to boolean and then evaluated.
|
||||
* Returns true on success or false on failure.
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
if (!is_array($this->val)) {
|
||||
return null;
|
||||
}
|
||||
if ($this->assocArray) {
|
||||
$keys = array_keys($this->val);
|
||||
return isset($keys[$this->position]);
|
||||
}
|
||||
|
||||
return isset($this->val[$this->position]);
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Rewind the Iterator to the first element
|
||||
* @link http://php.net/manual/en/iterator.rewind.php
|
||||
* @return void Any returned value is ignored.
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
if (is_array($this->val)) {
|
||||
$this->assocArray = $this->isAssocArray($this->val);
|
||||
}
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.4.0)
|
||||
* Serializes the object to a value that can be serialized natively by json_encode().
|
||||
* @link http://docs.php.net/manual/en/jsonserializable.jsonserialize.php
|
||||
* @return mixed Returns data which can be serialized by json_encode(), which is a value of any type other than a resource.
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->__value();
|
||||
}
|
||||
}
|
||||
127
vendor/codeception/base/src/Codeception/Util/PathResolver.php
vendored
Normal file
127
vendor/codeception/base/src/Codeception/Util/PathResolver.php
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace Codeception\Util;
|
||||
|
||||
use Codeception\Exception\ConfigurationException;
|
||||
|
||||
class PathResolver
|
||||
{
|
||||
/**
|
||||
* Returns path to a given directory relative to $projDir.
|
||||
* @param string $path
|
||||
* @param string $projDir
|
||||
* @param string $dirSep
|
||||
* @return string
|
||||
*/
|
||||
public static function getRelativeDir($path, $projDir, $dirSep = DIRECTORY_SEPARATOR)
|
||||
{
|
||||
// ensure $projDir ends with a trailing $dirSep
|
||||
$projDir = preg_replace('/'.preg_quote($dirSep, '/').'*$/', $dirSep, $projDir);
|
||||
// if $path is a within $projDir
|
||||
if (self::fsCaseStrCmp(substr($path, 0, strlen($projDir)), $projDir, $dirSep) == 0) {
|
||||
// simply chop it off the front
|
||||
return substr($path, strlen($projDir));
|
||||
}
|
||||
// Identify any absoluteness prefix (like '/' in Unix or "C:\\" in Windows)
|
||||
$pathAbsPrefix = self::getPathAbsolutenessPrefix($path, $dirSep);
|
||||
$projDirAbsPrefix = self::getPathAbsolutenessPrefix($projDir, $dirSep);
|
||||
$sameAbsoluteness = (self::fsCaseStrCmp($pathAbsPrefix['wholePrefix'], $projDirAbsPrefix['wholePrefix'], $dirSep) == 0);
|
||||
if (!$sameAbsoluteness) {
|
||||
// if the $projDir and $path aren't relative to the same
|
||||
// thing, we can't make a relative path.
|
||||
|
||||
// if we're relative to the same device ...
|
||||
if (strlen($pathAbsPrefix['devicePrefix']) &&
|
||||
(self::fsCaseStrCmp($pathAbsPrefix['devicePrefix'], $projDirAbsPrefix['devicePrefix'], $dirSep) == 0)
|
||||
) {
|
||||
// ... shave that off
|
||||
return substr($path, strlen($pathAbsPrefix['devicePrefix']));
|
||||
}
|
||||
// Return the input unaltered
|
||||
return $path;
|
||||
}
|
||||
// peel off optional absoluteness prefixes and convert
|
||||
// $path and $projDir to an subdirectory path array
|
||||
$relPathParts = array_filter(explode($dirSep, substr($path, strlen($pathAbsPrefix['wholePrefix']))), 'strlen');
|
||||
$relProjDirParts = array_filter(explode($dirSep, substr($projDir, strlen($projDirAbsPrefix['wholePrefix']))), 'strlen');
|
||||
// While there are any, peel off any common parent directories
|
||||
// from the beginning of the $projDir and $path
|
||||
while ((count($relPathParts) > 0) && (count($relProjDirParts) > 0) &&
|
||||
(self::fsCaseStrCmp($relPathParts[0], $relProjDirParts[0], $dirSep) == 0)
|
||||
) {
|
||||
array_shift($relPathParts);
|
||||
array_shift($relProjDirParts);
|
||||
}
|
||||
if (count($relProjDirParts) > 0) {
|
||||
// prefix $relPath with '..' for all remaining unmatched $projDir
|
||||
// subdirectories
|
||||
$relPathParts = array_merge(array_fill(0, count($relProjDirParts), '..'), $relPathParts);
|
||||
}
|
||||
// only append a trailing seperator if one is already present
|
||||
$trailingSep = preg_match('/'.preg_quote($dirSep, '/').'$/', $path) ? $dirSep : '';
|
||||
// convert array of dir paths back into a string path
|
||||
return implode($dirSep, $relPathParts).$trailingSep;
|
||||
}
|
||||
/**
|
||||
* FileSystem Case String Compare
|
||||
* compare two strings with the filesystem's case-sensitiveness
|
||||
*
|
||||
* @param string $str1
|
||||
* @param string $str2
|
||||
* @param string $dirSep
|
||||
* @return int -1 / 0 / 1 for < / = / > respectively
|
||||
*/
|
||||
private static function fsCaseStrCmp($str1, $str2, $dirSep = DIRECTORY_SEPARATOR)
|
||||
{
|
||||
$cmpFn = self::isWindows($dirSep) ? 'strcasecmp' : 'strcmp';
|
||||
return $cmpFn($str1, $str2);
|
||||
}
|
||||
|
||||
/**
|
||||
* What part of this path (leftmost 0-3 characters) what
|
||||
* it is absolute relative to:
|
||||
*
|
||||
* On Unix:
|
||||
* This is simply '/' for an absolute path or
|
||||
* '' for a relative path
|
||||
*
|
||||
* On Windows this is more complicated:
|
||||
* If the first two characters are a letter followed
|
||||
* by a ':', this indicates that the path is
|
||||
* on a specific device.
|
||||
* With or without a device specified, a path MAY
|
||||
* start with a '\\' to indicate an absolute path
|
||||
* on the device or '' to indicate a path relative
|
||||
* to the device's CWD
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $dirSep
|
||||
* @return string
|
||||
*/
|
||||
private static function getPathAbsolutenessPrefix($path, $dirSep = DIRECTORY_SEPARATOR)
|
||||
{
|
||||
$devLetterPrefixPattern = '';
|
||||
if (self::isWindows($dirSep)) {
|
||||
$devLetterPrefixPattern = '([A-Za-z]:|)';
|
||||
}
|
||||
$matches = [];
|
||||
if (!preg_match('/^'.$devLetterPrefixPattern.preg_quote($dirSep, '/').'?/', $path, $matches)) {
|
||||
// This should match, even if it matches 0 characters
|
||||
throw new ConfigurationException("INTERNAL ERROR: This must be a regex problem.");
|
||||
}
|
||||
return [
|
||||
'wholePrefix' => $matches[0], // The optional device letter followed by the optional $dirSep
|
||||
'devicePrefix' => self::isWindows($dirSep) ? $matches[1] : ''];
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we in a Windows style filesystem?
|
||||
*
|
||||
* @param string $dirSep
|
||||
* @return bool
|
||||
*/
|
||||
private static function isWindows($dirSep = DIRECTORY_SEPARATOR)
|
||||
{
|
||||
return ($dirSep == '\\');
|
||||
}
|
||||
}
|
||||
17
vendor/codeception/base/src/Codeception/Util/PropertyAccess.php
vendored
Normal file
17
vendor/codeception/base/src/Codeception/Util/PropertyAccess.php
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
class PropertyAccess
|
||||
{
|
||||
/**
|
||||
* @deprecated Use ReflectionHelper::readPrivateProperty()
|
||||
* @param object $object
|
||||
* @param string $property
|
||||
* @param string|null $class
|
||||
* @return mixed
|
||||
*/
|
||||
public static function readPrivateProperty($object, $property, $class = null)
|
||||
{
|
||||
return ReflectionHelper::readPrivateProperty($object, $property, $class);
|
||||
}
|
||||
}
|
||||
3
vendor/codeception/base/src/Codeception/Util/README.md
vendored
Normal file
3
vendor/codeception/base/src/Codeception/Util/README.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Util Classes
|
||||
|
||||
Codeception Util classes are used by various parts of framework and can be used in tests or in other projects. They do not depend on Codeception core, nor they do know of Codeception itself. Thus, some of those classes have static methods.
|
||||
63
vendor/codeception/base/src/Codeception/Util/ReflectionHelper.php
vendored
Normal file
63
vendor/codeception/base/src/Codeception/Util/ReflectionHelper.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
/**
|
||||
* This class contains helper methods to help with common Reflection tasks.
|
||||
*/
|
||||
class ReflectionHelper
|
||||
{
|
||||
/**
|
||||
* Read a private property of an object.
|
||||
*
|
||||
* @param object $object
|
||||
* @param string $property
|
||||
* @param string|null $class
|
||||
* @return mixed
|
||||
*/
|
||||
public static function readPrivateProperty($object, $property, $class = null)
|
||||
{
|
||||
if (is_null($class)) {
|
||||
$class = $object;
|
||||
}
|
||||
|
||||
$property = new \ReflectionProperty($class, $property);
|
||||
$property->setAccessible(true);
|
||||
|
||||
return $property->getValue($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke a private method of an object.
|
||||
*
|
||||
* @param object $object
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
* @param string|null $class
|
||||
* @return mixed
|
||||
*/
|
||||
public static function invokePrivateMethod($object, $method, $args = [], $class = null)
|
||||
{
|
||||
if (is_null($class)) {
|
||||
$class = $object;
|
||||
}
|
||||
|
||||
$method = new \ReflectionMethod($class, $method);
|
||||
$method->setAccessible(true);
|
||||
|
||||
return $method->invokeArgs($object, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns class name without namespace
|
||||
*
|
||||
* (does not use reflection actually)
|
||||
*
|
||||
* @param $object
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getClassShortName($object)
|
||||
{
|
||||
$path = explode('\\', get_class($object));
|
||||
return array_pop($path);
|
||||
}
|
||||
}
|
||||
462
vendor/codeception/base/src/Codeception/Util/Shared/Asserts.php
vendored
Normal file
462
vendor/codeception/base/src/Codeception/Util/Shared/Asserts.php
vendored
Normal file
@@ -0,0 +1,462 @@
|
||||
<?php
|
||||
namespace Codeception\Util\Shared;
|
||||
|
||||
trait Asserts
|
||||
{
|
||||
protected function assert($arguments, $not = false)
|
||||
{
|
||||
$not = $not ? 'Not' : '';
|
||||
$method = ucfirst(array_shift($arguments));
|
||||
if (($method === 'True') && $not) {
|
||||
$method = 'False';
|
||||
$not = '';
|
||||
}
|
||||
if (($method === 'False') && $not) {
|
||||
$method = 'True';
|
||||
$not = '';
|
||||
}
|
||||
|
||||
call_user_func_array(['\PHPUnit\Framework\Assert', 'assert' . $not . $method], $arguments);
|
||||
}
|
||||
|
||||
protected function assertNot($arguments)
|
||||
{
|
||||
$this->assert($arguments, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that two variables are equal.
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
* @param float $delta
|
||||
*/
|
||||
protected function assertEquals($expected, $actual, $message = '', $delta = 0.0)
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertEquals($expected, $actual, $message, $delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that two variables are not equal
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
* @param float $delta
|
||||
*/
|
||||
protected function assertNotEquals($expected, $actual, $message = '', $delta = 0.0)
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertNotEquals($expected, $actual, $message, $delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that two variables are same
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertSame($expected, $actual, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertSame($expected, $actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that two variables are not same
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertNotSame($expected, $actual, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertNotSame($expected, $actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that actual is greater than expected
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertGreaterThan($expected, $actual, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertGreaterThan($expected, $actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
protected function assertGreaterThen($expected, $actual, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertGreaterThan($expected, $actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that actual is greater or equal than expected
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertGreaterThanOrEqual($expected, $actual, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertGreaterThanOrEqual($expected, $actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
protected function assertGreaterThenOrEqual($expected, $actual, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertGreaterThanOrEqual($expected, $actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that actual is less than expected
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertLessThan($expected, $actual, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertLessThan($expected, $actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that actual is less or equal than expected
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertLessThanOrEqual($expected, $actual, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertLessThanOrEqual($expected, $actual, $message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks that haystack contains needle
|
||||
*
|
||||
* @param $needle
|
||||
* @param $haystack
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertContains($needle, $haystack, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertContains($needle, $haystack, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that haystack doesn't contain needle.
|
||||
*
|
||||
* @param $needle
|
||||
* @param $haystack
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertNotContains($needle, $haystack, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertNotContains($needle, $haystack, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that string match with pattern
|
||||
*
|
||||
* @param string $pattern
|
||||
* @param string $string
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertRegExp($pattern, $string, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertRegExp($pattern, $string, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that string not match with pattern
|
||||
*
|
||||
* @param string $pattern
|
||||
* @param string $string
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertNotRegExp($pattern, $string, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertNotRegExp($pattern, $string, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a string starts with the given prefix.
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param string $string
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertStringStartsWith($prefix, $string, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertStringStartsWith($prefix, $string, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a string doesn't start with the given prefix.
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param string $string
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertStringStartsNotWith($prefix, $string, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertStringStartsNotWith($prefix, $string, $message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks that variable is empty.
|
||||
*
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertEmpty($actual, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertEmpty($actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that variable is not empty.
|
||||
*
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertNotEmpty($actual, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertNotEmpty($actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that variable is NULL
|
||||
*
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertNull($actual, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertNull($actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that variable is not NULL
|
||||
*
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertNotNull($actual, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertNotNull($actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that condition is positive.
|
||||
*
|
||||
* @param $condition
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertTrue($condition, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertTrue($condition, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the condition is NOT true (everything but true)
|
||||
*
|
||||
* @param $condition
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertNotTrue($condition, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertNotTrue($condition, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that condition is negative.
|
||||
*
|
||||
* @param $condition
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertFalse($condition, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertFalse($condition, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the condition is NOT false (everything but false)
|
||||
*
|
||||
* @param $condition
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertNotFalse($condition, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertNotFalse($condition, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param $haystack
|
||||
* @param $constraint
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertThat($haystack, $constraint, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertThat($haystack, $constraint, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that haystack doesn't attend
|
||||
*
|
||||
* @param $haystack
|
||||
* @param $constraint
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertThatItsNot($haystack, $constraint, $message = '')
|
||||
{
|
||||
$constraint = new \PHPUnit\Framework\Constraint\LogicalNot($constraint);
|
||||
\PHPUnit\Framework\Assert::assertThat($haystack, $constraint, $message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if file exists
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertFileExists($filename, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertFileExists($filename, $message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if file doesn't exist
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertFileNotExists($filename, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertFileNotExists($filename, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
protected function assertGreaterOrEquals($expected, $actual, $description = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertGreaterThanOrEqual($expected, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
protected function assertLessOrEquals($expected, $actual, $description = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertLessThanOrEqual($expected, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
protected function assertIsEmpty($actual, $description = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertEmpty($actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
protected function assertArrayHasKey($key, $actual, $description = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertArrayHasKey($key, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
protected function assertArrayNotHasKey($key, $actual, $description = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertArrayNotHasKey($key, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that array contains subset.
|
||||
*
|
||||
* @param array $subset
|
||||
* @param array $array
|
||||
* @param bool $strict
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertArraySubset($subset, $array, $strict = false, $message = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertArraySubset($subset, $array, $strict, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $expectedCount
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
protected function assertCount($expectedCount, $actual, $description = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertCount($expectedCount, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
protected function assertInstanceOf($class, $actual, $description = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertInstanceOf($class, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
protected function assertNotInstanceOf($class, $actual, $description = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertNotInstanceOf($class, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
protected function assertInternalType($type, $actual, $description = '')
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertInternalType($type, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fails the test with message.
|
||||
*
|
||||
* @param $message
|
||||
*/
|
||||
protected function fail($message)
|
||||
{
|
||||
\PHPUnit\Framework\Assert::fail($message);
|
||||
}
|
||||
}
|
||||
47
vendor/codeception/base/src/Codeception/Util/Shared/Namespaces.php
vendored
Normal file
47
vendor/codeception/base/src/Codeception/Util/Shared/Namespaces.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
namespace Codeception\Util\Shared;
|
||||
|
||||
trait Namespaces
|
||||
{
|
||||
protected function breakParts($class)
|
||||
{
|
||||
$class = str_replace('/', '\\', $class);
|
||||
$namespaces = explode('\\', $class);
|
||||
if (count($namespaces)) {
|
||||
$namespaces[0] = ltrim($namespaces[0], '\\');
|
||||
}
|
||||
if (!$namespaces[0]) {
|
||||
array_shift($namespaces);
|
||||
} // remove empty namespace caused of \\
|
||||
return $namespaces;
|
||||
}
|
||||
|
||||
protected function getShortClassName($class)
|
||||
{
|
||||
$namespaces = $this->breakParts($class);
|
||||
return array_pop($namespaces);
|
||||
}
|
||||
|
||||
protected function getNamespaceString($class)
|
||||
{
|
||||
$namespaces = $this->getNamespaces($class);
|
||||
return implode('\\', $namespaces);
|
||||
}
|
||||
|
||||
protected function getNamespaceHeader($class)
|
||||
{
|
||||
$str = $this->getNamespaceString($class);
|
||||
if (!$str) {
|
||||
return "";
|
||||
}
|
||||
return "namespace $str;\n";
|
||||
}
|
||||
|
||||
protected function getNamespaces($class)
|
||||
{
|
||||
$namespaces = $this->breakParts($class);
|
||||
array_pop($namespaces);
|
||||
$namespaces = array_filter($namespaces, 'strlen');
|
||||
return $namespaces;
|
||||
}
|
||||
}
|
||||
22
vendor/codeception/base/src/Codeception/Util/Soap.php
vendored
Normal file
22
vendor/codeception/base/src/Codeception/Util/Soap.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
/**
|
||||
* This class is left for BC compatibility.
|
||||
* Most of its contents moved to parent
|
||||
*
|
||||
* Class Soap
|
||||
* @package Codeception\Util
|
||||
*/
|
||||
class Soap extends Xml
|
||||
{
|
||||
public static function request()
|
||||
{
|
||||
return new XmlBuilder();
|
||||
}
|
||||
|
||||
public static function response()
|
||||
{
|
||||
return new XmlBuilder();
|
||||
}
|
||||
}
|
||||
33
vendor/codeception/base/src/Codeception/Util/Stub.php
vendored
Normal file
33
vendor/codeception/base/src/Codeception/Util/Stub.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Codeception\Util;
|
||||
|
||||
use Codeception\Lib\Notification;
|
||||
use Codeception\Stub\Expected;
|
||||
|
||||
class Stub extends \Codeception\Stub
|
||||
{
|
||||
public static function never($params = null)
|
||||
{
|
||||
Notification::deprecate("Stub::never is deprecated in favor of \Codeception\Stub\Expected::never");
|
||||
return Expected::never($params);
|
||||
}
|
||||
|
||||
public static function once($params = null)
|
||||
{
|
||||
Notification::deprecate("Stub::once is deprecated in favor of \Codeception\Stub\Expected::once");
|
||||
return Expected::once($params);
|
||||
}
|
||||
|
||||
public static function atLeastOnce($params = null)
|
||||
{
|
||||
Notification::deprecate("Stub::atLeastOnce is deprecated in favor of \Codeception\Stub\Expected::atLeastOnce");
|
||||
return Expected::atLeastOnce($params);
|
||||
}
|
||||
|
||||
public static function exactly($count, $params = null)
|
||||
{
|
||||
Notification::deprecate("Stub::exactly is deprecated in favor of \Codeception\Stub\Expected::exactly");
|
||||
return Expected::exactly($count, $params);
|
||||
}
|
||||
}
|
||||
79
vendor/codeception/base/src/Codeception/Util/Template.php
vendored
Normal file
79
vendor/codeception/base/src/Codeception/Util/Template.php
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
/**
|
||||
* Basic template engine used for generating initial Cept/Cest/Test files.
|
||||
*/
|
||||
class Template
|
||||
{
|
||||
protected $template;
|
||||
protected $vars = [];
|
||||
protected $placeholderStart;
|
||||
protected $placeholderEnd;
|
||||
|
||||
/**
|
||||
* Takes a template string
|
||||
*
|
||||
* @param $template
|
||||
*/
|
||||
public function __construct($template, $placeholderStart = '{{', $placeholderEnd = '}}')
|
||||
{
|
||||
$this->template = $template;
|
||||
$this->placeholderStart = $placeholderStart;
|
||||
$this->placeholderEnd = $placeholderEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces {{var}} string with provided value
|
||||
*
|
||||
* @param $var
|
||||
* @param $val
|
||||
* @return $this
|
||||
*/
|
||||
public function place($var, $val)
|
||||
{
|
||||
$this->vars[$var] = $val;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all template vars
|
||||
*
|
||||
* @param array $vars
|
||||
*/
|
||||
public function setVars(array $vars)
|
||||
{
|
||||
$this->vars = $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills up template string with placed variables.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function produce()
|
||||
{
|
||||
$result = $this->template;
|
||||
$regex = sprintf('~%s([\w\.]+)%s~m', $this->placeholderStart, $this->placeholderEnd);
|
||||
|
||||
$matched = preg_match_all($regex, $result, $matches, PREG_SET_ORDER);
|
||||
if (!$matched) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
foreach ($matches as $match) { // fill in placeholders
|
||||
$placeholder = $match[1];
|
||||
$value = $this->vars;
|
||||
foreach (explode('.', $placeholder) as $segment) {
|
||||
if (is_array($value) && array_key_exists($segment, $value)) {
|
||||
$value = $value[$segment];
|
||||
} else {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
$result = str_replace($this->placeholderStart . $placeholder . $this->placeholderEnd, $value, $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
115
vendor/codeception/base/src/Codeception/Util/Uri.php
vendored
Normal file
115
vendor/codeception/base/src/Codeception/Util/Uri.php
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
use GuzzleHttp\Psr7\Uri as Psr7Uri;
|
||||
|
||||
class Uri
|
||||
{
|
||||
/**
|
||||
* Merges the passed $add argument onto $base.
|
||||
*
|
||||
* If a relative URL is passed as the 'path' part of the $add url
|
||||
* array, the relative URL is mapped using the base 'path' part as
|
||||
* its base.
|
||||
*
|
||||
* @param string $baseUri the base URL
|
||||
* @param string $uri the URL to merge
|
||||
* @return array the merged array
|
||||
*/
|
||||
public static function mergeUrls($baseUri, $uri)
|
||||
{
|
||||
$base = new Psr7Uri($baseUri);
|
||||
$parts = parse_url($uri);
|
||||
|
||||
//If the relative URL does not parse, attempt to parse the entire URL.
|
||||
//PHP Known bug ( https://bugs.php.net/bug.php?id=70942 )
|
||||
if ($parts === false) {
|
||||
$parts = parse_url($base.$uri);
|
||||
}
|
||||
|
||||
if ($parts === false) {
|
||||
throw new \InvalidArgumentException("Invalid URI $uri");
|
||||
}
|
||||
|
||||
if (isset($parts['host']) and isset($parts['scheme'])) {
|
||||
// if this is an absolute url, replace with it
|
||||
return $uri;
|
||||
}
|
||||
|
||||
if (isset($parts['host'])) {
|
||||
$base = $base->withHost($parts['host']);
|
||||
$base = $base->withPath('');
|
||||
$base = $base->withQuery('');
|
||||
$base = $base->withFragment('');
|
||||
}
|
||||
if (isset($parts['path'])) {
|
||||
$path = $parts['path'];
|
||||
$basePath = $base->getPath();
|
||||
if ((strpos($path, '/') !== 0) && !empty($path)) {
|
||||
if ($basePath) {
|
||||
// if it ends with a slash, relative paths are below it
|
||||
if (preg_match('~/$~', $basePath)) {
|
||||
$path = $basePath . $path;
|
||||
} else {
|
||||
// remove double slashes
|
||||
$dir = rtrim(dirname($basePath), '\\/');
|
||||
$path = $dir . '/' . $path;
|
||||
}
|
||||
} else {
|
||||
$path = '/' . ltrim($path, '/');
|
||||
}
|
||||
}
|
||||
$base = $base->withPath($path);
|
||||
$base = $base->withQuery('');
|
||||
$base = $base->withFragment('');
|
||||
}
|
||||
if (isset($parts['query'])) {
|
||||
$base = $base->withQuery($parts['query']);
|
||||
$base = $base->withFragment('');
|
||||
}
|
||||
if (isset($parts['fragment'])) {
|
||||
$base = $base->withFragment($parts['fragment']);
|
||||
}
|
||||
|
||||
return (string) $base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve /path?query#fragment part of URL
|
||||
* @param $url
|
||||
* @return string
|
||||
*/
|
||||
public static function retrieveUri($url)
|
||||
{
|
||||
$uri = new Psr7Uri($url);
|
||||
return (string)(new Psr7Uri())
|
||||
->withPath($uri->getPath())
|
||||
->withQuery($uri->getQuery())
|
||||
->withFragment($uri->getFragment());
|
||||
}
|
||||
|
||||
public static function retrieveHost($url)
|
||||
{
|
||||
$urlParts = parse_url($url);
|
||||
if (!isset($urlParts['host']) or !isset($urlParts['scheme'])) {
|
||||
throw new \InvalidArgumentException("Wrong URL passes, host and scheme not set");
|
||||
}
|
||||
$host = $urlParts['scheme'] . '://' . $urlParts['host'];
|
||||
if (isset($urlParts['port'])) {
|
||||
$host .= ':' . $urlParts['port'];
|
||||
}
|
||||
return $host;
|
||||
}
|
||||
|
||||
public static function appendPath($url, $path)
|
||||
{
|
||||
$uri = new Psr7Uri($url);
|
||||
$cutUrl = (string)$uri->withQuery('')->withFragment('');
|
||||
|
||||
if ($path === '' || $path[0] === '#') {
|
||||
return $cutUrl . $path;
|
||||
}
|
||||
|
||||
return rtrim($cutUrl, '/') . '/' . ltrim($path, '/');
|
||||
}
|
||||
}
|
||||
63
vendor/codeception/base/src/Codeception/Util/Xml.php
vendored
Normal file
63
vendor/codeception/base/src/Codeception/Util/Xml.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
class Xml
|
||||
{
|
||||
/**
|
||||
* @static
|
||||
*
|
||||
* @param \DOMDocument $xml
|
||||
* @param \DOMNode $node
|
||||
* @param array $array
|
||||
*
|
||||
* @return \DOMDocument
|
||||
*/
|
||||
public static function arrayToXml(\DOMDocument $xml, \DOMNode $node, $array = [])
|
||||
{
|
||||
foreach ($array as $el => $val) {
|
||||
if (is_array($val)) {
|
||||
self::arrayToXml($xml, $node->$el, $val);
|
||||
} else {
|
||||
$node->appendChild($xml->createElement($el, $val));
|
||||
}
|
||||
}
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
*
|
||||
* @param $xml
|
||||
*
|
||||
* @return \DOMDocument|\DOMNode
|
||||
*/
|
||||
public static function toXml($xml)
|
||||
{
|
||||
if ($xml instanceof XmlBuilder) {
|
||||
return $xml->getDom();
|
||||
}
|
||||
if ($xml instanceof \DOMDocument) {
|
||||
return $xml;
|
||||
}
|
||||
$dom = new \DOMDocument();
|
||||
$dom->preserveWhiteSpace = false;
|
||||
if ($xml instanceof \DOMNode) {
|
||||
$xml = $dom->importNode($xml, true);
|
||||
$dom->appendChild($xml);
|
||||
return $dom;
|
||||
}
|
||||
|
||||
if (is_array($xml)) {
|
||||
return self::arrayToXml($dom, $dom, $xml);
|
||||
}
|
||||
if (!empty($xml)) {
|
||||
$dom->loadXML($xml);
|
||||
}
|
||||
return $dom;
|
||||
}
|
||||
|
||||
public static function build()
|
||||
{
|
||||
return new XmlBuilder();
|
||||
}
|
||||
}
|
||||
177
vendor/codeception/base/src/Codeception/Util/XmlBuilder.php
vendored
Normal file
177
vendor/codeception/base/src/Codeception/Util/XmlBuilder.php
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
/**
|
||||
* That's a pretty simple yet powerful class to build XML structures in jQuery-like style.
|
||||
* With no XML line actually written!
|
||||
* Uses DOM extension to manipulate XML data.
|
||||
*
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $xml = new \Codeception\Util\XmlBuilder();
|
||||
* $xml->users
|
||||
* ->user
|
||||
* ->val(1)
|
||||
* ->email
|
||||
* ->val('davert@mail.ua')
|
||||
* ->attr('valid','true')
|
||||
* ->parent()
|
||||
* ->cart
|
||||
* ->attr('empty','false')
|
||||
* ->items
|
||||
* ->item
|
||||
* ->val('useful item');
|
||||
* ->parents('user')
|
||||
* ->active
|
||||
* ->val(1);
|
||||
* echo $xml;
|
||||
* ```
|
||||
*
|
||||
* This will produce this XML
|
||||
*
|
||||
* ```xml
|
||||
* <?xml version="1.0"?>
|
||||
* <users>
|
||||
* <user>
|
||||
* 1
|
||||
* <email valid="true">davert@mail.ua</email>
|
||||
* <cart empty="false">
|
||||
* <items>
|
||||
* <item>useful item</item>
|
||||
* </items>
|
||||
* </cart>
|
||||
* <active>1</active>
|
||||
* </user>
|
||||
* </users>
|
||||
* ```
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* Builder uses chained calls. So each call to builder returns a builder object.
|
||||
* Except for `getDom` and `__toString` methods.
|
||||
*
|
||||
* * `$xml->node` - create new xml node and go inside of it.
|
||||
* * `$xml->node->val('value')` - sets the inner value of node
|
||||
* * `$xml->attr('name','value')` - set the attribute of node
|
||||
* * `$xml->parent()` - go back to parent node.
|
||||
* * `$xml->parents('user')` - go back through all parents to `user` node.
|
||||
*
|
||||
* Export:
|
||||
*
|
||||
* * `$xml->getDom` - get a DOMDocument object
|
||||
* * `$xml->__toString` - get a string representation of XML.
|
||||
*
|
||||
* [Source code](https://github.com/Codeception/Codeception/blob/master/src/Codeception/Util/XmlBuilder.php)
|
||||
*/
|
||||
class XmlBuilder
|
||||
{
|
||||
/**
|
||||
* @var \DOMDocument
|
||||
*/
|
||||
protected $__dom__;
|
||||
|
||||
/**
|
||||
* @var \DOMElement
|
||||
*/
|
||||
protected $__currentNode__;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->__dom__ = new \DOMDocument();
|
||||
$this->__currentNode__ = $this->__dom__;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends child node
|
||||
*
|
||||
* @param $tag
|
||||
*
|
||||
* @return XmlBuilder
|
||||
*/
|
||||
public function __get($tag)
|
||||
{
|
||||
$node = $this->__dom__->createElement($tag);
|
||||
$this->__currentNode__->appendChild($node);
|
||||
$this->__currentNode__ = $node;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $val
|
||||
*
|
||||
* @return XmlBuilder
|
||||
*/
|
||||
public function val($val)
|
||||
{
|
||||
$this->__currentNode__->nodeValue = $val;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets attribute for current node
|
||||
*
|
||||
* @param $attr
|
||||
* @param $val
|
||||
*
|
||||
* @return XmlBuilder
|
||||
*/
|
||||
public function attr($attr, $val)
|
||||
{
|
||||
$this->__currentNode__->setAttribute($attr, $val);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses to parent
|
||||
*
|
||||
* @return XmlBuilder
|
||||
*/
|
||||
public function parent()
|
||||
{
|
||||
$this->__currentNode__ = $this->__currentNode__->parentNode;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses to parent with $name
|
||||
*
|
||||
* @param $tag
|
||||
*
|
||||
* @return XmlBuilder
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function parents($tag)
|
||||
{
|
||||
$traverseNode = $this->__currentNode__;
|
||||
$elFound = false;
|
||||
while ($traverseNode->parentNode) {
|
||||
$traverseNode = $traverseNode->parentNode;
|
||||
if ($traverseNode->tagName == $tag) {
|
||||
$this->__currentNode__ = $traverseNode;
|
||||
$elFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$elFound) {
|
||||
throw new \Exception("Parent $tag not found in XML");
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->__dom__->saveXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DOMDocument
|
||||
*/
|
||||
public function getDom()
|
||||
{
|
||||
return $this->__dom__;
|
||||
}
|
||||
}
|
||||
92
vendor/codeception/base/src/Codeception/Util/XmlStructure.php
vendored
Normal file
92
vendor/codeception/base/src/Codeception/Util/XmlStructure.php
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
namespace Codeception\Util;
|
||||
|
||||
use Codeception\Exception\ElementNotFound;
|
||||
use Codeception\Exception\MalformedLocatorException;
|
||||
use Symfony\Component\CssSelector\CssSelectorConverter;
|
||||
use Symfony\Component\CssSelector\Exception\ParseException;
|
||||
use Codeception\Util\Soap as XmlUtils;
|
||||
|
||||
class XmlStructure
|
||||
{
|
||||
/**
|
||||
* @var \DOMDocument|\DOMNode
|
||||
*/
|
||||
protected $xml;
|
||||
|
||||
public function __construct($xml)
|
||||
{
|
||||
$this->xml = XmlUtils::toXml($xml);
|
||||
}
|
||||
|
||||
public function matchesXpath($xpath)
|
||||
{
|
||||
$path = new \DOMXPath($this->xml);
|
||||
$res = $path->query($xpath);
|
||||
if ($res === false) {
|
||||
throw new MalformedLocatorException($xpath);
|
||||
}
|
||||
return $res->length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $cssOrXPath
|
||||
* @return \DOMElement
|
||||
*/
|
||||
public function matchElement($cssOrXPath)
|
||||
{
|
||||
$xpath = new \DOMXpath($this->xml);
|
||||
try {
|
||||
$selector = (new CssSelectorConverter())->toXPath($cssOrXPath);
|
||||
$els = $xpath->query($selector);
|
||||
if ($els) {
|
||||
return $els->item(0);
|
||||
}
|
||||
} catch (ParseException $e) {
|
||||
}
|
||||
$els = $xpath->query($cssOrXPath);
|
||||
if ($els->length) {
|
||||
return $els->item(0);
|
||||
}
|
||||
throw new ElementNotFound($cssOrXPath);
|
||||
}
|
||||
/**
|
||||
|
||||
* @param $xml
|
||||
* @return bool
|
||||
*/
|
||||
public function matchXmlStructure($xml)
|
||||
{
|
||||
$xml = XmlUtils::toXml($xml);
|
||||
$root = $xml->firstChild;
|
||||
$els = $this->xml->getElementsByTagName($root->nodeName);
|
||||
if (empty($els)) {
|
||||
throw new ElementNotFound($root->nodeName, 'Element');
|
||||
}
|
||||
|
||||
$matches = false;
|
||||
foreach ($els as $node) {
|
||||
$matches |= $this->matchForNode($root, $node);
|
||||
}
|
||||
return $matches;
|
||||
}
|
||||
|
||||
protected function matchForNode($schema, $xml)
|
||||
{
|
||||
foreach ($schema->childNodes as $node1) {
|
||||
$matched = false;
|
||||
foreach ($xml->childNodes as $node2) {
|
||||
if ($node1->nodeName == $node2->nodeName) {
|
||||
$matched = $this->matchForNode($node1, $node2);
|
||||
if ($matched) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$matched) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
32
vendor/codeception/base/src/Codeception/Util/sq.php
vendored
Normal file
32
vendor/codeception/base/src/Codeception/Util/sq.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
use Codeception\Module\Sequence;
|
||||
|
||||
if (!function_exists('sq')) {
|
||||
function sq($id = null)
|
||||
{
|
||||
if ($id and isset(Sequence::$hash[$id])) {
|
||||
return Sequence::$hash[$id];
|
||||
}
|
||||
$prefix = str_replace('{id}', $id, Sequence::$prefix);
|
||||
$sequence = $prefix . uniqid($id);
|
||||
if ($id) {
|
||||
Sequence::$hash[$id] = $sequence;
|
||||
}
|
||||
return $sequence;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('sqs')) {
|
||||
function sqs($id = null)
|
||||
{
|
||||
if ($id and isset(Sequence::$suiteHash[$id])) {
|
||||
return Sequence::$suiteHash[$id];
|
||||
}
|
||||
$prefix = str_replace('{id}', $id, Sequence::$prefix);
|
||||
$sequence = $prefix . uniqid($id);
|
||||
if ($id) {
|
||||
Sequence::$suiteHash[$id] = $sequence;
|
||||
}
|
||||
return $sequence;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user