This commit is contained in:
2020-02-01 16:47:12 +07:00
commit 4c619ad6e6
16739 changed files with 3329179 additions and 0 deletions

View File

@@ -0,0 +1,157 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\test;
use yii\base\InvalidConfigException;
use yii\db\TableSchema;
/**
* ActiveFixture represents a fixture backed up by a [[modelClass|ActiveRecord class]] or a [[tableName|database table]].
*
* Either [[modelClass]] or [[tableName]] must be set. You should also provide fixture data in the file
* specified by [[dataFile]] or overriding [[getData()]] if you want to use code to generate the fixture data.
*
* When the fixture is being loaded, it will first call [[resetTable()]] to remove any existing data in the table.
* It will then populate the table with the data returned by [[getData()]].
*
* After the fixture is loaded, you can access the loaded data via the [[data]] property. If you set [[modelClass]],
* you will also be able to retrieve an instance of [[modelClass]] with the populated data via [[getModel()]].
*
* For more details and usage information on ActiveFixture, see the [guide article on fixtures](guide:test-fixtures).
*
* @property TableSchema $tableSchema The schema information of the database table associated with this
* fixture. This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ActiveFixture extends BaseActiveFixture
{
/**
* @var string the name of the database table that this fixture is about. If this property is not set,
* the table name will be determined via [[modelClass]].
* @see modelClass
*/
public $tableName;
/**
* @var string|bool the file path or [path alias](guide:concept-aliases) of the data file that contains the fixture data
* to be returned by [[getData()]]. If this is not set, it will default to `FixturePath/data/TableName.php`,
* where `FixturePath` stands for the directory containing this fixture class, and `TableName` stands for the
* name of the table associated with this fixture. You can set this property to be false to prevent loading any data.
*/
public $dataFile;
/**
* @var TableSchema the table schema for the table associated with this fixture
*/
private $_table;
/**
* {@inheritdoc}
*/
public function init()
{
parent::init();
if ($this->modelClass === null && $this->tableName === null) {
throw new InvalidConfigException('Either "modelClass" or "tableName" must be set.');
}
}
/**
* Loads the fixture.
*
* It populate the table with the data returned by [[getData()]].
*
* If you override this method, you should consider calling the parent implementation
* so that the data returned by [[getData()]] can be populated into the table.
*/
public function load()
{
$this->data = [];
$table = $this->getTableSchema();
foreach ($this->getData() as $alias => $row) {
$primaryKeys = $this->db->schema->insert($table->fullName, $row);
$this->data[$alias] = array_merge($row, $primaryKeys);
}
}
/**
* Returns the fixture data.
*
* The default implementation will try to return the fixture data by including the external file specified by [[dataFile]].
* The file should return an array of data rows (column name => column value), each corresponding to a row in the table.
*
* If the data file does not exist, an empty array will be returned.
*
* @return array the data rows to be inserted into the database table.
*/
protected function getData()
{
if ($this->dataFile === null) {
if ($this->dataDirectory !== null) {
$dataFile = $this->getTableSchema()->fullName . '.php';
} else {
$class = new \ReflectionClass($this);
$dataFile = dirname($class->getFileName()) . '/data/' . $this->getTableSchema()->fullName . '.php';
}
return $this->loadData($dataFile, false);
}
return parent::getData();
}
/**
* {@inheritdoc}
*/
public function unload()
{
$this->resetTable();
parent::unload();
}
/**
* Removes all existing data from the specified table and resets sequence number to 1 (if any).
* This method is called before populating fixture data into the table associated with this fixture.
*/
protected function resetTable()
{
$table = $this->getTableSchema();
$this->db->createCommand()->delete($table->fullName)->execute();
if ($table->sequenceName !== null) {
$this->db->createCommand()->resetSequence($table->fullName, 1)->execute();
}
}
/**
* @return TableSchema the schema information of the database table associated with this fixture.
* @throws \yii\base\InvalidConfigException if the table does not exist
*/
public function getTableSchema()
{
if ($this->_table !== null) {
return $this->_table;
}
$db = $this->db;
$tableName = $this->tableName;
if ($tableName === null) {
/* @var $modelClass \yii\db\ActiveRecord */
$modelClass = $this->modelClass;
$tableName = $modelClass::tableName();
}
$this->_table = $db->getSchema()->getTableSchema($tableName);
if ($this->_table === null) {
throw new InvalidConfigException("Table does not exist: {$tableName}");
}
return $this->_table;
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\test;
use yii\base\ArrayAccessTrait;
use yii\base\InvalidConfigException;
/**
* ArrayFixture represents arbitrary fixture that can be loaded from PHP files.
*
* For more details and usage information on ArrayFixture, see the [guide article on fixtures](guide:test-fixtures).
*
* @author Mark Jebri <mark.github@yandex.ru>
* @since 2.0
*/
class ArrayFixture extends Fixture implements \IteratorAggregate, \ArrayAccess, \Countable
{
use ArrayAccessTrait;
use FileFixtureTrait;
/**
* @var array the data rows. Each array element represents one row of data (column name => column value).
*/
public $data = [];
/**
* Loads the fixture.
*
* The default implementation simply stores the data returned by [[getData()]] in [[data]].
* You should usually override this method by putting the data into the underlying database.
*/
public function load()
{
$this->data = $this->getData();
}
/**
* Returns the fixture data.
*
* The default implementation will try to return the fixture data by including the external file specified by [[dataFile]].
* The file should return the data array that will be stored in [[data]] after inserting into the database.
*
* @return array the data to be put into the database
* @throws InvalidConfigException if the specified data file does not exist.
*/
protected function getData()
{
return $this->loadData($this->dataFile);
}
/**
* {@inheritdoc}
*/
public function unload()
{
parent::unload();
$this->data = [];
}
}

View File

@@ -0,0 +1,103 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\test;
use yii\base\ArrayAccessTrait;
use yii\base\InvalidConfigException;
/**
* BaseActiveFixture is the base class for fixture classes that support accessing fixture data as ActiveRecord objects.
*
* For more details and usage information on BaseActiveFixture, see the [guide article on fixtures](guide:test-fixtures).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
abstract class BaseActiveFixture extends DbFixture implements \IteratorAggregate, \ArrayAccess, \Countable
{
use ArrayAccessTrait;
use FileFixtureTrait;
/**
* @var string the AR model class associated with this fixture.
*/
public $modelClass;
/**
* @var array the data rows. Each array element represents one row of data (column name => column value).
*/
public $data = [];
/**
* @var \yii\db\ActiveRecord[] the loaded AR models
*/
private $_models = [];
/**
* Returns the AR model by the specified model name.
* A model name is the key of the corresponding data row in [[data]].
* @param string $name the model name.
* @return null|\yii\db\ActiveRecord the AR model, or null if the model cannot be found in the database
* @throws \yii\base\InvalidConfigException if [[modelClass]] is not set.
*/
public function getModel($name)
{
if (!isset($this->data[$name])) {
return null;
}
if (array_key_exists($name, $this->_models)) {
return $this->_models[$name];
}
if ($this->modelClass === null) {
throw new InvalidConfigException('The "modelClass" property must be set.');
}
$row = $this->data[$name];
/* @var $modelClass \yii\db\ActiveRecord */
$modelClass = $this->modelClass;
$keys = [];
foreach ($modelClass::primaryKey() as $key) {
$keys[$key] = isset($row[$key]) ? $row[$key] : null;
}
return $this->_models[$name] = $modelClass::findOne($keys);
}
/**
* Loads the fixture.
*
* The default implementation simply stores the data returned by [[getData()]] in [[data]].
* You should usually override this method by putting the data into the underlying database.
*/
public function load()
{
$this->data = $this->getData();
}
/**
* Returns the fixture data.
*
* @return array the data to be put into the database
* @throws InvalidConfigException if the specified data file does not exist.
* @see [[loadData]]
*/
protected function getData()
{
return $this->loadData($this->dataFile);
}
/**
* {@inheritdoc}
*/
public function unload()
{
parent::unload();
$this->data = [];
$this->_models = [];
}
}

43
vendor/yiisoft/yii2/test/DbFixture.php vendored Normal file
View File

@@ -0,0 +1,43 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\test;
use yii\base\BaseObject;
use yii\db\Connection;
use yii\di\Instance;
/**
* DbFixture is the base class for DB-related fixtures.
*
* DbFixture provides the [[db]] connection to be used by DB fixtures.
*
* For more details and usage information on DbFixture, see the [guide article on fixtures](guide:test-fixtures).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
abstract class DbFixture extends Fixture
{
/**
* @var Connection|array|string the DB connection object or the application component ID of the DB connection.
* After the DbFixture object is created, if you want to change this property, you should only assign it
* with a DB connection object.
* Starting from version 2.0.2, this can also be a configuration array for creating the object.
*/
public $db = 'db';
/**
* {@inheritdoc}
*/
public function init()
{
parent::init();
$this->db = Instance::ensure($this->db, BaseObject::className());
}
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\test;
use Yii;
use yii\base\InvalidConfigException;
/**
* FileFixtureTrait provides functionalities for loading data fixture from file.
*
* @author Leandro Guindani Gehlen <leandrogehlen@gmail.com>
* @since 2.0.14
*/
trait FileFixtureTrait
{
/**
* @var string the directory path or [path alias](guide:concept-aliases) that contains the fixture data
*/
public $dataDirectory;
/**
* @var string|bool the file path or [path alias](guide:concept-aliases) of the data file that contains the fixture data
* to be returned by [[getData()]]. You can set this property to be false to prevent loading any data.
*/
public $dataFile;
/**
* Returns the fixture data.
*
* The default implementation will try to return the fixture data by including the external file specified by [[dataFile]].
* The file should return the data array that will be stored in [[data]] after inserting into the database.
*
* @param string $file the data file path
* @param bool $throwException whether to throw exception if fixture data file does not exist.
* @return array the data to be put into the database
* @throws InvalidConfigException if the specified data file does not exist.
*/
protected function loadData($file, $throwException = true)
{
if ($file === null || $file === false) {
return [];
}
if (basename($file) === $file && $this->dataDirectory !== null) {
$file = $this->dataDirectory . '/' . $file;
}
$file = Yii::getAlias($file);
if (is_file($file)) {
return require $file;
}
if ($throwException) {
throw new InvalidConfigException("Fixture data file does not exist: {$file}");
}
return [];
}
}

