We will work on Apr 26th (Saturday) and will be off from Apr 30th (Wednesday) until May 2nd (Friday) for public holiday in our country

Commit 03169b5b authored by Ivan Chepurnyi's avatar Ivan Chepurnyi

+ PHPUnit test suite initial version

parent 707b289f
<?php
require 'app/Mage.php';
if (version_compare(PHP_VERSION, '5.3', '<')) {
exit('Magento Unit Tests can be runned only on PHP version over 5.3');
}
if (!Mage::isInstalled()) {
exit('Magento Unit Tests can be runned only on installed version');
}
Mage::app('admin');
Mage::getConfig()->init();
class UnitTests extends EcomDev_PHPUnit_Test_Suite
{
}
<?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) 2011 Ecommerce Developers (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>
*/
/**
* Application model for phpunit tests
*
*/
class EcomDev_PHPUnit_Model_App extends Mage_Core_Model_App
{
// Run types constants,
// Don't know why
// they are not defined in core application
const RUN_TYPE_STORE = 'store';
const RUN_TYPE_WEBSITE = 'website';
const RUN_TYPE_GROUP = 'group';
// Admin store code
const ADMIN_STORE_CODE = 'admin';
/**
* Old configuration model to be returned back
* after unit tests are finished
*
* @var Mage_Core_Model_Config
*/
protected static $_oldConfig = null;
/**
* Old application model to be returned back
* after unit tests are finished
*
* @var Mage_Core_Model_App
*/
protected static $_oldApplication = null;
/**
* Old event collection to be returned back
* after the unit tests are finished
*
* @var Varien_Event_Collection
*/
protected static $_oldEventCollection = null;
/**
* Configuration model class name for unit tests
*
* @var string
*/
protected static $_configClass = 'EcomDev_PHPUnit_Model_Config';
/**
* Configuration model class name for unit tests
*
* @var string
*/
protected static $_eventCollectionClass = 'Varien_Event_Collection';
/**
* Configuration model class name for unit tests
*
* @var string
*/
protected static $_cacheClass = 'EcomDev_PHPUnit_Model_Cache';
/**
* This method replaces application, event and config objects
* in Mage to perform unit tests in separate Magento steam
*
*/
public static function applyTestScope()
{
// Save old environment variables
self::$_oldApplication = EcomDev_Utils_Reflection::getRestrictedPropertyValue('Mage', '_app');
self::$_oldConfig = EcomDev_Utils_Reflection::getRestrictedPropertyValue('Mage', '_config');
self::$_oldEventCollection = EcomDev_Utils_Reflection::getRestrictedPropertyValue('Mage', '_events');
$resource = Mage::getSingleton('core/resource');
// Setting environment variables for unit tests
EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_config', new self::$_configClass);
EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_app', new self);
EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_events', new self::$_eventCollectionClass);
EcomDev_Utils_Reflection::setRestrictedPropertyValue($resource, '_connections', array());
// All unit tests will be runned in admin scope, to get rid of frontend restrictions
Mage::app()->initTest();
}
/**
* Initializes test scope for PHPUnit
*
* @return EcomDev_PHPUnit_Model_App
*/
public function initTest()
{
$this->_config = Mage::getConfig();
$this->_config->setOptions($options);
$this->_initBaseConfig();
$this->_initCache();
$this->getCache()->clean();
// Init modules runs install proccess for table structures,
// It is required for setting up proper setup script
$this->_initModules();
$this->loadAreaPart(Mage_Core_Model_App_Area::AREA_GLOBAL, Mage_Core_Model_App_Area::PART_EVENTS);
if ($this->_config->isLocalConfigLoaded()) {
$this->_initCurrentStore(self::ADMIN_STORE_CODE, self::RUN_TYPE_STORE);
$this->_initRequest();
Mage_Core_Model_Resource_Setup::applyAllDataUpdates();
}
return $this;
}
/**
* Discard test scope for application, returns all the objects from live version
*
*/
public static function discardTestScope()
{
// Setting environment variables for unit tests
EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_app', self::$_oldApplication);
EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_config', self::$_oldConfig);
EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_events', self::$_oldEventCollection);
$resource = Mage::getSingleton('core/resource');
EcomDev_Utils_Reflection::setRestrictedPropertyValue($resource, '_connections', array());
}
/**
* We will not use cache for UnitTests
*
* @return boolean
*/
public function useCache($type=null)
{
return false;
}
}
<?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) 2011 Ecommerce Developers (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>
*/
/**
* Configution model extended to make unit tests to be available
* at separate configuration scope
*
*/
class EcomDev_PHPUnit_Model_Config extends Mage_Core_Model_Config
{
/**
* Loads additional configuration for unit tests
* (non-PHPdoc)
* @see Mage_Core_Model_Config::loadBase()
*/
public function loadBase()
{
parent::loadBase();
$this->_loadTestCacheConfig();
return $this;
}
/**
* (non-PHPdoc)
* @see Mage_Core_Model_Config::loadModules()
*/
public function loadModules()
{
parent::loadModules();
$this->_loadTestConfig();
$this->_loadTestCacheConfig();
return $this;
}
/**
* Loads local.xml.phpunit file
* for overriding DB credentials
*
* @return EcomDev_PHPUnit_Model_Config
*/
protected function _loadTestConfig()
{
$merge = clone $this->_prototype;
if ($merge->loadFile($this->_getLocalXmlForTest())) {
$this->_checkDbCredentialForDuplicate($this, $merge);
$this->extend($merge);
} else {
throw new Exception('Unable to load local.xml.phpunit');
}
return $this;
}
/**
* Loads cache configuration for PHPUnit tests scope
*
* @return EcomDev_PHPUnit_Model_Config
*/
protected function _loadTestCacheConfig()
{
// Cache beckend initialization for unit tests,
// because it should be separate from live one
$this->setNode('global/cache/backend', 'file');
$this->getOptions()->setData('cache_dir', $this->getVarDir() . DS . 'phpunit.cache');
$this->getOptions()->setData('session_dir', $this->getVarDir() . DS . 'phpunit.session');
return $this;
}
/**
* Checks DB credentials for phpunit test case.
* They shouldn't be the same as live ones.
*
* @param Mage_Core_Model_Config_Base $original
* @param Mage_Core_Model_Config_Base $test
* @return EcomDev_PHPUnit_Model_Config
* @throws RuntimeException
*/
protected function _checkDbCredentialForDuplicate($original, $test)
{
$originalDbName = (string) $original->getNode('global/resources/default_setup/connection/dbname');
$testDbName = (string) $test->getNode('global/resources/default_setup/connection/dbname');
if ($originalDbName == $testDbName) {
throw new RuntimeException('Test DB cannot be the same as the live one');
}
return $this;
}
/**
* Retrieves local.xml file path for tests,
* If it is not found, method will rise an exception
*
* @return string
* @throws RuntimeException
*/
protected function _getLocalXmlForTest()
{
$filePath = $this->getOptions()->getEtcDir() . DS . 'local.xml.phpunit';
if (!file_exists($filePath)) {
throw new RuntimeException('There is no local.xml.phpunit file');
}
return $filePath;
}
}
<?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) 2011 Ecommerce Developers (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>
*/
// Loading Spyc yaml parser,
// becuase Symfony component is not working propertly with nested
require_once 'Spyc/spyc.php';
/**
* Fixture model for Magento unit tests
*
* Created for operations with different fixture types
*
*/
class EcomDev_PHPUnit_Model_Fixture extends Mage_Core_Model_Abstract
{
/**
* 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();
/**
* Associative array of configuration values that was changed by fixture,
* it is used to preserve
*
*/
protected $_originalConfiguration = array();
/**
* Model constuctor, just defines wich resource model to use
* (non-PHPdoc)
* @see Varien_Object::_construct()
*/
protected function _construct()
{
$this->_init('ecomdev_phpunit/fixture');
}
/**
* 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 = Spyc::YAMLLoad($filePath);
if (empty($this->_fixture)) {
$this->_fixture = $data;
} else {
$this->_fixture = array_merge_recursive($this->_fixture, $data);
}
return $this;
}
/**
* Applies loaded fixture
*
* @return EcomDev_PHPUnit_Model_Fixture
*/
public function apply()
{
$reflection = EcomDev_Utils_Reflection::getRelflection($this);
foreach ($this->_fixture as $part => $data) {
$method = '_apply' . uc_words($part, '', '_');
if ($reflection->hasMethod($method)) {
$this->$method($data);
}
}
return $this;
}
/**
* Reverts environment to previous state
*
* @return EcomDev_PHPUnit_Model_Fixture
*/
public function discard()
{
$reflection = EcomDev_Utils_Reflection::getRelflection($this);
foreach ($this->_fixture as $part => $data) {
$method = '_discard' . uc_words($part, '', '_');
if ($reflection->hasMethod($method)) {
$this->$method($data);
}
}
$this->_fixture = array();
}
/**
* Applies fixture configuration values into Mage_Core_Model_Config
*
* @param array $configuration
* @return EcomDev_PHPUnit_Model_Fixture
*/
protected function _applyConfig($configuration)
{
if (!is_array($configuration)) {
throw new InvalidArgumentException('Configuration part should be an associative list');
}
foreach ($configuration as $path => $value) {
$this->_originalConfiguration[$path] = Mage::getConfig()->getNode($path);
Mage::getConfig()->setNode($path, $value);
}
return $this;
}
/**
* Reverts fixture configuration values in Mage_Core_Model_Config
*
* @return EcomDev_PHPUnit_Model_Fixture
*/
protected function _discardConfig()
{
foreach ($this->_originalConfiguration as $path => $value) {
Mage::getConfig()->setNode($path, $value);
}
$this->_originalConfiguration = array();
return $this;
}
/**
* Applies table data into test database
*
* @param array $tables
* @return EcomDev_PHPUnit_Model_Fixture
*/
protected function _applyTables($tables)
{
if (!is_array($tables)) {
throw new InvalidArgumentException(
'Tables part should be an associative list with keys as table entity and values as list of associative rows'
);
}
foreach ($tables as $tableEntity => $data) {
$this->getResource()->cleanTable($tableEntity);
$this->getResource()->loadTableData($tableEntity, $data);
}
}
/**
* Removes table data from test data base
*
* @param array $tables
* @return EcomDev_PHPUnit_Model_Fixture
*/
protected function _discardTables($tables)
{
if (!is_array($tables)) {
throw new InvalidArgumentException(
'Tables part should be an associative list with keys as table entity and values as list of associative rows'
);
}
foreach ($tables as $tableEntity => $data) {
$this->getResource()->cleanTable($tableEntity);
}
}
/**
* @todo Create Implementation for EAV models
*/
/**
* @todo Create Implementation for Websites/Stores/Groups
*/
}
<?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) 2011 Ecommerce Developers (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 resource model.
*
* Created for direct operations with DB.
*
*/
class EcomDev_PHPUnit_Model_Mysql4_Fixture extends Mage_Core_Model_Mysql4_Abstract
{
protected function _construct()
{
$this->_setResource('ecomdev_phpunit');
}
/**
* Cleans table in test database
*
* @param string $tableEntity
* @return EcomDev_PHPUnit_Model_Mysql4_Fixture
*/
public function cleanTable($tableEntity)
{
$this->_getWriteAdapter()
->truncate($this->getTable($tableEntity));
return $this;
}
/**
* Loads multiple data rows into table
*
* @param string $tableEntity
* @param array $tableData
*/
public function loadTableData($tableEntity, $tableData)
{
$this->_getWriteAdapter()->insertMultiple(
$this->getTable($tableEntity),
$tableData
);
return $this;
}
}
\ No newline at end of file
<?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) 2011 Ecommerce Developers (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>
*/
// Loading Spyc yaml parser,
// becuase Symfony component is not working propertly with nested associations
require_once 'Spyc/spyc.php';
/**
* Basic test case class
*
*
*/
abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
{
/**
* The expectations for current test are loaded here
*
* @var Varien_Object|null
*/
protected $_expectations = null;
/**
* Loads expectations for current test case
*
* @throws RuntimeException if no expectation was found
* @return Varien_Object
*/
protected function _getExpectations()
{
if ($this->_expectations === null) {
$annotations = $this->getAnnotations();
if (isset($annotations['method']['loadExpectation'])) {
// Load expectation by annotations
$expectations = array();
foreach ($annotations['method']['loadExpectation'] as $expectation) {
if (empty($expectation)) {
$expectation = null;
}
$expectationFile = $this->_getYamlFilePath('expectations', $expectation);
if ($expectationFile) {
$expectations = array_merge_recursive(
$expectations, Spyc::YAMLLoad($expectationFile)
);
} else {
$text = 'There was no expectation defined for current test case';
if ($expectation) {
$text = sprintf('Cannot load expectation %s', $expectation);
}
throw new RuntimeException($test);
}
}
} else {
// Load expectations by test name
$expectationFile = $this->_getYamlFilePath('expectations');
if ($expectationFile) {
$expectations = Spyc::YAMLLoad($expectationFile);
} else {
throw new RuntimeException('There was no expectation defined for current test case');
}
}
$this->_expectations = new Varien_Object($expectations);
}
return $this->_expectations;
}
/**
* Retrieves fixture model singleton
*
* @return EcomDev_PHPUnit_Model_Fixture
*/
protected function _getFixture()
{
return Mage::getSingleton('ecomdev_phpunit/fixture');
}
/**
* Loads YAML file from directory inside of the unit test class
* Enter description here ...
*
* @param string $type type of YAML data (fixtures,expectations,dataproviders)
* @param string|null $name the file name for loading, if equals to null,
* the current test name will be used
* @return string|boolean
*/
protected function _getYamlFilePath($type, $name = null)
{
if ($name === null) {
$name = $this->getName(false);
}
if (strrpos($name, '.yaml') !== strlen($name) - 5) {
$name .= '.yaml';
}
$classFileObject = new SplFileInfo(
EcomDev_Utils_Reflection::getRelflection($this)->getFileName()
);
$filePath = $classFileObject->getPath() . DS
. $classFileObject->getBasename('.php') . DS
. $type . DS . $name;
if (file_exists($filePath)) {
return $filePath;
}
return false;
}
/**
* Initializes a particular test environment
*
* (non-PHPdoc)
* @see PHPUnit_Framework_TestCase::setUp()
*/
protected function setUp()
{
$annotations = $this->getAnnotations();
if (isset($annotations['method']['loadFixture'])) {
foreach ($annotations['method']['loadFixture'] as $fixture) {
if (empty($fixture)) {
$fixture = null;
}
$filePath = $this->_getYamlFilePath('fixtures', $fixture);
if (!$filePath) {
throw new RuntimeException('Unable to load fixture for test');
}
$this->_getFixture()->loadYaml($filePath);
}
}
$this->_getFixture()->apply();
parent::setUp();
}
/**
* Implements default data provider functionality,
* returns array data loaded from Yaml file with the same name as test method
*
* @return array
*/
public function dataProvider($testName)
{
$this->setName($testName);
$filePath = $this->_getYamlFilePath('providers');
$this->setName(null);
if (!$filePath) {
throw new RuntimeException('Unable to load data provider for the current test');
}
return Spyc::YAMLLoad($filePath);
}
/**
* Performs a clean up after a particular test was run
* (non-PHPdoc)
* @see PHPUnit_Framework_TestCase::tearDown()
*/
protected function tearDown()
{
$this->_expectations = null; // Clear expectation values
$this->_getFixture()->discard(); // Clear applied fixture
parent::tearDown();
}
}
\ No newline at end of file
<?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) 2011 Ecommerce Developers (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>
*/
/**
* Test suite for Magento
*
* It discovers all test cases in modules
* if they were added to 'phpunit/suite/modules' configuration node
*
*/
class EcomDev_PHPUnit_Test_Suite extends PHPUnit_Framework_TestSuite
{
// Configuration path constants
const XML_PATH_UNIT_TEST_GROUPS = 'phpunit/suite/groups';
const XML_PATH_UNIT_TEST_MODULES = 'phpunit/suite/modules';
const XML_PATH_UNIT_TEST_APP = 'phpunit/suite/app';
/**
* Setting up test scope for Magento
* (non-PHPdoc)
* @see PHPUnit_Framework_TestSuite::setUp()
*/
protected function setUp()
{
$appClass = (string) Mage::getConfig()->getNode(self::XML_PATH_UNIT_TEST_APP);
$reflectionClass = EcomDev_Utils_Reflection::getRelflection($appClass);
if ($reflectionClass->hasMethod('applyTestScope')) {
$reflectionClass->getMethod('applyTestScope')->invoke(null);
}
}
/**
* Returning Magento to the state before suite was run
* (non-PHPdoc)
* @see PHPUnit_Framework_TestSuite::tearDown()
*/
protected function tearDown()
{
$appClass = (string) Mage::getConfig()->getNode(self::XML_PATH_UNIT_TEST_APP);
$reflectionClass = EcomDev_Utils_Reflection::getRelflection($appClass);
if ($reflectionClass->hasMethod('discardTestScope')) {
$reflectionClass->getMethod('discardTestScope')->invoke(null);
}
}
/**
* This method loads all available test suites for PHPUnit
*
* @return PHPUnit_Framework_TestSuite
*/
public static function suite()
{
$groups = Mage::getConfig()->getNode(self::XML_PATH_UNIT_TEST_GROUPS);
$modules = Mage::getConfig()->getNode(self::XML_PATH_UNIT_TEST_MODULES);
$suite = new self('Magento Test Suite');
// Walk through different groups in modules for finding test cases
foreach ($groups->children() as $group) {
foreach ($modules->children() as $module) {
$realModule = Mage::getConfig()->getNode('modules/' . $module->getName());
if (!$realModule || !$realModule->is('active')) {
$suite->addTest(self::warning('There is no module with name: ' . $module->getName()));
continue;
}
$moduleCodeDir = Mage::getBaseDir('code') . DS . (string) $realModule->codePool;
$searchPath = Mage::getModuleDir('', $module->getName()) . DS . 'Test' . DS . (string) $group;
if (!is_dir($searchPath)) {
continue;
}
$directoryIterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($searchPath)
);
$currentGroups = array(
$group->getName(),
$module->getName()
);
foreach ($directoryIterator as $fileObject) {
/* @var $fileObject SplFileObject */
// Skip entry if it is not a php file
if (!$fileObject->isFile() || $fileObject->getBasename('.php') === $fileObject->getBasename()) {
continue;
}
$classPath = substr($fileObject->getPath() . DS . $fileObject->getBasename('.php'), strlen($moduleCodeDir));
$className = uc_words(ltrim($classPath, DS), '_', DS);
// Add unit test case only
// if it is a valid class extended from EcomDev_PHPUnit_Test_Case
if (class_exists($className, true)) {
$reflectionClass = EcomDev_Utils_Reflection::getRelflection($className);
if (!$reflectionClass->isSubclassOf('EcomDev_PHPUnit_Test_Case')) {
continue;
}
$suite->addTest(new PHPUnit_Framework_TestSuite($reflectionClass), $currentGroups);
}
}
}
}
if (!$suite->count()) {
$suite->addTest(self::warning('There were no test cases for the current run'));
}
return $suite;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* 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) 2011 Ecommerce Developers (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>
*/
-->
<config>
<modules>
<EcomDev_PHPUnit>
<version>0.1.0</version>
</EcomDev_PHPUnit>
</modules>
<global>
<models>
<ecomdev_phpunit>
<class>EcomDev_PHPUnit_Model</class>
<resourceModel>ecomdev_phpunit_mysql4</resourceModel>
</ecomdev_phpunit>
<ecomdev_phpunit_mysql4>
<class>EcomDev_PHPUnit_Model_Mysql4</class>
</ecomdev_phpunit_mysql4>
</models>
</global>
<phpunit>
<suite>
<!-- The names of directories inside Test for recognizion of tests per group -->
<groups>
<models>Model</models>
<helpers>Helper</helpers>
<blocks>Block</blocks>
</groups>
<!-- Application model class name for running tests -->
<app>EcomDev_PHPUnit_Model_App</app>
<modules>
<!-- Place your module name in your module config.xml
For adding it to test suite -->
<!-- Example:
<Namespace_MyModule />
-->
</modules>
</suite>
</phpunit>
</config>
<?xml version="1.0"?>
<config>
<global>
<resources>
<default_setup>
<connection>
<dbname><![CDATA[magento_unit_tests]]></dbname>
</connection>
</default_setup>
</resources>
</global>
</config>
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* 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) 2010 Ecommerce Developers (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>
*/
-->
<config>
<modules>
<EcomDev_PHPUnit>
<codePool>community</codePool>
<active>true</active>
</EcomDev_PHPUnit>
</modules>
</config>
\ No newline at end of file
<?php
class EcomDev_Utils_Reflection
{
/**
* Cache of reflection objects
*
* @var array
*/
protected static $_reflectionCache = array();
/**
* Sets protected or private property value
*
* @param string|object $object class name
* @param string $property
* @param mixed $value
*/
public static function setRestrictedPropertyValue($object, $property, $value)
{
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
throw new RuntimeException('For setting of restricted properties via Reflection, PHP version should be 5.3.0 or later');
}
$reflectionObject = self::getRelflection($object);
$reflectionProperty = $reflectionObject->getProperty($property);
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue((is_string($object) ? null : $object), $value);
}
/**
* Gets protected or private property value
*
* @param string|object $object class name
* @param string $property
* @return mixed
*/
public static function getRestrictedPropertyValue($object, $property)
{
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
throw new RuntimeException('For getting of restricted properties via Reflection, PHP version should be 5.3.0 or later');
}
$reflectionObject = self::getRelflection($object);
$reflectionProperty = $reflectionObject->getProperty($property);
$reflectionProperty->setAccessible(true);
return $reflectionProperty->getValue((is_string($object) ? null : $object));
}
/**
* Calls private or protected method
*
* @param string|object $object
* @param string $method
* @param array $args
* @return mixed
*/
public static function invokeRestrictedMethod($object, $method, $args = array())
{
if (version_compare(PHP_VERSION, '5.3.2', '<')) {
throw new RuntimeException('For invoking restricted methods via Reflection, PHP version should be 5.3.2 or later');
}
$reflectionObject = self::getRelflection($object);
$reflectionMethod = $reflectionObject->getMethod($method);
$reflectionMethod->setAccessible(true);
if (!empty($args)) {
return $reflectionMethod->invokeArgs($reflectionObject, $args);
}
return $reflectionMethod->invoke((is_string($object) ? null : $object));
}
/**
* Returns reflection object from instance or class name
*
* @param string|object $object
* @return ReflectionClass|ReflectionObject
*/
public static function getRelflection($object)
{
// If object is a class name
if (is_string($object) && class_exists($object)) {
if (isset(self::$_reflectionCache[$object])) {
return self::$_reflectionCache[$object];
}
$reflection = new ReflectionClass($object);
self::$_reflectionCache[$object] = $reflection;
return $reflection;
}
// If object is an instance of a class
elseif (is_object($object)) {
$objectHash = spl_object_hash($object);
if (isset(self::$_reflectionCache[$objectHash])) {
return self::$_reflectionCache[$objectHash];
}
$reflection = new ReflectionClass($object);
self::$_reflectionCache[$objectHash] = $reflection;
return $reflection;
}
// In case of invalid argument
else {
throw new InvalidArgumentException('$object should be a valid class name or object instance');
}
}
}
\ No newline at end of file
<?php
/**
* Spyc -- A Simple PHP YAML Class
* @version 0.4.5
* @author Vlad Andersen <vlad.andersen@gmail.com>
* @author Chris Wanstrath <chris@ozmm.org>
* @link http://code.google.com/p/spyc/
* @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2009 Vlad Andersen
* @license http://www.opensource.org/licenses/mit-license.php MIT License
* @package Spyc
*/
if (!function_exists('spyc_load')) {
/**
* Parses YAML to array.
* @param string $string YAML string.
* @return array
*/
function spyc_load ($string) {
return Spyc::YAMLLoadString($string);
}
}
if (!function_exists('spyc_load_file')) {
/**
* Parses YAML to array.
* @param string $file Path to YAML file.
* @return array
*/
function spyc_load_file ($file) {
return Spyc::YAMLLoad($file);
}
}
/**
* The Simple PHP YAML Class.
*
* This class can be used to read a YAML file and convert its contents
* into a PHP array. It currently supports a very limited subsection of
* the YAML spec.
*
* Usage:
* <code>
* $Spyc = new Spyc;
* $array = $Spyc->load($file);
* </code>
* or:
* <code>
* $array = Spyc::YAMLLoad($file);
* </code>
* or:
* <code>
* $array = spyc_load_file($file);
* </code>
* @package Spyc
*/
class Spyc {
// SETTINGS
/**
* Setting this to true will force YAMLDump to enclose any string value in
* quotes. False by default.
*
* @var bool
*/
public $setting_dump_force_quotes = false;
/**
* Setting this to true will forse YAMLLoad to use syck_load function when
* possible. False by default.
* @var bool
*/
public $setting_use_syck_is_possible = false;
/**#@+
* @access private
* @var mixed
*/
private $_dumpIndent;
private $_dumpWordWrap;
private $_containsGroupAnchor = false;
private $_containsGroupAlias = false;
private $path;
private $result;
private $LiteralPlaceHolder = '___YAML_Literal_Block___';
private $SavedGroups = array();
private $indent;
/**
* Path modifier that should be applied after adding current element.
* @var array
*/
private $delayedPath = array();
/**#@+
* @access public
* @var mixed
*/
public $_nodeId;
/**
* Load a valid YAML string to Spyc.
* @param string $input
* @return array
*/
public function load ($input) {
return $this->__loadString($input);
}
/**
* Load a valid YAML file to Spyc.
* @param string $file
* @return array
*/
public function loadFile ($file) {
return $this->__load($file);
}
/**
* Load YAML into a PHP array statically
*
* The load method, when supplied with a YAML stream (string or file),
* will do its best to convert YAML in a file into a PHP array. Pretty
* simple.
* Usage:
* <code>
* $array = Spyc::YAMLLoad('lucky.yaml');
* print_r($array);
* </code>
* @access public
* @return array
* @param string $input Path of YAML file or string containing YAML
*/
public static function YAMLLoad($input) {
$Spyc = new Spyc;
return $Spyc->__load($input);
}
/**
* Load a string of YAML into a PHP array statically
*
* The load method, when supplied with a YAML string, will do its best
* to convert YAML in a string into a PHP array. Pretty simple.
*
* Note: use this function if you don't want files from the file system
* loaded and processed as YAML. This is of interest to people concerned
* about security whose input is from a string.
*
* Usage:
* <code>
* $array = Spyc::YAMLLoadString("---\n0: hello world\n");
* print_r($array);
* </code>
* @access public
* @return array
* @param string $input String containing YAML
*/
public static function YAMLLoadString($input) {
$Spyc = new Spyc;
return $Spyc->__loadString($input);
}
/**
* Dump YAML from PHP array statically
*
* The dump method, when supplied with an array, will do its best
* to convert the array into friendly YAML. Pretty simple. Feel free to
* save the returned string as nothing.yaml and pass it around.
*
* Oh, and you can decide how big the indent is and what the wordwrap
* for folding is. Pretty cool -- just pass in 'false' for either if
* you want to use the default.
*
* Indent's default is 2 spaces, wordwrap's default is 40 characters. And
* you can turn off wordwrap by passing in 0.
*
* @access public
* @return string
* @param array $array PHP array
* @param int $indent Pass in false to use the default, which is 2
* @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
*/
public static function YAMLDump($array,$indent = false,$wordwrap = false) {
$spyc = new Spyc;
return $spyc->dump($array,$indent,$wordwrap);
}
/**
* Dump PHP array to YAML
*
* The dump method, when supplied with an array, will do its best
* to convert the array into friendly YAML. Pretty simple. Feel free to
* save the returned string as tasteful.yaml and pass it around.
*
* Oh, and you can decide how big the indent is and what the wordwrap
* for folding is. Pretty cool -- just pass in 'false' for either if
* you want to use the default.
*
* Indent's default is 2 spaces, wordwrap's default is 40 characters. And
* you can turn off wordwrap by passing in 0.
*
* @access public
* @return string
* @param array $array PHP array
* @param int $indent Pass in false to use the default, which is 2
* @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
*/
public function dump($array,$indent = false,$wordwrap = false) {
// Dumps to some very clean YAML. We'll have to add some more features
// and options soon. And better support for folding.
// New features and options.
if ($indent === false or !is_numeric($indent)) {
$this->_dumpIndent = 2;
} else {
$this->_dumpIndent = $indent;
}
if ($wordwrap === false or !is_numeric($wordwrap)) {
$this->_dumpWordWrap = 40;
} else {
$this->_dumpWordWrap = $wordwrap;
}
// New YAML document
$string = "---\n";
// Start at the base of the array and move through it.
if ($array) {
$array = (array)$array;
$first_key = key($array);
$previous_key = -1;
foreach ($array as $key => $value) {
$string .= $this->_yamlize($key,$value,0,$previous_key, $first_key);
$previous_key = $key;
}
}
return $string;
}
/**
* Attempts to convert a key / value array item to YAML
* @access private
* @return string
* @param $key The name of the key
* @param $value The value of the item
* @param $indent The indent of the current node
*/
private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0) {
if (is_array($value)) {
if (empty ($value))
return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key);
// It has children. What to do?
// Make it the right kind of item
$string = $this->_dumpNode($key, NULL, $indent, $previous_key, $first_key);
// Add the indent
$indent += $this->_dumpIndent;
// Yamlize the array
$string .= $this->_yamlizeArray($value,$indent);
} elseif (!is_array($value)) {
// It doesn't have children. Yip.
$string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key);
}
return $string;
}
/**
* Attempts to convert an array to YAML
* @access private
* @return string
* @param $array The array you want to convert
* @param $indent The indent of the current level
*/
private function _yamlizeArray($array,$indent) {
if (is_array($array)) {
$string = '';
$previous_key = -1;
$first_key = key($array);
foreach ($array as $key => $value) {
$string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key);
$previous_key = $key;
}
return $string;
} else {
return false;
}
}
/**
* Returns YAML from a key and a value
* @access private
* @return string
* @param $key The name of the key
* @param $value The value of the item
* @param $indent The indent of the current node
*/
private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0) {
// do some folding here, for blocks
if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false ||
strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false ||
strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || substr ($value, -1, 1) == ':')) {
$value = $this->_doLiteralBlock($value,$indent);
} else {
$value = $this->_doFolding($value,$indent);
if (is_bool($value)) {
$value = ($value) ? "true" : "false";
}
}
if ($value === array()) $value = '[ ]';
$spaces = str_repeat(' ',$indent);
if (is_int($key) && $key - 1 == $previous_key && $first_key===0) {
// It's a sequence
$string = $spaces.'- '.$value."\n";
} else {
if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"');
// It's mapped
if (strpos($key, ":") !== false) { $key = '"' . $key . '"'; }
$string = $spaces.$key.': '.$value."\n";
}
return $string;
}
/**
* Creates a literal block for dumping
* @access private
* @return string
* @param $value
* @param $indent int The value of the indent
*/
private function _doLiteralBlock($value,$indent) {
if (strpos($value, "\n") === false && strpos($value, "'") === false) {
return sprintf ("'%s'", $value);
}
if (strpos($value, "\n") === false && strpos($value, '"') === false) {
return sprintf ('"%s"', $value);
}
$exploded = explode("\n",$value);
$newValue = '|';
$indent += $this->_dumpIndent;
$spaces = str_repeat(' ',$indent);
foreach ($exploded as $line) {
$newValue .= "\n" . $spaces . trim($line);
}
return $newValue;
}
/**
* Folds a string of text, if necessary
* @access private
* @return string
* @param $value The string you wish to fold
*/
private function _doFolding($value,$indent) {
// Don't do anything if wordwrap is set to 0
if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) {
$indent += $this->_dumpIndent;
$indent = str_repeat(' ',$indent);
$wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent");
$value = ">\n".$indent.$wrapped;
} else {
if ($this->setting_dump_force_quotes && is_string ($value))
$value = '"' . $value . '"';
}
return $value;
}
// LOADING FUNCTIONS
private function __load($input) {
$Source = $this->loadFromSource($input);
return $this->loadWithSource($Source);
}
private function __loadString($input) {
$Source = $this->loadFromString($input);
return $this->loadWithSource($Source);
}
private function loadWithSource($Source) {
if (empty ($Source)) return array();
if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) {
$array = syck_load (implode ('', $Source));
return is_array($array) ? $array : array();
}
$this->path = array();
$this->result = array();
$cnt = count($Source);
for ($i = 0; $i < $cnt; $i++) {
$line = $Source[$i];
$this->indent = strlen($line) - strlen(ltrim($line));
$tempPath = $this->getParentPathByIndent($this->indent);
$line = self::stripIndent($line, $this->indent);
if (self::isComment($line)) continue;
if (self::isEmpty($line)) continue;
$this->path = $tempPath;
$literalBlockStyle = self::startsLiteralBlock($line);
if ($literalBlockStyle) {
$line = rtrim ($line, $literalBlockStyle . " \n");
$literalBlock = '';
$line .= $this->LiteralPlaceHolder;
while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) {
$literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle);
}
$i--;
}
while (++$i < $cnt && self::greedilyNeedNextLine($line)) {
$line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t");
}
$i--;
if (strpos ($line, '#')) {
if (strpos ($line, '"') === false && strpos ($line, "'") === false)
$line = preg_replace('/\s+#(.+)$/','',$line);
}
$lineArray = $this->_parseLine($line);
if ($literalBlockStyle)
$lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock);
$this->addArray($lineArray, $this->indent);
foreach ($this->delayedPath as $indent => $delayedPath)
$this->path[$indent] = $delayedPath;
$this->delayedPath = array();
}
return $this->result;
}
private function loadFromSource ($input) {
if (!empty($input) && strpos($input, "\n") === false && file_exists($input))
return file($input);
return $this->loadFromString($input);
}
private function loadFromString ($input) {
$lines = explode("\n",$input);
foreach ($lines as $k => $_) {
$lines[$k] = rtrim ($_, "\r");
}
return $lines;
}
/**
* Parses YAML code and returns an array for a node
* @access private
* @return array
* @param string $line A line from the YAML file
*/
private function _parseLine($line) {
if (!$line) return array();
$line = trim($line);
if (!$line) return array();
$array = array();
$group = $this->nodeContainsGroup($line);
if ($group) {
$this->addGroup($line, $group);
$line = $this->stripGroup ($line, $group);
}
if ($this->startsMappedSequence($line))
return $this->returnMappedSequence($line);
if ($this->startsMappedValue($line))
return $this->returnMappedValue($line);
if ($this->isArrayElement($line))
return $this->returnArrayElement($line);
if ($this->isPlainArray($line))
return $this->returnPlainArray($line);
return $this->returnKeyValuePair($line);
}
/**
* Finds the type of the passed value, returns the value as the new type.
* @access private
* @param string $value
* @return mixed
*/
private function _toType($value) {
if ($value === '') return null;
$first_character = $value[0];
$last_character = substr($value, -1, 1);
$is_quoted = false;
do {
if (!$value) break;
if ($first_character != '"' && $first_character != "'") break;
if ($last_character != '"' && $last_character != "'") break;
$is_quoted = true;
} while (0);
if ($is_quoted)
return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\''));
if (strpos($value, ' #') !== false)
$value = preg_replace('/\s+#(.+)$/','',$value);
if ($first_character == '[' && $last_character == ']') {
// Take out strings sequences and mappings
$innerValue = trim(substr ($value, 1, -1));
if ($innerValue === '') return array();
$explode = $this->_inlineEscape($innerValue);
// Propagate value array
$value = array();
foreach ($explode as $v) {
$value[] = $this->_toType($v);
}
return $value;
}
if (strpos($value,': ')!==false && $first_character != '{') {
$array = explode(': ',$value);
$key = trim($array[0]);
array_shift($array);
$value = trim(implode(': ',$array));
$value = $this->_toType($value);
return array($key => $value);
}
if ($first_character == '{' && $last_character == '}') {
$innerValue = trim(substr ($value, 1, -1));
if ($innerValue === '') return array();
// Inline Mapping
// Take out strings sequences and mappings
$explode = $this->_inlineEscape($innerValue);
// Propagate value array
$array = array();
foreach ($explode as $v) {
$SubArr = $this->_toType($v);
if (empty($SubArr)) continue;
if (is_array ($SubArr)) {
$array[key($SubArr)] = $SubArr[key($SubArr)]; continue;
}
$array[] = $SubArr;
}
return $array;
}
if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') {
return null;
}
if (intval($first_character) > 0 && preg_match ('/^[1-9]+[0-9]*$/', $value)) {
$intvalue = (int)$value;
if ($intvalue != PHP_INT_MAX)
$value = $intvalue;
return $value;
}
if (in_array($value,
array('true', 'on', '+', 'yes', 'y', 'True', 'TRUE', 'On', 'ON', 'YES', 'Yes', 'Y'))) {
return true;
}
if (in_array(strtolower($value),
array('false', 'off', '-', 'no', 'n'))) {
return false;
}
if (is_numeric($value)) {
if ($value === '0') return 0;
if (trim ($value, 0) === $value)
$value = (float)$value;
return $value;
}
return $value;
}
/**
* Used in inlines to check for more inlines or quoted strings
* @access private
* @return array
*/
private function _inlineEscape($inline) {
// There's gotta be a cleaner way to do this...
// While pure sequences seem to be nesting just fine,
// pure mappings and mappings with sequences inside can't go very
// deep. This needs to be fixed.
$seqs = array();
$maps = array();
$saved_strings = array();
// Check for strings
$regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/';
if (preg_match_all($regex,$inline,$strings)) {
$saved_strings = $strings[0];
$inline = preg_replace($regex,'YAMLString',$inline);
}
unset($regex);
$i = 0;
do {
// Check for sequences
while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) {
$seqs[] = $matchseqs[0];
$inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1);
}
// Check for mappings
while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) {
$maps[] = $matchmaps[0];
$inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1);
}
if ($i++ >= 10) break;
} while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false);
$explode = explode(', ',$inline);
$stringi = 0; $i = 0;
while (1) {
// Re-add the sequences
if (!empty($seqs)) {
foreach ($explode as $key => $value) {
if (strpos($value,'YAMLSeq') !== false) {
foreach ($seqs as $seqk => $seq) {
$explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value);
$value = $explode[$key];
}
}
}
}
// Re-add the mappings
if (!empty($maps)) {
foreach ($explode as $key => $value) {
if (strpos($value,'YAMLMap') !== false) {
foreach ($maps as $mapk => $map) {
$explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value);
$value = $explode[$key];
}
}
}
}
// Re-add the strings
if (!empty($saved_strings)) {
foreach ($explode as $key => $value) {
while (strpos($value,'YAMLString') !== false) {
$explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1);
unset($saved_strings[$stringi]);
++$stringi;
$value = $explode[$key];
}
}
}
$finished = true;
foreach ($explode as $key => $value) {
if (strpos($value,'YAMLSeq') !== false) {
$finished = false; break;
}
if (strpos($value,'YAMLMap') !== false) {
$finished = false; break;
}
if (strpos($value,'YAMLString') !== false) {
$finished = false; break;
}
}
if ($finished) break;
$i++;
if ($i > 10)
break; // Prevent infinite loops.
}
return $explode;
}
private function literalBlockContinues ($line, $lineIndent) {
if (!trim($line)) return true;
if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true;
return false;
}
private function referenceContentsByAlias ($alias) {
do {
if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; }
$groupPath = $this->SavedGroups[$alias];
$value = $this->result;
foreach ($groupPath as $k) {
$value = $value[$k];
}
} while (false);
return $value;
}
private function addArrayInline ($array, $indent) {
$CommonGroupPath = $this->path;
if (empty ($array)) return false;
foreach ($array as $k => $_) {
$this->addArray(array($k => $_), $indent);
$this->path = $CommonGroupPath;
}
return true;
}
private function addArray ($incoming_data, $incoming_indent) {
// print_r ($incoming_data);
if (count ($incoming_data) > 1)
return $this->addArrayInline ($incoming_data, $incoming_indent);
$key = key ($incoming_data);
$value = isset($incoming_data[$key]) ? $incoming_data[$key] : null;
if ($key === '__!YAMLZero') $key = '0';
if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values.
if ($key || $key === '' || $key === '0') {
$this->result[$key] = $value;
} else {
$this->result[] = $value; end ($this->result); $key = key ($this->result);
}
$this->path[$incoming_indent] = $key;
return;
}
$history = array();
// Unfolding inner array tree.
$history[] = $_arr = $this->result;
foreach ($this->path as $k) {
$history[] = $_arr = $_arr[$k];
}
if ($this->_containsGroupAlias) {
$value = $this->referenceContentsByAlias($this->_containsGroupAlias);
$this->_containsGroupAlias = false;
}
// Adding string or numeric key to the innermost level or $this->arr.
if (is_string($key) && $key == '<<') {
if (!is_array ($_arr)) { $_arr = array (); }
$_arr = array_merge ($_arr, $value);
} else if ($key || $key === '' || $key === '0') {
$_arr[$key] = $value;
} else {
if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; }
else { $_arr[] = $value; end ($_arr); $key = key ($_arr); }
}
$reverse_path = array_reverse($this->path);
$reverse_history = array_reverse ($history);
$reverse_history[0] = $_arr;
$cnt = count($reverse_history) - 1;
for ($i = 0; $i < $cnt; $i++) {
$reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i];
}
$this->result = $reverse_history[$cnt];
$this->path[$incoming_indent] = $key;
if ($this->_containsGroupAnchor) {
$this->SavedGroups[$this->_containsGroupAnchor] = $this->path;
if (is_array ($value)) {
$k = key ($value);
if (!is_int ($k)) {
$this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k;
}
}
$this->_containsGroupAnchor = false;
}
}
private static function startsLiteralBlock ($line) {
$lastChar = substr (trim($line), -1);
if ($lastChar != '>' && $lastChar != '|') return false;
if ($lastChar == '|') return $lastChar;
// HTML tags should not be counted as literal blocks.
if (preg_match ('#<.*?>$#', $line)) return false;
return $lastChar;
}
private static function greedilyNeedNextLine($line) {
$line = trim ($line);
if (!strlen($line)) return false;
if (substr ($line, -1, 1) == ']') return false;
if ($line[0] == '[') return true;
if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true;
return false;
}
private function addLiteralLine ($literalBlock, $line, $literalBlockStyle) {
$line = self::stripIndent($line);
$line = rtrim ($line, "\r\n\t ") . "\n";
if ($literalBlockStyle == '|') {
return $literalBlock . $line;
}
if (strlen($line) == 0)
return rtrim($literalBlock, ' ') . "\n";
if ($line == "\n" && $literalBlockStyle == '>') {
return rtrim ($literalBlock, " \t") . "\n";
}
if ($line != "\n")
$line = trim ($line, "\r\n ") . " ";
return $literalBlock . $line;
}
function revertLiteralPlaceHolder ($lineArray, $literalBlock) {
foreach ($lineArray as $k => $_) {
if (is_array($_))
$lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock);
else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder)
$lineArray[$k] = rtrim ($literalBlock, " \r\n");
}
return $lineArray;
}
private static function stripIndent ($line, $indent = -1) {
if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line));
return substr ($line, $indent);
}
private function getParentPathByIndent ($indent) {
if ($indent == 0) return array();
$linePath = $this->path;
do {
end($linePath); $lastIndentInParentPath = key($linePath);
if ($indent <= $lastIndentInParentPath) array_pop ($linePath);
} while ($indent <= $lastIndentInParentPath);
return $linePath;
}
private function clearBiggerPathValues ($indent) {
if ($indent == 0) $this->path = array();
if (empty ($this->path)) return true;
foreach ($this->path as $k => $_) {
if ($k > $indent) unset ($this->path[$k]);
}
return true;
}
private static function isComment ($line) {
if (!$line) return false;
if ($line[0] == '#') return true;
if (trim($line, " \r\n\t") == '---') return true;
return false;
}
private static function isEmpty ($line) {
return (trim ($line) === '');
}
private function isArrayElement ($line) {
if (!$line) return false;
if ($line[0] != '-') return false;
if (strlen ($line) > 3)
if (substr($line,0,3) == '---') return false;
return true;
}
private function isHashElement ($line) {
return strpos($line, ':');
}
private function isLiteral ($line) {
if ($this->isArrayElement($line)) return false;
if ($this->isHashElement($line)) return false;
return true;
}
private static function unquote ($value) {
if (!$value) return $value;
if (!is_string($value)) return $value;
if ($value[0] == '\'') return trim ($value, '\'');
if ($value[0] == '"') return trim ($value, '"');
return $value;
}
private function startsMappedSequence ($line) {
return ($line[0] == '-' && substr ($line, -1, 1) == ':');
}
private function returnMappedSequence ($line) {
$array = array();
$key = self::unquote(trim(substr($line,1,-1)));
$array[$key] = array();
$this->delayedPath = array(strpos ($line, $key) + $this->indent => $key);
return array($array);
}
private function returnMappedValue ($line) {
$array = array();
$key = self::unquote (trim(substr($line,0,-1)));
$array[$key] = '';
return $array;
}
private function startsMappedValue ($line) {
return (substr ($line, -1, 1) == ':');
}
private function isPlainArray ($line) {
return ($line[0] == '[' && substr ($line, -1, 1) == ']');
}
private function returnPlainArray ($line) {
return $this->_toType($line);
}
private function returnKeyValuePair ($line) {
$array = array();
$key = '';
if (strpos ($line, ':')) {
// It's a key/value pair most likely
// If the key is in double quotes pull it out
if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) {
$value = trim(str_replace($matches[1],'',$line));
$key = $matches[2];
} else {
// Do some guesswork as to the key and the value
$explode = explode(':',$line);
$key = trim($explode[0]);
array_shift($explode);
$value = trim(implode(':',$explode));
}
// Set the type of the value. Int, string, etc
$value = $this->_toType($value);
if ($key === '0') $key = '__!YAMLZero';
$array[$key] = $value;
} else {
$array = array ($line);
}
return $array;
}
private function returnArrayElement ($line) {
if (strlen($line) <= 1) return array(array()); // Weird %)
$array = array();
$value = trim(substr($line,1));
$value = $this->_toType($value);
$array[] = $value;
return $array;
}
private function nodeContainsGroup ($line) {
$symbolsForReference = 'A-z0-9_\-';
if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-)
if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1];
if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1];
if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1];
return false;
}
private function addGroup ($line, $group) {
if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1);
if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1);
//print_r ($this->path);
}
private function stripGroup ($line, $group) {
$line = trim(str_replace($group, '', $line));
return $line;
}
}
// Enable use of Spyc from command line
// The syntax is the following: php spyc.php spyc.yaml
define ('SPYC_FROM_COMMAND_LINE', false);
do {
if (!SPYC_FROM_COMMAND_LINE) break;
if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break;
if (empty ($_SERVER['PHP_SELF']) || $_SERVER['PHP_SELF'] != 'spyc.php') break;
$file = $argv[1];
printf ("Spyc loading file: %s\n", $file);
print_r (spyc_load_file ($file));
} while (0);
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment