<?php /** * PHP Unit test suite for Magento * * NOTICE OF LICENSE * * This source file is subject to the Open Software License (OSL 3.0) * that is bundled with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://opensource.org/licenses/osl-3.0.php * * @category EcomDev * @package EcomDev_PHPUnit * @copyright Copyright (c) 2013 EcomDev BV (http://www.ecomdev.org) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org> */ /** * Fixture model for Magento unit tests * * Created for operations with different fixture types * */ class EcomDev_PHPUnit_Model_Fixture extends Varien_Object implements EcomDev_PHPUnit_Model_Fixture_Interface { // Configuration path for eav loaders /* @deprecated since 0.3.0 */ const XML_PATH_FIXTURE_EAV_LOADERS = EcomDev_PHPUnit_Model_Fixture_Processor_Eav::XML_PATH_FIXTURE_EAV_LOADERS; // Processors configuration path const XML_PATH_FIXTURE_PROCESSORS = 'phpunit/suite/fixture/processors'; // Configuration path for attribute loaders const XML_PATH_FIXTURE_ATTRIBUTE_LOADERS = 'phpunit/suite/fixture/attribute'; // Default attribute loader class alias const DEFAULT_ATTRIBUTE_LOADER_CLASS = 'ecomdev_phpunit/fixture_attribute_default'; // Default eav loader class node in loaders configuration /* @deprecated since 0.3.0 */ const DEFAULT_EAV_LOADER_NODE = EcomDev_PHPUnit_Model_Fixture_Processor_Eav::DEFAULT_EAV_LOADER_NODE; // Default shared fixture name const DEFAULT_SHARED_FIXTURE_NAME = 'default'; // Default eav loader class alias /* @deprecated since 0.3.0 */ const DEFAULT_EAV_LOADER_CLASS = EcomDev_PHPUnit_Model_Fixture_Processor_Eav::DEFAULT_EAV_LOADER_CLASS; // Key for storing fixture data into storage const STORAGE_KEY_FIXTURE = 'fixture'; // Key for loaded tables into database /* @deprecated since 0.3.0 */ const STORAGE_KEY_TABLES = EcomDev_PHPUnit_Model_Fixture_Processor_Tables::STORAGE_KEY; // Key for loaded entities by EAV loaders /* @deprecated since 0.3.0 */ const STORAGE_KEY_ENTITIES = EcomDev_PHPUnit_Model_Fixture_Processor_Eav::STORAGE_KEY; // Key for loaded cache options /* @deprecated since 0.3.0 */ const STORAGE_KEY_CACHE_OPTIONS = EcomDev_PHPUnit_Model_Fixture_Processor_Cache::STORAGE_KEY; // Key for created scope models /* @deprecated since 0.3.0 */ const STORAGE_KEY_SCOPE = EcomDev_PHPUnit_Model_Fixture_Processor_Scope::STORAGE_KEY; /** * Fixtures array, contains config, * table and eav keys. * Each of them loads data into its area. * * @example * array( * 'config' => array( * 'node/path' => 'value' * ), * 'table' => array( * 'tablename' => array( * array( * 'column1' => 'value' * 'column2' => 'value' * 'column3' => 'value' * ), // row 1 * array( * 'column1' => 'value' * 'column2' => 'value' * 'column3' => 'value' * ) // row 2 * ) * ) * * ) * * @var array */ protected $_fixture = array(); /** * Storage object, for storing data between tests * * @var Varien_Object */ protected $_storage = null; /** * Scope of the fixture, * used for different logic depending on * * @var string */ protected $_scope = self::SCOPE_LOCAL; /** * Fixture options * * @var array */ protected $_options = array(); /** * Processors list * * @var EcomDev_PHPUnit_Model_Fixture_Processor_Interface[] */ protected $_processors = array(); /** * List of scope model aliases by scope type * * @var array * @deprecated since 0.3.0 */ protected static $_scopeModelByType = array(); /** * Associative array of configuration nodes xml that was changed by fixture, * it is used to preserve * @deprecated since 0.2.1 * * @var array */ protected $_originalConfigurationXml = array(); /** * Hash of current scope instances (store, website, group) * * @deprecated since 0.2.1 * @return array */ protected $_currentScope = array(); /** * Set fixture options * * @param array $options * @return EcomDev_PHPUnit_Model_Fixture */ public function setOptions(array $options) { $this->_options = $options; return $this; } /** * Retrieve fixture options * * @return array */ public function getOptions() { return $this->_options; } /** * Sets storage for fixtures * * @param Varien_Object $storage * @return EcomDev_PHPUnit_Model_Fixture */ public function setStorage(Varien_Object $storage) { $this->_storage = $storage; return $this; } /** * Retrieve fixture storage * * @return Varien_Object */ public function getStorage() { return $this->_storage; } /** * Retrieves storage data for a particular fixture scope * * @param string $key * @param string|null $scope * @return mixed */ public function getStorageData($key, $scope = null) { if ($scope === null) { $scope = $this->getScope(); } $dataKey = sprintf('%s_%s', $scope, $key); return $this->getStorage()->getData($dataKey); } /** * Sets storage data for a particular fixture scope * * @param string $key * @param mixed $value * @param string|null $scope * @return EcomDev_PHPUnit_Model_Fixture */ public function setStorageData($key, $value, $scope = null) { if ($scope === null) { $scope = $this->getScope(); } $dataKey = sprintf('%s_%s', $scope, $key); $this->getStorage()->setData($dataKey, $value); return $this; } /** * Returns current fixture scope * * @return string */ public function getScope() { return $this->_scope; } /** * Sets current fixture scope * * @param string $scope EcomDev_PHPUnit_Model_Fixture_Interface::SCOPE_LOCAL|EcomDev_PHPUnit_Model_Fixture_Interface::SCOPE_SHARED * @return EcomDev_PHPUnit_Model_Fixture */ public function setScope($scope) { $this->_scope = $scope; return $this; } /** * Check that current fixture scope is equal to SCOPE_SHARED * * @return boolean */ public function isScopeShared() { return $this->getScope() === self::SCOPE_SHARED; } /** * Check that current fixture scope is equal to SCOPE_LOCAL * * @return boolean */ public function isScopeLocal() { return $this->getScope() === self::SCOPE_LOCAL; } /** * Check that current fixture scope is equal to SCOPE_DEFAULT * * @return boolean */ public function isScopeDefault() { return $this->getScope() === self::SCOPE_DEFAULT; } /** * Loads fixture files from test case annotations * * @param PHPUnit_Framework_TestCase $testCase * @return PHPUnit_Framework_TestCase */ public function loadByTestCase(PHPUnit_Framework_TestCase $testCase) { $fixtures = EcomDev_PHPUnit_Test_Case_Util::getAnnotationByNameFromClass( get_class($testCase), 'loadFixture', array('class', 'method'), $testCase->getName(false) ); $this->_loadFixtureFiles($fixtures, $testCase); return $this; } /** * Loads fixture files from test class annotations * * @param string $className * @return EcomDev_PHPUnit_Model_Fixture */ public function loadForClass($className) { $fixtures = EcomDev_PHPUnit_Test_Case_Util::getAnnotationByNameFromClass( $className, 'loadSharedFixture', 'class' ); $this->_loadFixtureFiles($fixtures, $className); return $this; } /** * Loads test case cache on off annotations * * @param array $annotations * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _parseCacheOptions($annotations) { return $this; } /** * Sets fixture value * * @param string $key * @param array[] $value * * @return EcomDev_PHPUnit_Model_Fixture */ public function setFixtureValue($key, $value) { $this->_fixture[$key] = $value; return $this; } /** * Returns value from fixture * * @param $key * @return array[] */ public function getFixtureValue($key) { if (isset($this->_fixture[$key])) { return $this->_fixture[$key]; } return array(); } /** * Loads fixture files * * @param array $fixtures * @param string|EcomDev_PHPUnit_Test_Case $classOrInstance * * @throws RuntimeException * @return EcomDev_PHPUnit_Model_Fixture */ protected function _loadFixtureFiles(array $fixtures, $classOrInstance) { $isShared = ($this->isScopeShared() || !$classOrInstance instanceof PHPUnit_Framework_TestCase); foreach ($fixtures as $fixture) { if (empty($fixture) && $isShared) { $fixture = self::DEFAULT_SHARED_FIXTURE_NAME; } elseif (empty($fixture)) { $fixture = $classOrInstance->getName(false); } $className = (is_string($classOrInstance) ? $classOrInstance : get_class($classOrInstance)); $filePath = EcomDev_PHPUnit_Test_Case_Util::getYamlLoader() ->resolveFilePath($className, EcomDev_PHPUnit_Model_Yaml_Loader::TYPE_FIXTURE, $fixture); if (!$filePath) { throw new RuntimeException('Unable to load fixture for test: '.$fixture); } $this->loadYaml($filePath); } return $this; } /** * Load YAML file * * @param string $filePath * @return EcomDev_PHPUnit_Model_Fixture * @throws InvalidArgumentException if file is not a valid YAML file */ public function loadYaml($filePath) { $data = EcomDev_PHPUnit_Test_Case_Util::getYamlLoader()->load($filePath); if (empty($this->_fixture)) { $this->_fixture = $data; } else { $this->_fixture = array_merge_recursive($this->_fixture, $data); } return $this; } /** * Returns list of available processors for fixture * * @return EcomDev_PHPUnit_Model_Fixture_Processor_Interface[] */ public function getProcessors() { if (empty($this->_processors)) { $processorsNode = Mage::getConfig()->getNode(self::XML_PATH_FIXTURE_PROCESSORS); foreach ($processorsNode->children() as $code => $processorAlias) { $processor = Mage::getSingleton((string)$processorAlias); if ($processor instanceof EcomDev_PHPUnit_Model_Fixture_Processor_Interface) { $this->_processors[$code] = $processor; } } } return $this->_processors; } /** * Applies loaded fixture * * @return EcomDev_PHPUnit_Model_Fixture */ public function apply() { $processors = $this->getProcessors(); // Initialize fixture processors foreach ($processors as $processor) { $processor->initialize($this); } $this->setStorageData(self::STORAGE_KEY_FIXTURE, $this->_fixture); foreach ($this->_fixture as $part => $data) { if (isset($processors[$part])) { $processors[$part]->apply($data, $part, $this); } } // Clear fixture for getting rid of double processing $this->_fixture = array(); return $this; } /** * Reverts environment to previous state * * @return EcomDev_PHPUnit_Model_Fixture */ public function discard() { $fixture = $this->getStorageData(self::STORAGE_KEY_FIXTURE); if (!is_array($fixture)) { $fixture = array(); } $this->_fixture = $fixture; $this->setStorageData(self::STORAGE_KEY_FIXTURE, null); $processors = $this->getProcessors(); foreach ($this->_fixture as $part => $data) { if (isset($processors[$part])) { $processors[$part]->discard($data, $part, $this); } } $this->_fixture = array(); } /** * Applies cache options for current test or test case * * @param array $options * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _applyCacheOptions($options) { return $this; } /** * Discards changes that were made to Magento cache * * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _discardCacheOptions() { return $this; } /** * Applies fixture configuration values into Mage_Core_Model_Config * * @param array $configuration * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 * @throws InvalidArgumentException in case if wrong configuration array supplied */ protected function _applyConfig($configuration) { return $this; } /** * Applies raw xml data to config node * * @param array $configuration * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 * @throws InvalidArgumentException in case of wrong configuration data passed */ protected function _applyConfigXml($configuration) { return $this; } /** * Restores config to a previous configuration scope * * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _restoreConfig() { return $this; } /** * Reverts fixture configuration values in Mage_Core_Model_Config * * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _discardConfig() { return $this; } /** * Reverts fixture configuration xml values in Mage_Core_Model_Config * * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _discardConfigXml() { return $this; } /** * Applies table data into test database * * @param array $tables * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _applyTables($tables) { return $this; } /** * Removes table data from test data base * * @param array $tables * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _discardTables($tables) { return $this; } /** * Setting config value with applying the values to stores and websites * * @param string $path * @param string $value * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _setConfigNodeValue($path, $value) { return $this; } /** * Retrieves eav loader for a particular entity type * * @param string $entityType * @return EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract * @deprecated since 0.3.0 */ protected function _getEavLoader($entityType) { return $this->_getComplexLoader($entityType, 'EAV'); } /** * Retrieves the loader for a particular entity type and data type * * @throws InvalidArgumentException * @param string $entityType * @param string $dataType * @return EcomDev_PHPUnit_Model_Mysql4_Fixture * @deprecated since 0.3.0 */ protected function _getComplexLoader($entityType, $dataType) { if(!$dataType) { throw new InvalidArgumentException('Must specify a data type for the loader'); } $reflection = EcomDev_Utils_Reflection::getRelflection($this); $loaders = Mage::getConfig()->getNode($reflection->getConstant("XML_PATH_FIXTURE_{$dataType}_LOADERS")); if (isset($loaders->$entityType)) { $classAlias = (string)$loaders->$entityType; } elseif (isset($loaders->{self::DEFAULT_EAV_LOADER_NODE})) { $classAlias = (string)$loaders->{self::DEFAULT_EAV_LOADER_NODE}; } else { $classAlias = self::DEFAULT_EAV_LOADER_CLASS; } return Mage::getResourceSingleton($classAlias); } /** * Applies fixture EAV values * * @param array $entities * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _applyEav($entities) { return $this; } /** * Clean applied eav data * * @param array $entities * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _discardEav($entities) { return $this; } /** * Applies scope fixture, * i.e., website, store, store group * * @param array $types * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _applyScope($types) { return $this; } /** * Handle scope row data * * @param string $type * @param array $row * @return boolean|Mage_Core_Model_Abstract * @deprecated since 0.3.0 */ protected function _handleScopeRow($type, $row) { return false; } /** * Validate scope data * * @param array $types * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _validateScope($types) { return $this; } /** * Removes scope fixture changes, * i.e., website, store, store group * * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _discardScope() { return $this; } /** * Returns VFS wrapper instance * * @return EcomDev_PHPUnit_Model_Fixture_Vfs * @throws PHPUnit_Framework_SkippedTestError */ public function getVfs() { if ($this->_vfs !== null) { return $this->_vfs; } if (is_dir(Mage::getBaseDir('lib') . DS . 'vfsStream' . DS . 'src')) { spl_autoload_register(array($this, 'vfsAutoload'), true, true); } if( class_exists('\org\bovigo\vfs\vfsStream') ){ $this->_vfs = Mage::getModel('ecomdev_phpunit/fixture_vfs'); return $this->_vfs; } throw new PHPUnit_Framework_SkippedTestError( 'The test was skipped, since vfsStream component is not installed. ' . 'Try install submodules required for this functionality' ); } /** * Autoloader for vfs * * @param string $className * @return bool */ public function vfsAutoload($className) { if (strpos($className, 'org\\bovigo\\vfs') === false) { return false; } $fileName = 'vfsStream' . DS . 'src' . DS . 'main' . DS . 'php' . DS . strtr(trim($className, '\\'), '\\', DS) . '.php'; return include $fileName; } /** * Applies VFS structure fixture * * @param array $data * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _applyVfs($data) { return $this; } /** * Discards VFS structure fixture * * @return EcomDev_PHPUnit_Model_Fixture * @deprecated since 0.3.0 */ protected function _discardVfs() { return $this; } }