86
vendor/yiisoft/yii2/test/Fixture.php vendored Normal file
View File

@@ -0,0 +1,86 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\test;
use yii\base\Component;
/**
* Fixture represents a fixed state of a test environment.
*
* Each fixture instance represents a particular aspect of a test environment. For example,
* you may use `UserFixture` to initialize the user database table with a set of known data. You may
* load the fixture when running every test method so that the user table always contains the fixed data
* and thus allows your test predictable and repeatable.
*
* A fixture may depend on other fixtures, specified via the [[depends]] property. When a fixture is being loaded,
* its dependent fixtures will be automatically loaded BEFORE the fixture; and when the fixture is being unloaded,
* its dependent fixtures will be unloaded AFTER the fixture.
*
* You should normally override [[load()]] to specify how to set up a fixture; and override [[unload()]]
* for clearing up a fixture.
*
* For more details and usage information on Fixture, see the [guide article on fixtures](guide:test-fixtures).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Fixture extends Component
{
/**
* @var array the fixtures that this fixture depends on. This must be a list of the dependent
* fixture class names.
*/
public $depends = [];
/**
* Loads the fixture.
* This method is called before performing every test method.
* You should override this method with concrete implementation about how to set up the fixture.
*/
public function load()
{
}
/**
* This method is called BEFORE any fixture data is loaded for the current test.
*/
public function beforeLoad()
{
}
/**
* This method is called AFTER all fixture data have been loaded for the current test.
*/
public function afterLoad()
{
}
/**
* Unloads the fixture.
* This method is called after every test method finishes.
* You may override this method to perform necessary cleanup work for the fixture.
*/
public function unload()
{
}
/**
* This method is called BEFORE any fixture data is unloaded for the current test.
*/
public function beforeUnload()
{
}
/**
* This method is called AFTER all fixture data have been unloaded for the current test.
*/
public function afterUnload()
{
}
}

View File

@@ -0,0 +1,221 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\test;
use Yii;
use yii\base\InvalidConfigException;
/**
* FixtureTrait provides functionalities for loading, unloading and accessing fixtures for a test case.
*
* By using FixtureTrait, a test class will be able to specify which fixtures to load by overriding
* the [[fixtures()]] method. It can then load and unload the fixtures using [[loadFixtures()]] and [[unloadFixtures()]].
* Once a fixture is loaded, it can be accessed like an object property, thanks to the PHP `__get()` magic method.
* Also, if the fixture is an instance of [[ActiveFixture]], you will be able to access AR models
* through the syntax `$this->fixtureName('model name')`.
*
* For more details and usage information on FixtureTrait, see the [guide article on fixtures](guide:test-fixtures).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
trait FixtureTrait
{
/**
* @var array the list of fixture objects available for the current test.
* The array keys are the corresponding fixture class names.
* The fixtures are listed in their dependency order. That is, fixture A is listed before B
* if B depends on A.
*/
private $_fixtures;
/**
* Declares the fixtures that are needed by the current test case.
*
* The return value of this method must be an array of fixture configurations. For example,
*
* ```php
* [
* // anonymous fixture
* PostFixture::className(),
* // "users" fixture
* 'users' => UserFixture::className(),
* // "cache" fixture with configuration
* 'cache' => [
* 'class' => CacheFixture::className(),
* 'host' => 'xxx',
* ],
* ]
* ```
*
* Note that the actual fixtures used for a test case will include both [[globalFixtures()]]
* and [[fixtures()]].
*
* @return array the fixtures needed by the current test case
*/
public function fixtures()
{
return [];
}
/**
* Declares the fixtures shared required by different test cases.
* The return value should be similar to that of [[fixtures()]].
* You should usually override this method in a base class.
* @return array the fixtures shared and required by different test cases.
* @see fixtures()
*/
public function globalFixtures()
{
return [];
}
/**
* Loads the specified fixtures.
* This method will call [[Fixture::load()]] for every fixture object.
* @param Fixture[] $fixtures the fixtures to be loaded. If this parameter is not specified,
* the return value of [[getFixtures()]] will be used.
*/
public function loadFixtures($fixtures = null)
{
if ($fixtures === null) {
$fixtures = $this->getFixtures();
}
/* @var $fixture Fixture */
foreach ($fixtures as $fixture) {
$fixture->beforeLoad();
}
foreach ($fixtures as $fixture) {
$fixture->load();
}
foreach (array_reverse($fixtures) as $fixture) {
$fixture->afterLoad();
}
}
/**
* Unloads the specified fixtures.
* This method will call [[Fixture::unload()]] for every fixture object.
* @param Fixture[] $fixtures the fixtures to be loaded. If this parameter is not specified,
* the return value of [[getFixtures()]] will be used.
*/
public function unloadFixtures($fixtures = null)
{
if ($fixtures === null) {
$fixtures = $this->getFixtures();
}
/* @var $fixture Fixture */
foreach ($fixtures as $fixture) {
$fixture->beforeUnload();
}
$fixtures = array_reverse($fixtures);
foreach ($fixtures as $fixture) {
$fixture->unload();
}
foreach ($fixtures as $fixture) {
$fixture->afterUnload();
}
}
/**
* Initialize the fixtures.
* @since 2.0.12
*/
public function initFixtures()
{
$this->unloadFixtures();
$this->loadFixtures();
}
/**
* Returns the fixture objects as specified in [[globalFixtures()]] and [[fixtures()]].
* @return Fixture[] the loaded fixtures for the current test case
*/
public function getFixtures()
{
if ($this->_fixtures === null) {
$this->_fixtures = $this->createFixtures(array_merge($this->globalFixtures(), $this->fixtures()));
}
return $this->_fixtures;
}
/**
* Returns the named fixture.
* @param string $name the fixture name. This can be either the fixture alias name, or the class name if the alias is not used.
* @return Fixture the fixture object, or null if the named fixture does not exist.
*/
public function getFixture($name)
{
if ($this->_fixtures === null) {
$this->_fixtures = $this->createFixtures(array_merge($this->globalFixtures(), $this->fixtures()));
}
$name = ltrim($name, '\\');
return isset($this->_fixtures[$name]) ? $this->_fixtures[$name] : null;
}
/**
* Creates the specified fixture instances.
* All dependent fixtures will also be created.
* @param array $fixtures the fixtures to be created. You may provide fixture names or fixture configurations.
* If this parameter is not provided, the fixtures specified in [[globalFixtures()]] and [[fixtures()]] will be created.
* @return Fixture[] the created fixture instances
* @throws InvalidConfigException if fixtures are not properly configured or if a circular dependency among
* the fixtures is detected.
*/
protected function createFixtures(array $fixtures)
{
// normalize fixture configurations
$config = []; // configuration provided in test case
$aliases = []; // class name => alias or class name
foreach ($fixtures as $name => $fixture) {
if (!is_array($fixture)) {
$class = ltrim($fixture, '\\');
$fixtures[$name] = ['class' => $class];
$aliases[$class] = is_int($name) ? $class : $name;
} elseif (isset($fixture['class'])) {
$class = ltrim($fixture['class'], '\\');
$config[$class] = $fixture;
$aliases[$class] = $name;
} else {
throw new InvalidConfigException("You must specify 'class' for the fixture '$name'.");
}
}
// create fixture instances
$instances = [];
$stack = array_reverse($fixtures);
while (($fixture = array_pop($stack)) !== null) {
if ($fixture instanceof Fixture) {
$class = get_class($fixture);
$name = isset($aliases[$class]) ? $aliases[$class] : $class;
unset($instances[$name]); // unset so that the fixture is added to the last in the next line
$instances[$name] = $fixture;
} else {
$class = ltrim($fixture['class'], '\\');
$name = isset($aliases[$class]) ? $aliases[$class] : $class;
if (!isset($instances[$name])) {
$instances[$name] = false;
$stack[] = $fixture = Yii::createObject($fixture);
foreach ($fixture->depends as $dep) {
// need to use the configuration provided in test case
$stack[] = isset($config[$dep]) ? $config[$dep] : ['class' => $dep];
}
} elseif ($instances[$name] === false) {
throw new InvalidConfigException("A circular dependency is detected for fixture '$class'.");
}
}
}
return $instances;
}
}

View File

@@ -0,0 +1,99 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\test;
use Yii;
/**
* InitDbFixture represents the initial state needed for DB-related tests.
*
* Its main task is to toggle integrity check of the database during data loading.
* This is needed by other DB-related fixtures (e.g. [[ActiveFixture]]) so that they can populate
* data into the database without triggering integrity check errors.
*
* Besides, DbFixture also attempts to load an [[initScript|initialization script]] if it exists.
*
* You should normally use InitDbFixture to prepare a skeleton test database.
* Other DB fixtures will then add specific tables and data to this database.
*
* For more details and usage information on InitDbFixture, see the [guide article on fixtures](guide:test-fixtures).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class InitDbFixture extends DbFixture
{
/**
* @var string the init script file that should be executed when loading this fixture.
* This should be either a file path or [path alias](guide:concept-aliases). Note that if the file does not exist,
* no error will be raised.
*/
public $initScript = '@app/tests/fixtures/initdb.php';
/**
* @var array list of database schemas that the test tables may reside in. Defaults to
* `['']`, meaning using the default schema (an empty string refers to the
* default schema). This property is mainly used when turning on and off integrity checks
* so that fixture data can be populated into the database without causing problem.
*/
public $schemas = [''];
/**
* {@inheritdoc}
*/
public function beforeLoad()
{
$this->checkIntegrity(false);
}
/**
* {@inheritdoc}
*/
public function afterLoad()
{
$this->checkIntegrity(true);
}
/**
* {@inheritdoc}
*/
public function load()
{
$file = Yii::getAlias($this->initScript);
if (is_file($file)) {
require $file;
}
}
/**
* {@inheritdoc}
*/
public function beforeUnload()
{
$this->checkIntegrity(false);
}
/**
* {@inheritdoc}
*/
public function afterUnload()
{
$this->checkIntegrity(true);
}
/**
* Toggles the DB integrity check.
* @param bool $check whether to turn on or off the integrity check.
*/
public function checkIntegrity($check)
{
foreach ($this->schemas as $schema) {
$this->db->createCommand()->checkIntegrity($check, $schema)->execute();
}
}
}