diff --git a/src/Config.php b/src/Config.php index 44748e4..78593ff 100644 --- a/src/Config.php +++ b/src/Config.php @@ -14,7 +14,7 @@ * * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -27,7 +27,7 @@ * @uses \Zend\Config\Exception * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Config implements \Countable, \Iterator diff --git a/src/Exception.php b/src/Exception.php index 7fb8890..3e10647 100644 --- a/src/Exception.php +++ b/src/Exception.php @@ -14,7 +14,7 @@ * * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -24,10 +24,9 @@ namespace Zend\Config; /** - * @uses \Zend\Exception * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ interface Exception diff --git a/src/Ini.php b/src/Ini.php index ea3599d..b1b2da4 100644 --- a/src/Ini.php +++ b/src/Ini.php @@ -14,7 +14,7 @@ * * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -28,7 +28,7 @@ * @uses \Zend\Config\Exception * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Ini extends Config diff --git a/src/Json.php b/src/Json.php new file mode 100755 index 0000000..97a61d3 --- /dev/null +++ b/src/Json.php @@ -0,0 +1,254 @@ + $value) { + switch (strtolower($key)) { + case 'allow_modifications': + case 'allowmodifications': + $allowModifications = (bool) $value; + break; + case 'skip_extends': + case 'skipextends': + $this->_skipExtends = (bool) $value; + break; + case 'ignore_constants': + case 'ignoreconstants': + $this->_ignoreConstants = (bool) $value; + break; + default: + break; + } + } + } + + set_error_handler(array($this, '_loadFileErrorHandler')); // Warnings and errors are suppressed + if ($json[0] != '{') { + $json = file_get_contents($json); + } + restore_error_handler(); + + // Check if there was a error while loading file + if ($this->_loadFileErrorStr !== null) { + throw new Exception\RuntimeException($this->_loadFileErrorStr); + } + + // Replace constants + if (!$this->_ignoreConstants) { + $json = $this->_replaceConstants($json); + } + + // Parse/decode + $config = JsonUtil::decode($json); + + if (null === $config) { + // decode failed + throw new Exception\RuntimeException("Error parsing JSON data"); + } + + // Flatten object structure into array + $config = $this->flattenObjects($config); + + if ($section === null) { + $dataArray = array(); + foreach ($config as $sectionName => $sectionData) { + $dataArray[$sectionName] = $this->_processExtends($config, $sectionName); + } + + parent::__construct($dataArray, $allowModifications); + } elseif (is_array($section)) { + $dataArray = array(); + foreach ($section as $sectionName) { + if (!isset($config[$sectionName])) { + throw new Exception\RuntimeException(sprintf('Section "%s" cannot be found', $sectionName)); + } + + $dataArray = array_merge($this->_processExtends($config, $sectionName), $dataArray); + } + + parent::__construct($dataArray, $allowModifications); + } else { + if (!isset($config[$section])) { + throw new Exception\RuntimeException(sprintf('Section "%s" cannot be found', $section)); + } + + $dataArray = $this->_processExtends($config, $section); + if (!is_array($dataArray)) { + // Section in the JSON data contains just one top level string + $dataArray = array($section => $dataArray); + } + + parent::__construct($dataArray, $allowModifications); + } + + $this->_loadedSection = $section; + } + + /** + * Helper function to process each element in the section and handle + * the "_extends" inheritance attribute. + * + * @param array $data Data array to process + * @param string $section Section to process + * @param array $config Configuration which was parsed yet + * @throws Exception\RuntimeException When $section cannot be found + * @return array + */ + protected function _processExtends(array $data, $section, array $config = array()) + { + if (!isset($data[$section])) { + throw new Exception\RuntimeException(sprintf('Section "%s" cannot be found', $section)); + } + + $thisSection = $data[$section]; + + if (is_array($thisSection) && isset($thisSection[self::EXTENDS_NAME])) { + if (is_array($thisSection[self::EXTENDS_NAME])) { + throw new Exception\RuntimeException('Invalid extends clause: must be a string; array received'); + } + $this->_assertValidExtend($section, $thisSection[self::EXTENDS_NAME]); + + if (!$this->_skipExtends) { + $config = $this->_processExtends($data, $thisSection[self::EXTENDS_NAME], $config); + } + unset($thisSection[self::EXTENDS_NAME]); + } + + $config = $this->_arrayMergeRecursive($config, $thisSection); + + return $config; + } + + /** + * Replace any constants referenced in a string with their values + * + * @param string $value + * @return string + */ + protected function _replaceConstants($value) + { + foreach ($this->_getConstants() as $constant) { + if (strstr($value, $constant)) { + $value = str_replace($constant, constant($constant), $value); + } + } + return $value; + } + + /** + * Get (reverse) sorted list of defined constant names + * + * @return array + */ + protected function _getConstants() + { + $constants = array_keys(get_defined_constants()); + rsort($constants, SORT_STRING); + return $constants; + } + + /** + * Flatten JSON object structure to associative array + * + * @param object|array $config + * @return array + */ + protected function flattenObjects($config) + { + $flattened = array(); + foreach ($config as $key => $value) { + if (is_object($value)) { + $value = $this->flattenObjects($value); + } + if (is_array($value)) { + foreach ($value as $k => $v) { + if (is_object($v)) { + $value[$k] = $this->flattenObjects($v); + } + } + } + $flattened[$key] = $value; + } + return $flattened; + } +} diff --git a/src/Writer/AbstractFileWriter.php b/src/Writer/AbstractFileWriter.php index 9e1bc3d..943619a 100644 --- a/src/Writer/AbstractFileWriter.php +++ b/src/Writer/AbstractFileWriter.php @@ -15,7 +15,7 @@ * @category Zend * @package Zend_Config * @package Writer - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -32,7 +32,7 @@ * @uses \Zend\Config\Writer\Writer * @category Zend * @package Zend_package - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class AbstractFileWriter extends AbstractWriter diff --git a/src/Writer/AbstractWriter.php b/src/Writer/AbstractWriter.php index fa6e376..3613413 100644 --- a/src/Writer/AbstractWriter.php +++ b/src/Writer/AbstractWriter.php @@ -14,7 +14,7 @@ * * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -26,7 +26,7 @@ /** * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ abstract class AbstractWriter diff --git a/src/Writer/ArrayWriter.php b/src/Writer/ArrayWriter.php index 4c7c36a..eada599 100644 --- a/src/Writer/ArrayWriter.php +++ b/src/Writer/ArrayWriter.php @@ -14,7 +14,7 @@ * * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -27,7 +27,7 @@ * @uses \Zend\Config\Writer\FileAbstract * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class ArrayWriter extends AbstractFileWriter diff --git a/src/Writer/Ini.php b/src/Writer/Ini.php index 2042a78..87a641c 100644 --- a/src/Writer/Ini.php +++ b/src/Writer/Ini.php @@ -14,7 +14,7 @@ * * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -29,7 +29,7 @@ * @uses \Zend\Config\Writer\FileAbstract * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Ini extends AbstractFileWriter diff --git a/src/Writer/Json.php b/src/Writer/Json.php new file mode 100755 index 0000000..aafbc09 --- /dev/null +++ b/src/Writer/Json.php @@ -0,0 +1,100 @@ +_prettyPrint; + } + + /** + * Set prettyPrint flag + * + * @param bool $prettyPrint PrettyPrint flag + * @return Zend_Config_Writer_Json + */ + public function setPrettyPrint($flag) + { + $this->_prettyPrint = (bool) $flag; + return $this; + } + + /** + * Render a Zend_Config into a JSON config string. + * + * @since 1.10 + * @return string + */ + public function render() + { + $data = $this->_config->toArray(); + $sectionName = $this->_config->getSectionName(); + $extends = $this->_config->getExtends(); + + if (is_string($sectionName)) { + $data = array($sectionName => $data); + } + + foreach ($extends as $section => $parentSection) { + $data[$section][JsonConfig::EXTENDS_NAME] = $parentSection; + } + + // Ensure that each "extends" section actually exists + foreach ($data as $section => $sectionData) { + if (is_array($sectionData) && isset($sectionData[JsonConfig::EXTENDS_NAME])) { + $sectionExtends = $sectionData[JsonConfig::EXTENDS_NAME]; + if (!isset($data[$sectionExtends])) { + // Remove "extends" declaration if section does not exist + unset($data[$section][JsonConfig::EXTENDS_NAME]); + } + } + } + + $out = JsonUtil::encode($data); + if ($this->prettyPrint()) { + $out = JsonUtil::prettyPrint($out); + } + return $out; + } +} diff --git a/src/Writer/Xml.php b/src/Writer/Xml.php index 2609ce1..3cbcafd 100644 --- a/src/Writer/Xml.php +++ b/src/Writer/Xml.php @@ -14,7 +14,7 @@ * * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -30,7 +30,7 @@ * @uses \Zend\Config\Xml * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Xml extends AbstractFileWriter diff --git a/src/Writer/Yaml.php b/src/Writer/Yaml.php new file mode 100755 index 0000000..438fefc --- /dev/null +++ b/src/Writer/Yaml.php @@ -0,0 +1,138 @@ +_yamlEncoder; + } + + /** + * Set callback for decoding YAML + * + * @param callable $yamlEncoder the decoder to set + * @return Zend_Config_Yaml + */ + public function setYamlEncoder($yamlEncoder) + { + if (!is_callable($yamlEncoder)) { + throw new Exception\InvalidArgumentException('Invalid parameter to setYamlEncoder - must be callable'); + } + + $this->_yamlEncoder = $yamlEncoder; + return $this; + } + + /** + * Render a Zend_Config into a YAML config string. + * + * @since 1.10 + * @return string + */ + public function render() + { + $data = $this->_config->toArray(); + $sectionName = $this->_config->getSectionName(); + $extends = $this->_config->getExtends(); + + if (is_string($sectionName)) { + $data = array($sectionName => $data); + } + + foreach ($extends as $section => $parentSection) { + $data[$section][YamlConfig::EXTENDS_NAME] = $parentSection; + } + + // Ensure that each "extends" section actually exists + foreach ($data as $section => $sectionData) { + if (is_array($sectionData) && isset($sectionData[YamlConfig::EXTENDS_NAME])) { + $sectionExtends = $sectionData[YamlConfig::EXTENDS_NAME]; + if (!isset($data[$sectionExtends])) { + // Remove "extends" declaration if section does not exist + unset($data[$section][YamlConfig::EXTENDS_NAME]); + } + } + } + + return call_user_func($this->getYamlEncoder(), $data); + } + + /** + * Very dumb YAML encoder + * + * Until we have Zend_Yaml... + * + * @param array $data YAML data + * @return string + */ + public static function encode($data) + { + return self::_encodeYaml(0, $data); + } + + /** + * Service function for encoding YAML + * + * @param int $indent Current indent level + * @param array $data Data to encode + * @return string + */ + protected static function _encodeYaml($indent, $data) + { + reset($data); + $result = ""; + $numeric = is_numeric(key($data)); + + foreach($data as $key => $value) { + if(is_array($value)) { + $encoded = "\n".self::_encodeYaml($indent+1, $value); + } else { + $encoded = (string)$value."\n"; + } + $result .= str_repeat(" ", $indent).($numeric?"- ":"$key: ").$encoded; + } + return $result; + } +} diff --git a/src/Xml.php b/src/Xml.php index 4cf95fe..fe236bb 100644 --- a/src/Xml.php +++ b/src/Xml.php @@ -14,7 +14,7 @@ * * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -30,7 +30,7 @@ * @uses \Zend\Config\Exception * @category Zend * @package Zend_Config - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Xml extends Config diff --git a/src/Yaml.php b/src/Yaml.php new file mode 100755 index 0000000..47f38b3 --- /dev/null +++ b/src/Yaml.php @@ -0,0 +1,370 @@ +_yamlDecoder; + } + + /** + * Set callback for decoding YAML + * + * @param callable $yamlDecoder the decoder to set + * @return Zend_Config_Yaml + */ + public function setYamlDecoder($yamlDecoder) + { + if (!is_callable($yamlDecoder)) { + throw new Exception\InvalidArgumentException('Invalid parameter to setYamlDecoder() - must be callable'); + } + + $this->_yamlDecoder = $yamlDecoder; + return $this; + } + + /** + * Loads the section $section from the config file encoded as YAML + * + * Sections are defined as properties of the main object + * + * In order to extend another section, a section defines the "_extends" + * property having a value of the section name from which the extending + * section inherits values. + * + * Note that the keys in $section will override any keys of the same + * name in the sections that have been included via "_extends". + * + * Options may include: + * - allow_modifications: whether or not the config object is mutable + * - skip_extends: whether or not to skip processing of parent configuration + * - yaml_decoder: a callback to use to decode the Yaml source + * + * @param string $yaml YAML file to process + * @param mixed $section Section to process + * @param boolean $options Whether modifiacations are allowed at runtime + */ + public function __construct($yaml, $section = null, $options = false) + { + if (empty($yaml)) { + throw new Exception\RuntimeException('Filename is not set'); + } + + $ignoreConstants = $staticIgnoreConstants = self::ignoreConstants(); + $allowModifications = false; + if (is_bool($options)) { + $allowModifications = $options; + } elseif (is_array($options)) { + foreach ($options as $key => $value) { + switch (strtolower($key)) { + case 'allow_modifications': + case 'allowmodifications': + $allowModifications = (bool) $value; + break; + case 'skip_extends': + case 'skipextends': + $this->_skipExtends = (bool) $value; + break; + case 'ignore_constants': + case 'ignoreconstants': + $ignoreConstants = (bool) $value; + break; + case 'yaml_decoder': + case 'yamldecoder': + $this->setYamlDecoder($value); + break; + default: + break; + } + } + } + + // Suppress warnings and errors while loading file + set_error_handler(array($this, '_loadFileErrorHandler')); + $yaml = file_get_contents($yaml); + restore_error_handler(); + + // Check if there was a error while loading file + if ($this->_loadFileErrorStr !== null) { + throw new Exception\RuntimeException($this->_loadFileErrorStr); + } + + // Override static value for ignore_constants if provided in $options + self::setIgnoreConstants($ignoreConstants); + + // Parse YAML + $config = call_user_func($this->getYamlDecoder(), $yaml); + + // Reset original static state of ignore_constants + self::setIgnoreConstants($staticIgnoreConstants); + + if (null === $config) { + // decode failed + throw new Exception\RuntimeException("Error parsing YAML data"); + } + + if (null === $section) { + $dataArray = array(); + foreach ($config as $sectionName => $sectionData) { + $dataArray[$sectionName] = $this->_processExtends($config, $sectionName); + } + parent::__construct($dataArray, $allowModifications); + } elseif (is_array($section)) { + $dataArray = array(); + foreach ($section as $sectionName) { + if (!isset($config[$sectionName])) { + throw new Exception\RuntimeException(sprintf('Section "%s" cannot be found', $section)); + } + + $dataArray = array_merge($this->_processExtends($config, $sectionName), $dataArray); + } + parent::__construct($dataArray, $allowModifications); + } else { + if (!isset($config[$section])) { + throw new Exception\RuntimeException(sprintf('Section "%s" cannot be found', $section)); + } + + $dataArray = $this->_processExtends($config, $section); + if (!is_array($dataArray)) { + // Section in the yaml data contains just one top level string + $dataArray = array($section => $dataArray); + } + parent::__construct($dataArray, $allowModifications); + } + + $this->_loadedSection = $section; + } + + /** + * Helper function to process each element in the section and handle + * the "_extends" inheritance attribute. + * + * @param array $data Data array to process + * @param string $section Section to process + * @param array $config Configuration which was parsed yet + * @return array + * @throws Zend_Config_Exception When $section cannot be found + */ + protected function _processExtends(array $data, $section, array $config = array()) + { + if (!isset($data[$section])) { + throw new Exception\RuntimeException(sprintf('Section "%s" cannot be found', $section)); + } + + $thisSection = $data[$section]; + + if (is_array($thisSection) && isset($thisSection[self::EXTENDS_NAME])) { + $this->_assertValidExtend($section, $thisSection[self::EXTENDS_NAME]); + + if (!$this->_skipExtends) { + $config = $this->_processExtends($data, $thisSection[self::EXTENDS_NAME], $config); + } + unset($thisSection[self::EXTENDS_NAME]); + } + + $config = $this->_arrayMergeRecursive($config, $thisSection); + + return $config; + } + + /** + * Very dumb YAML parser + * + * Until we have Zend_Yaml... + * + * @param string $yaml YAML source + * @return array Decoded data + */ + public static function decode($yaml) + { + $lines = explode("\n", $yaml); + reset($lines); + return self::_decodeYaml(0, $lines); + } + + /** + * Service function to decode YAML + * + * @param int $currentIndent Current indent level + * @param array $lines YAML lines + * @return array|string + */ + protected static function _decodeYaml($currentIndent, &$lines) + { + $config = array(); + $inIndent = false; + while (list($n, $line) = each($lines)) { + $lineno = $n + 1; + if (strlen($line) == 0) { + continue; + } + if ($line[0] == '#') { + // comment + continue; + } + $indent = strspn($line, " "); + + // line without the spaces + $line = trim($line); + if (strlen($line) == 0) { + continue; + } + + if ($indent < $currentIndent) { + // this level is done + prev($lines); + return $config; + } + + if (!$inIndent) { + $currentIndent = $indent; + $inIndent = true; + } + + if (preg_match("/(\w+):\s*(.*)/", $line, $m)) { + // key: value + if (strlen($m[2])) { + // simple key: value + $value = $m[2]; + // Check for booleans and constants + if (preg_match('/^(t(rue)?|on|y(es)?)$/i', $value)) { + $value = true; + } elseif (preg_match('/^(f(alse)?|off|n(o)?)$/i', $value)) { + $value = false; + } elseif (!self::$_ignoreConstants) { + // test for constants + $value = self::_replaceConstants($value); + } + } else { + // key: and then values on new lines + $value = self::_decodeYaml($currentIndent + 1, $lines); + if (is_array($value) && !count($value)) { + $value = ""; + } + } + $config[$m[1]] = $value; + } elseif ($line[0] == "-") { + // item in the list: + // - FOO + if (strlen($line) > 2) { + $config[] = substr($line, 2); + } else { + $config[] = self::_decodeYaml($currentIndent + 1, $lines); + } + } else { + throw new Exception\RuntimeException(sprintf( + 'Error parsing YAML at line %d - unsupported syntax: "%s"', + $lineno, $line + )); + } + } + return $config; + } + + /** + * Replace any constants referenced in a string with their values + * + * @param string $value + * @return string + */ + protected static function _replaceConstants($value) + { + foreach (self::_getConstants() as $constant) { + if (strstr($value, $constant)) { + $value = str_replace($constant, constant($constant), $value); + } + } + return $value; + } + + /** + * Get (reverse) sorted list of defined constant names + * + * @return array + */ + protected static function _getConstants() + { + $constants = array_keys(get_defined_constants()); + rsort($constants, SORT_STRING); + return $constants; + } +} diff --git a/test/ConfigTest.php b/test/ConfigTest.php index 169ee04..9602919 100644 --- a/test/ConfigTest.php +++ b/test/ConfigTest.php @@ -15,7 +15,7 @@ * @category Zend * @package Zend_Config * @subpackage UnitTests - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -27,7 +27,7 @@ * @category Zend * @package Zend_Config * @subpackage UnitTests - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * @group Zend_Config */ diff --git a/test/IniTest.php b/test/IniTest.php index d436940..3c5e230 100644 --- a/test/IniTest.php +++ b/test/IniTest.php @@ -15,7 +15,7 @@ * @category Zend * @package Zend_Config * @subpackage UnitTests - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -27,7 +27,7 @@ * @category Zend * @package Zend_Config * @subpackage UnitTests - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * @group Zend_Config */ diff --git a/test/JsonTest.php b/test/JsonTest.php new file mode 100644 index 0000000..f4a9418 --- /dev/null +++ b/test/JsonTest.php @@ -0,0 +1,286 @@ +_iniFileConfig = __DIR__ . '/_files/config.json'; + $this->_iniFileAllSectionsConfig = __DIR__ . '/_files/allsections.json'; + $this->_iniFileCircularConfig = __DIR__ . '/_files/circular.json'; + $this->_iniFileMultipleInheritanceConfig = __DIR__ . '/_files/multipleinheritance.json'; + $this->_nonReadableConfig = __DIR__ . '/_files/nonreadable.json'; + $this->_iniFileNoSectionsConfig = __DIR__ . '/_files/nosections.json'; + $this->_iniFileInvalid = __DIR__ . '/_files/invalid.json'; + } + + public function testLoadSingleSection() + { + $config = new JsonConfig($this->_iniFileConfig, 'all'); + + $this->assertEquals('all', $config->hostname); + $this->assertEquals('live', $config->db->name); + $this->assertEquals('multi', $config->one->two->three); + $this->assertNull(@$config->nonexistent); // property doesn't exist + } + + public function testSectionInclude() + { + $config = new JsonConfig($this->_iniFileConfig, 'staging'); + + $this->assertEquals('', $config->debug); // only in staging + $this->assertEquals('thisname', $config->name); // only in all + $this->assertEquals('username', $config->db->user); // only in all (nested version) + $this->assertEquals('dbstaging', $config->db->name); // inherited and overridden + } + + public function testTrueValues() + { + $config = new JsonConfig($this->_iniFileConfig, 'debug'); + + $this->assertTrue($config->debug); + $this->assertTrue($config->values->changed); + } + + public function testEmptyValues() + { + $config = new JsonConfig($this->_iniFileConfig, 'debug'); + + $this->assertInternalType('string', $config->special->no); + $this->assertEquals('no', $config->special->no); + $this->assertNull($config->special->null); + $this->assertFalse($config->special->false); + } + + /** + * @group review + */ + public function testMultiDepthExtends() + { + $config = new JsonConfig($this->_iniFileConfig, 'other_staging'); + + $this->assertEquals('otherStaging', $config->only_in); // only in other_staging + $this->assertEquals('', $config->debug); // 1 level down: only in staging + $this->assertEquals('thisname', $config->name); // 2 levels down: only in all + $this->assertEquals('username', $config->db->user); // 2 levels down: only in all (nested version) + $this->assertEquals('staging', $config->hostname); // inherited from two to one and overridden + $this->assertEquals('dbstaging', $config->db->name); // inherited from two to one and overridden + $this->assertEquals('anotherpwd', $config->db->pass); // inherited from two to other_staging and overridden + } + + public function testRaisesExceptionWhenSectionNotFound() + { + $this->setExpectedException('Zend\Config\Exception\RuntimeException', 'cannot be found'); + $config = new JsonConfig($this->_iniFileConfig, 'extendserror'); + } + + public function testRetrievesAndMergesMultipleSections() + { + $config = new JsonConfig($this->_iniFileAllSectionsConfig, array('staging','other_staging')); + + $this->assertEquals('otherStaging', $config->only_in); + $this->assertEquals('dbstaging', $config->db->name); + + } + + public function testCanRetrieveAllSections() + { + $config = new JsonConfig($this->_iniFileAllSectionsConfig, null); + $this->assertEquals('otherStaging', $config->other_staging->only_in); + $this->assertEquals('dbstaging', $config->staging->db->name); + } + + public function testAllowsLoadingAllSectionsOrSomeSectionsSelectively() + { + $config = new JsonConfig($this->_iniFileAllSectionsConfig, null); + $this->assertEquals(null, $config->getSectionName()); + $this->assertEquals(true, $config->areAllSectionsLoaded()); + + $config = new JsonConfig($this->_iniFileAllSectionsConfig, 'all'); + $this->assertEquals('all', $config->getSectionName()); + $this->assertEquals(false, $config->areAllSectionsLoaded()); + + $config = new JsonConfig($this->_iniFileAllSectionsConfig, array('staging','other_staging')); + $this->assertEquals(array('staging','other_staging'), $config->getSectionName()); + $this->assertEquals(false, $config->areAllSectionsLoaded()); + } + + public function testDetectsCircularInheritance() + { + $this->setExpectedException('Zend\Config\Exception\RuntimeException', 'circular inheritance'); + $config = new JsonConfig($this->_iniFileCircularConfig, null); + } + + public function testRaisesErrorWhenNoFileProvided() + { + $this->setExpectedException('Zend\Config\Exception\InvalidArgumentException', 'not set'); + $config = new JsonConfig('',''); + } + + public function testRaisesErrorOnAttemptsToExtendMultipleSectionsAtOnce() + { + $this->setExpectedException('Zend\Config\Exception\RuntimeException', 'Invalid'); + $config = new JsonConfig($this->_iniFileMultipleInheritanceConfig, 'multiinherit'); + } + + public function testRaisesErrorWhenSectionNotFound() + { + try { + $config = new JsonConfig($this->_iniFileConfig,array('all', 'notthere')); + $this->fail('An expected exception has not been raised'); + } catch (\Zend\Config\Exception $expected) { + $this->assertContains('cannot be found', $expected->getMessage()); + } + + try { + $config = new JsonConfig($this->_iniFileConfig,'notthere'); + $this->fail('An expected exception has not been raised'); + } catch (\Zend\Config\Exception $expected) { + $this->assertContains('cannot be found', $expected->getMessage()); + } + } + + + public function testCanLoadConfigWithNoSections() + { + $config = new JsonConfig($this->_iniFileNoSectionsConfig); + + $this->assertEquals('all', $config->hostname); + $this->assertEquals('two', $config->one->two); + $this->assertEquals('4', $config->one->three->four); + $this->assertEquals('5', $config->one->three->five); + } + + public function testRaisesExceptionOnInvalidJsonMarkup() + { + $this->setExpectedException('Zend\Json\Exception', 'Syntax error'); + $config = new JsonConfig($this->_iniFileInvalid); + } + + public function testOptionsPassedAreHonored() + { + $config = new JsonConfig($this->_iniFileConfig, 'staging', array( + 'skipExtends' => true, + 'allowModifications' => true, + 'bar' => 'foo', // ignored + )); + $this->assertNull($config->name); // demonstrates extends were skipped + $config->foo = 'bar'; + $this->assertEquals('bar', $config->foo); // demonstrates modifications were made + } + + public function testZf2StyleOptionsAreHonored() + { + $config = new JsonConfig($this->_iniFileConfig, 'staging', array( + 'skip_extends' => true, + 'allow_modifications' => true, + 'bar' => 'foo', // ignored + )); + $this->assertNull($config->name); // demonstrates extends were skipped + $config->foo = 'bar'; + $this->assertEquals('bar', $config->foo); // demonstrates modifications were made + } + + public function testAllowsPassingJsonStringsToConstructor() + { + $json =<<assertTrue($config->debug); + $this->assertEquals('bar', $config->foo); + $this->assertNull($config->bar); + } + + public function testProcessesSectionsWithSingleValues() + { + $json = '{"all":"values"}'; + $config = new JsonConfig($json, 'all'); + $this->assertEquals('values', $config->all); + } + + public function testReplacesConstantNamesWithValuesByDefault() + { + if (!defined('ZEND_CONFIG_JSON_ENV')) { + define('ZEND_CONFIG_JSON_ENV', 'testing'); + } + if (!defined('ZEND_CONFIG_JSON_ENV_PATH')) { + define('ZEND_CONFIG_JSON_ENV_PATH', dirname(__FILE__)); + } + if (!defined('ZEND_CONFIG_JSON_ENV_INT')) { + define('ZEND_CONFIG_JSON_ENV_INT', 42); + } + $json = '{"env":"ZEND_CONFIG_JSON_ENV","path":"ZEND_CONFIG_JSON_ENV_PATH/tests","int":ZEND_CONFIG_JSON_ENV_INT}'; + $config = new JsonConfig($json); + $this->assertEquals(ZEND_CONFIG_JSON_ENV, $config->env); + $this->assertEquals(ZEND_CONFIG_JSON_ENV_PATH . '/tests', $config->path); + $this->assertEquals(ZEND_CONFIG_JSON_ENV_INT, $config->int); + } + + public function testCanIgnoreConstantsWhenParsing() + { + if (!defined('ZEND_CONFIG_JSON_ENV')) { + define('ZEND_CONFIG_JSON_ENV', 'testing'); + } + $json = '{"env":"ZEND_CONFIG_JSON_ENV"}'; + $config = new JsonConfig($json, null, array('ignore_constants' => true)); + $this->assertEquals('ZEND_CONFIG_JSON_ENV', $config->env); + } + + public function testIgnoringConstantsCanLeadToParseErrors() + { + if (!defined('ZEND_CONFIG_JSON_ENV')) { + define('ZEND_CONFIG_JSON_ENV', 'testing'); + } + if (!defined('ZEND_CONFIG_JSON_ENV_PATH')) { + define('ZEND_CONFIG_JSON_ENV_PATH', dirname(__FILE__)); + } + if (!defined('ZEND_CONFIG_JSON_ENV_INT')) { + define('ZEND_CONFIG_JSON_ENV_INT', 42); + } + $json = '{"env":"ZEND_CONFIG_JSON_ENV","path":"ZEND_CONFIG_JSON_ENV_PATH/tests","int":ZEND_CONFIG_JSON_ENV_INT}'; + + $this->setExpectedException('Zend\Json\Exception', 'Syntax'); + $config = new JsonConfig($json, null, array('ignore_constants' => true)); + } + + public function testNestedConfigSetsAreArrays() + { + $config = new JsonConfig(__DIR__ . '/_files/nested.json', 'testing'); + $array = $config->toArray(); + $this->assertInternalType('array', $array['definitions'][0]); + } +} diff --git a/test/Writer/ArrayWriterTest.php b/test/Writer/ArrayWriterTest.php index 16f237d..350ded2 100644 --- a/test/Writer/ArrayWriterTest.php +++ b/test/Writer/ArrayWriterTest.php @@ -15,7 +15,7 @@ * @category Zend * @package Zend_Config * @subpackage UnitTests - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -28,7 +28,7 @@ * @category Zend * @package Zend_Config * @subpackage UnitTests - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * @group Zend_Config */ diff --git a/test/Writer/IniTest.php b/test/Writer/IniTest.php index f8e4a40..c193796 100644 --- a/test/Writer/IniTest.php +++ b/test/Writer/IniTest.php @@ -15,7 +15,7 @@ * @category Zend * @package Zend_Config * @subpackage UnitTests - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -29,7 +29,7 @@ * @category Zend * @package Zend_Config * @subpackage UnitTests - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * @group Zend_Config */ diff --git a/test/Writer/JsonTest.php b/test/Writer/JsonTest.php new file mode 100644 index 0000000..8b31627 --- /dev/null +++ b/test/Writer/JsonTest.php @@ -0,0 +1,150 @@ +_tempName = tempnam(__DIR__ . '/temp', 'tmp'); + } + + public function tearDown() + { + @unlink($this->_tempName); + } + + public function testNoFilenameSet() + { + $writer = new JsonWriter(array('config' => new Config(array()))); + + $this->setExpectedException('Zend\Config\Exception\InvalidArgumentException', 'No filename was set'); + $writer->write(); + } + + public function testNoConfigSet() + { + $writer = new JsonWriter(array('filename' => $this->_tempName)); + + $this->setExpectedException('Zend\Config\Exception\InvalidArgumentException', 'No config was set'); + $writer->write(); + } + + public function testFileNotWritable() + { + $writer = new JsonWriter(array('config' => new Config(array()), 'filename' => '/../../../')); + + $this->setExpectedException('Zend\Config\Exception\RuntimeException', 'Could not write to file'); + $writer->write(); + } + + public function testWriteAndRead() + { + $config = new Config(array('default' => array('test' => 'foo'))); + + $writer = new JsonWriter(array('config' => $config, 'filename' => $this->_tempName)); + $writer->write(); + + $config = new JsonConfig($this->_tempName, null); + + $this->assertEquals('foo', $config->default->test); + } + + public function testNoSection() + { + $config = new Config(array('test' => 'foo', 'test2' => array('test3' => 'bar'))); + + $writer = new JsonWriter(array('config' => $config, 'filename' => $this->_tempName)); + $writer->write(); + + $config = new JsonConfig($this->_tempName); + + $this->assertEquals('foo', $config->test); + $this->assertEquals('bar', $config->test2->test3); + } + + public function testWriteAndReadOriginalFile() + { + $config = new JsonConfig(__DIR__ . '/files/allsections.json', null, array('skip_extends' => true)); + + $writer = new JsonWriter(array('config' => $config, 'filename' => $this->_tempName)); + $writer->write(); + + $config = new JsonConfig($this->_tempName, null); + $this->assertEquals('multi', $config->staging->one->two->three, var_export($config->toArray(), 1)); + + $config = new JsonConfig($this->_tempName, null, array('skip_extends' => true)); + $this->assertFalse(isset($config->staging->one)); + } + + + public function testWriteAndReadSingleSection() + { + $config = new JsonConfig(__DIR__ . '/files/allsections.json', 'staging', array('skip_extends' => true)); + + $writer = new JsonWriter(array('config' => $config, 'filename' => $this->_tempName)); + $writer->write(); + + $config = new JsonConfig($this->_tempName, null); + + $this->assertEquals('staging', $config->staging->hostname); + $this->assertEquals('', $config->staging->debug); + $this->assertEquals(null, @$config->production); + } + + public function testArgumentOverride() + { + $config = new Config(array('default' => array('test' => 'foo'))); + + $writer = new JsonWriter(); + $writer->write($this->_tempName, $config); + + $config = new JsonConfig($this->_tempName, null); + + $this->assertEquals('foo', $config->default->test); + } + + public function testCanWritePrettyPrintedVersion() + { + $config = new JsonConfig(__DIR__ . '/files/allsections-pretty.json'); + + $writer = new JsonWriter(array('config' => $config, 'filename' => $this->_tempName)); + $writer->setPrettyPrint(true); + $writer->write(); + $testOutput = file_get_contents($this->_tempName); + $this->assertRegExp('/^\s+/m', $testOutput); + } +} diff --git a/test/Writer/XmlTest.php b/test/Writer/XmlTest.php index 6588215..46bcd47 100644 --- a/test/Writer/XmlTest.php +++ b/test/Writer/XmlTest.php @@ -15,7 +15,7 @@ * @category Zend * @package Zend_Config * @subpackage UnitTests - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -29,7 +29,7 @@ * @category Zend * @package Zend_Config * @subpackage UnitTests - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * @group Zend_Config */ diff --git a/test/Writer/YamlTest.php b/test/Writer/YamlTest.php new file mode 100644 index 0000000..ded44dc --- /dev/null +++ b/test/Writer/YamlTest.php @@ -0,0 +1,139 @@ +_tempName = tempnam(__DIR__ . '/temp', 'tmp'); + } + + public function tearDown() + { + @unlink($this->_tempName); + } + + public function testNoFilenameSet() + { + $writer = new YamlWriter(array('config' => new Config(array()))); + + $this->setExpectedException('Zend\Config\Exception\InvalidArgumentException', 'No filename was set'); + $writer->write(); + } + + public function testNoConfigSet() + { + $writer = new YamlWriter(array('filename' => $this->_tempName)); + + $this->setExpectedException('Zend\Config\Exception\InvalidArgumentException', 'No config was set'); + $writer->write(); + } + + public function testFileNotWritable() + { + $writer = new YamlWriter(array('config' => new Config(array()), 'filename' => '/../../../')); + + $this->setExpectedException('Zend\Config\Exception\RuntimeException', 'Could not write'); + $writer->write(); + } + + public function testWriteAndRead() + { + $config = new Config(array('default' => array('test' => 'foo'))); + + $writer = new YamlWriter(array('config' => $config, 'filename' => $this->_tempName)); + $writer->write(); + + $config = new YamlConfig($this->_tempName, null); + + $this->assertEquals('foo', $config->default->test); + } + + public function testNoSection() + { + $config = new Config(array('test' => 'foo', 'test2' => array('test3' => 'bar'))); + + $writer = new YamlWriter(array('config' => $config, 'filename' => $this->_tempName)); + $writer->write(); + + $config = new YamlConfig($this->_tempName, null); + + $this->assertEquals('foo', $config->test); + $this->assertEquals('bar', $config->test2->test3); + } + + public function testWriteAndReadOriginalFile() + { + $config = new YamlConfig(__DIR__ . '/files/allsections.yaml', null, array('skip_extends' => true)); + + $writer = new YamlWriter(array('config' => $config, 'filename' => $this->_tempName)); + $writer->write(); + + $config = new YamlConfig($this->_tempName, null); + $this->assertEquals('multi', $config->staging->one->two->three, var_export($config->toArray(), 1)); + + $config = new YamlConfig($this->_tempName, null, array('skip_extends' => true)); + $this->assertFalse(isset($config->staging->one)); + } + + + public function testWriteAndReadSingleSection() + { + $config = new YamlConfig(__DIR__ . '/files/allsections.yaml', 'staging', array('skip_extends' => true)); + + $writer = new YamlWriter(array('config' => $config, 'filename' => $this->_tempName)); + $writer->write(); + + $config = new YamlConfig($this->_tempName, null); + + $this->assertEquals('staging', $config->staging->hostname); + $this->assertEquals('', $config->staging->debug); + $this->assertEquals(null, @$config->production); + } + + public function testArgumentOverride() + { + $config = new Config(array('default' => array('test' => 'foo'))); + + $writer = new YamlWriter(); + $writer->write($this->_tempName, $config); + + $config = new YamlConfig($this->_tempName, null); + + $this->assertEquals('foo', $config->default->test); + } +} diff --git a/test/Writer/files/allsections-pretty.json b/test/Writer/files/allsections-pretty.json new file mode 100644 index 0000000..8a0b7d4 --- /dev/null +++ b/test/Writer/files/allsections-pretty.json @@ -0,0 +1,47 @@ +{ + "all":{ + "hostname":"all", + "name":"thisname", + "db":{ + "host":"127.0.0.1", + "user":"username", + "pass":"password", + "name":"live" + }, + "one":{ + "two":{ + "three":"multi" + } + } + }, + "staging":{ + "_extends":"all", + "hostname":"staging", + "db":{ + "name":"dbstaging" + }, + "debug":false + }, + "debug":{ + "_extends":"all", + "hostname":"debug", + "db":{ + "name":"dbdebug" + }, + "debug":true, + "values":{ + "changed":true + }, + "special":{ + "no":"no", + "null":null, + "false":false + } + }, + "other_staging":{ + "only_in":"otherStaging", + "db":{ + "pass":"anotherpwd" + } + } +} \ No newline at end of file diff --git a/test/Writer/files/allsections.json b/test/Writer/files/allsections.json new file mode 100644 index 0000000..9c00533 --- /dev/null +++ b/test/Writer/files/allsections.json @@ -0,0 +1 @@ +{"all":{"hostname":"all","name":"thisname","db":{"host":"127.0.0.1","user":"username","pass":"password","name":"live"},"one":{"two":{"three":"multi"}}},"staging":{"_extends":"all","hostname":"staging","db":{"name":"dbstaging"},"debug":false},"debug":{"_extends":"all","hostname":"debug","db":{"name":"dbdebug"},"debug":true,"values":{"changed":true},"special":{"no":"no","null":null,"false":false}},"other_staging":{"only_in":"otherStaging","db":{"pass":"anotherpwd"}}} \ No newline at end of file diff --git a/test/Writer/files/allsections.yaml b/test/Writer/files/allsections.yaml new file mode 100644 index 0000000..b142b6f --- /dev/null +++ b/test/Writer/files/allsections.yaml @@ -0,0 +1,36 @@ +all: + hostname: all + name: thisname + db: + host: 127.0.0.1 + user: username + pass: password + name: live + one: + two: + three: multi + +staging: + _extends: all + hostname: staging + db: + name: dbstaging + debug: false + +debug: + _extends: all + hostname: debug + debug: true + values: + changed: yes + db: + name: dbdebug + special: + no: no + null: null + false: false + +other_staging: + only_in: otherStaging + db: + pass: anotherpwd diff --git a/test/XmlTest.php b/test/XmlTest.php index 0690c41..562b126 100644 --- a/test/XmlTest.php +++ b/test/XmlTest.php @@ -15,7 +15,7 @@ * @category Zend * @package Zend_Config * @subpackage UnitTests - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -27,7 +27,7 @@ * @category Zend * @package Zend_Config * @subpackage UnitTests - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * @group Zend_Config */ diff --git a/test/YamlTest.php b/test/YamlTest.php new file mode 100755 index 0000000..4c1e573 --- /dev/null +++ b/test/YamlTest.php @@ -0,0 +1,306 @@ +_iniFileConfig = __DIR__ . '/_files/config.yaml'; + $this->_iniFileAllSectionsConfig = __DIR__ . '/_files/allsections.yaml'; + $this->_iniFileCircularConfig = __DIR__ . '/_files/circular.yaml'; + $this->_nonReadableConfig = __DIR__ . '/_files/nonreadable.yaml'; + $this->_iniFileInvalid = __DIR__ . '/_files/invalid.yaml'; + $this->_iniFileSameNameKeysConfig = __DIR__ . '/_files/array.yaml'; + $this->_badIndentationConfig = __DIR__ . '/_files/badindentation.yaml'; + $this->_booleansConfig = __DIR__ . '/_files/booleans.yaml'; + $this->_constantsConfig = __DIR__ . '/_files/constants.yaml'; + } + + public function testLoadSingleSection() + { + $config = new YamlConfig($this->_iniFileConfig, 'all'); + + $this->assertEquals('all', $config->hostname); + $this->assertEquals('live', $config->db->name); + $this->assertEquals('multi', $config->one->two->three); + $this->assertNull(@$config->nonexistent); // property doesn't exist + } + + public function testSectionInclude() + { + $config = new YamlConfig($this->_iniFileConfig, 'staging'); + + $this->assertEquals('', $config->debug); // only in staging + $this->assertEquals('thisname', $config->name); // only in all + $this->assertEquals('username', $config->db->user); // only in all (nested version) + $this->assertEquals('staging', $config->hostname); // inherited and overridden + $this->assertEquals('dbstaging', $config->db->name); // inherited and overridden + } + + public function testTrueValues() + { + $config = new YamlConfig($this->_iniFileConfig, 'debug'); + + $this->assertInternalType('string', $config->debug); + $this->assertEquals('1', $config->debug); + $this->assertInternalType('string', $config->values->changed); + $this->assertEquals('1', $config->values->changed); + } + + public function testEmptyValues() + { + $config = new YamlConfig($this->_iniFileConfig, 'debug'); + + $this->assertInternalType('string', $config->special->no); + $this->assertEquals('', $config->special->no); + $this->assertInternalType('string', $config->special->null); + $this->assertEquals('', $config->special->null); + $this->assertInternalType('string', $config->special->false); + $this->assertEquals('', $config->special->false); + $this->assertInternalType('string', $config->special->zero); + $this->assertEquals('0', $config->special->zero); + } + + public function testMultiDepthExtends() + { + $config = new YamlConfig($this->_iniFileConfig, 'other_staging'); + + $this->assertEquals('otherStaging', $config->only_in); // only in other_staging + $this->assertEquals('', $config->debug); // 1 level down: only in staging + $this->assertEquals('thisname', $config->name); // 2 levels down: only in all + $this->assertEquals('username', $config->db->user); // 2 levels down: only in all (nested version) + $this->assertEquals('staging', $config->hostname); // inherited from two to one and overridden + $this->assertEquals('dbstaging', $config->db->name); // inherited from two to one and overridden + $this->assertEquals('anotherpwd', $config->db->pass); // inherited from two to other_staging and overridden + } + + public function testErrorNoExtendsSection() + { + $this->setExpectedException('Zend\Config\Exception\RuntimeException', 'cannot be found'); + $config = new YamlConfig($this->_iniFileConfig, 'extendserror'); + } + + public function testZF413_MultiSections() + { + $config = new YamlConfig($this->_iniFileAllSectionsConfig, array('staging','other_staging')); + + $this->assertEquals('otherStaging', $config->only_in); + $this->assertEquals('staging', $config->hostname); + + } + + public function testZF413_AllSections() + { + $config = new YamlConfig($this->_iniFileAllSectionsConfig, null); + $this->assertEquals('otherStaging', $config->other_staging->only_in); + $this->assertEquals('staging', $config->staging->hostname); + } + + public function testZF414() + { + $config = new YamlConfig($this->_iniFileAllSectionsConfig, null); + $this->assertEquals(null, $config->getSectionName()); + $this->assertEquals(true, $config->areAllSectionsLoaded()); + + $config = new YamlConfig($this->_iniFileAllSectionsConfig, 'all'); + $this->assertEquals('all', $config->getSectionName()); + $this->assertEquals(false, $config->areAllSectionsLoaded()); + + $config = new YamlConfig($this->_iniFileAllSectionsConfig, array('staging','other_staging')); + $this->assertEquals(array('staging','other_staging'), $config->getSectionName()); + $this->assertEquals(false, $config->areAllSectionsLoaded()); + } + + public function testZF415() + { + $this->setExpectedException('Zend\Config\Exception\RuntimeException', 'circular inheritance'); + $config = new YamlConfig($this->_iniFileCircularConfig, null); + } + + public function testErrorNoFile() + { + $this->setExpectedException('Zend\Config\Exception\RuntimeException', 'Filename is not set'); + $config = new YamlConfig('',''); + } + + public function testErrorNoSectionFound() + { + try { + $config = new YamlConfig($this->_iniFileConfig,array('all', 'notthere')); + $this->fail('An expected exception has not been raised'); + } catch (Exception\RuntimeException $expected) { + $this->assertContains('cannot be found', $expected->getMessage()); + } + + try { + $config = new YamlConfig($this->_iniFileConfig,'notthere'); + $this->fail('An expected exception has not been raised'); + } catch (Exception\RuntimeException $expected) { + $this->assertContains('cannot be found', $expected->getMessage()); + } + + } + + public function testZF3196_InvalidIniFile() + { + try { + $config = new YamlConfig($this->_iniFileInvalid); + $this->fail('An expected exception has not been raised'); + } catch (Exception\RuntimeException $expected) { + $this->assertRegexp('/(Error parsing|syntax error, unexpected)/', $expected->getMessage()); + } + + } + + public function testZF2285_MultipleKeysOfTheSameName() + { + $config = new YamlConfig($this->_iniFileSameNameKeysConfig, null); + $this->assertEquals('2a', $config->one->two->{0}); + $this->assertEquals('2b', $config->one->two->{1}); + $this->assertEquals('4', $config->three->four->{1}); + $this->assertEquals('5', $config->three->four->{0}->five); + } + + public function testZF2437_ArraysWithMultipleChildren() + { + $config = new YamlConfig($this->_iniFileSameNameKeysConfig, null); + $this->assertEquals('1', $config->six->seven->{0}->eight); + $this->assertEquals('2', $config->six->seven->{1}->eight); + $this->assertEquals('3', $config->six->seven->{2}->eight); + $this->assertEquals('1', $config->six->seven->{0}->nine); + $this->assertEquals('2', $config->six->seven->{1}->nine); + $this->assertEquals('3', $config->six->seven->{2}->nine); + } + + public function yamlDecoder($string) + { + return YamlConfig::decode($string); + } + + public function testHonorsOptionsProvidedToConstructor() + { + $config = new YamlConfig($this->_iniFileAllSectionsConfig, 'debug', array( + 'allow_modifications' => true, + 'skip_extends' => true, + 'yaml_decoder' => array($this, 'yamlDecoder'), + 'foo' => 'bar', // ignored + )); + $this->assertNull($config->name); // verifies extends were skipped + $config->foo = 'bar'; + $this->assertEquals('bar', $config->foo); // verifies allows modifications + $this->assertEquals(array($this, 'yamlDecoder'), $config->getYamlDecoder()); + } + + public function testConstructorRaisesExceptionWhenUnableToLoadFile() + { + $this->setExpectedException('Zend\Config\Exception\RuntimeException', 'file_get_contents'); + $config = new YamlConfig('__foo__'); + } + + public function testBadIndentationRaisesException() + { + $this->setExpectedException('Zend\Config\Exception\RuntimeException', 'unsupported syntax'); + $config = new YamlConfig($this->_badIndentationConfig, 'all'); + } + + public function testPassingBadYamlDecoderRaisesException() + { + $this->setExpectedException('Zend\Config\Exception\InvalidArgumentException', 'must be callable'); + $config = new YamlConfig($this->_iniFileAllSectionsConfig, 'debug', array( + 'yaml_decoder' => '__foo__', + )); + } + + public function testParsesBooleansAccordingToOneDotOneSpecification() + { + $config = new YamlConfig($this->_booleansConfig, 'production'); + + $this->assertTrue($config->usingLowerCasedYes); + $this->assertTrue($config->usingTitleCasedYes); + $this->assertTrue($config->usingCapitalYes); + $this->assertTrue($config->usingLowerY); + $this->assertTrue($config->usingUpperY); + + $this->assertFalse($config->usingLowerCasedNo); + $this->assertFalse($config->usingTitleCasedNo); + $this->assertFalse($config->usingCapitalNo); + $this->assertFalse($config->usingLowerN); + $this->assertFalse($config->usingUpperN); + + $this->assertTrue($config->usingLowerCasedTrue); + $this->assertTrue($config->usingTitleCasedTrue); + $this->assertTrue($config->usingCapitalTrue); + + $this->assertFalse($config->usingLowerCasedFalse); + $this->assertFalse($config->usingTitleCasedFalse); + $this->assertFalse($config->usingCapitalFalse); + + $this->assertTrue($config->usingLowerCasedOn); + $this->assertTrue($config->usingTitleCasedOn); + $this->assertTrue($config->usingCapitalOn); + + $this->assertFalse($config->usingLowerCasedOff); + $this->assertFalse($config->usingTitleCasedOff); + $this->assertFalse($config->usingCapitalOff); + } + + public function testHonorsPhpConstants() + { + if (!defined('ZEND_CONFIG_YAML_ENV')) { + define('ZEND_CONFIG_YAML_ENV', 'testing'); + } + if (!defined('ZEND_CONFIG_YAML_ENV_PATH')) { + define('ZEND_CONFIG_YAML_ENV_PATH', __DIR__); + } + $config = new YamlConfig($this->_constantsConfig, 'production'); + $this->assertEquals(ZEND_CONFIG_YAML_ENV, $config->env); + $this->assertEquals(ZEND_CONFIG_YAML_ENV_PATH . '/test/this', $config->path); + } + + public function testAllowsIgnoringConstantStrings() + { + if (!defined('ZEND_CONFIG_YAML_ENV')) { + define('ZEND_CONFIG_YAML_ENV', 'testing'); + } + if (!defined('ZEND_CONFIG_YAML_ENV_PATH')) { + define('ZEND_CONFIG_YAML_ENV_PATH', __DIR__); + } + $config = new YamlConfig( + $this->_constantsConfig, 'production', array('ignore_constants' => true) + ); + $this->assertEquals('ZEND_CONFIG_YAML_ENV', $config->env); + $this->assertEquals('ZEND_CONFIG_YAML_ENV_PATH/test/this', $config->path); + } +} diff --git a/test/_files/allsections.json b/test/_files/allsections.json new file mode 100644 index 0000000..8b25955 --- /dev/null +++ b/test/_files/allsections.json @@ -0,0 +1 @@ +{"all":{"hostname":"all","name":"thisname","db":{"host":"127.0.0.1","user":"username","pass":"password","name":"live"},"one":{"two":{"three":"multi"}}},"staging":{"_extends":"all","db":{"name":"dbstaging"},"debug":false},"debug":{"_extends":"all","db":{"name":"dbdebug"},"debug":true,"values":{"changed":true},"special":{"no":"no","null":null,"false":false}},"other_staging":{"only_in":"otherStaging","db":{"pass":"anotherpwd"}}} \ No newline at end of file diff --git a/test/_files/allsections.yaml b/test/_files/allsections.yaml new file mode 100755 index 0000000..1dafe98 --- /dev/null +++ b/test/_files/allsections.yaml @@ -0,0 +1,35 @@ +all: +# this is a comment + hostname: all + name: thisname + db: + host: 127.0.0.1 + user: username + pass: password + name: live + one: + two: + three: multi + +staging: + hostname: staging + db: + name: dbstaging + debug: + _extends: all +debug: + hostname: debug + debug: 1 + values: + changed: 1 + db: + name: dbdebug + special: + no: + null: + false: + _extends: all +other_staging: + only_in: otherStaging + db: + pass: anotherpwd diff --git a/test/_files/array.yaml b/test/_files/array.yaml new file mode 100755 index 0000000..31eaaf8 --- /dev/null +++ b/test/_files/array.yaml @@ -0,0 +1,22 @@ +one: + two: + - 2a + - 2b +three: + four: + - + five: 5 + - 4 + - + five: 5 +six: + seven: + - + eight: 1 + nine: 1 + - + eight: 2 + nine: 2 + - + eight: 3 + nine: 3 diff --git a/test/_files/badindentation.yaml b/test/_files/badindentation.yaml new file mode 100644 index 0000000..12e09a2 --- /dev/null +++ b/test/_files/badindentation.yaml @@ -0,0 +1,6 @@ +all: + hostname: all + name: thisname + foo: + bar + baz diff --git a/test/_files/booleans.yaml b/test/_files/booleans.yaml new file mode 100644 index 0000000..67a9277 --- /dev/null +++ b/test/_files/booleans.yaml @@ -0,0 +1,29 @@ +production: + usingLowerCasedYes: yes + usingTitleCasedYes: Yes + usingCapitalYes: YES + usingLowerY: y + usingUpperY: Y + + usingLowerCasedNo: no + usingTitleCasedNo: No + usingCapitalNo: NO + usingLowerN: n + usingUpperN: N + + usingLowerCasedTrue: true + usingTitleCasedTrue: True + usingCapitalTrue: TRUE + + usingLowerCasedFalse: false + usingTitleCasedFalse: False + usingCapitalFalse: FALSE + + usingLowerCasedOn: on + usingTitleCasedOn: On + usingCapitalOn: ON + + usingLowerCasedOff: off + usingTitleCasedOff: Off + usingCapitalOff: OFF + diff --git a/test/_files/circular.json b/test/_files/circular.json new file mode 100644 index 0000000..8c2f248 --- /dev/null +++ b/test/_files/circular.json @@ -0,0 +1 @@ +{"A":{"_extends":"C","someKey":"value_A"},"B":{"_extends":"A","someKey":"value_B"},"C":{"_extends":"B","someKey":"value_C"}} \ No newline at end of file diff --git a/test/_files/circular.yaml b/test/_files/circular.yaml new file mode 100755 index 0000000..f6c760e --- /dev/null +++ b/test/_files/circular.yaml @@ -0,0 +1,9 @@ +A: + someKey: value_A + _extends: C +B: + someKey: value_B + _extends: A +C: + someKey: value_C + _extends: B diff --git a/test/_files/config.json b/test/_files/config.json new file mode 100644 index 0000000..ebeb16c --- /dev/null +++ b/test/_files/config.json @@ -0,0 +1 @@ +{"all":{"hostname":"all","name":"thisname","db":{"host":"127.0.0.1","user":"username","pass":"password","name":"live"},"one":{"two":{"three":"multi"}}},"staging":{"_extends":"all","hostname":"staging","db":{"name":"dbstaging"},"debug":false},"debug":{"_extends":"all","db":{"name":"dbdebug"},"debug":true,"values":{"changed":true},"special":{"no":"no","null":null,"false":false}},"other_staging":{"_extends":"staging","only_in":"otherStaging","db":{"pass":"anotherpwd"}},"extendserror":{"_extends":"nonexistent","testing":123}} diff --git a/test/_files/config.yaml b/test/_files/config.yaml new file mode 100755 index 0000000..3fa7d37 --- /dev/null +++ b/test/_files/config.yaml @@ -0,0 +1,38 @@ +all: + hostname: all + name: thisname + db: + host: 127.0.0.1 + user: username + pass: password + name: live + one: + two: + three: multi +staging: + hostname: staging + db: + name: dbstaging + debug: + _extends: all +debug: + hostname: debug + debug: 1 + values: + changed: 1 + db: + name: dbdebug + special: + no: + null: + false: + zero: 0 + _extends: all +other_staging: + only_in: otherStaging + db: + pass: anotherpwd + _extends: staging +extendserror: + testing: 123 + _extends: notexistent diff --git a/test/_files/constants.yaml b/test/_files/constants.yaml new file mode 100644 index 0000000..2dbf595 --- /dev/null +++ b/test/_files/constants.yaml @@ -0,0 +1,3 @@ +production: + env: ZEND_CONFIG_YAML_ENV + path: ZEND_CONFIG_YAML_ENV_PATH/test/this diff --git a/test/_files/invalid.json b/test/_files/invalid.json new file mode 100644 index 0000000..613fa3a --- /dev/null +++ b/test/_files/invalid.json @@ -0,0 +1 @@ +{"default":{"foo":/("bar)}} diff --git a/test/_files/invalid.yaml b/test/_files/invalid.yaml new file mode 100755 index 0000000..1308c3b --- /dev/null +++ b/test/_files/invalid.yaml @@ -0,0 +1,2 @@ +yaml: + what? \ No newline at end of file diff --git a/test/_files/multipleinheritance.json b/test/_files/multipleinheritance.json new file mode 100644 index 0000000..d51fde3 --- /dev/null +++ b/test/_files/multipleinheritance.json @@ -0,0 +1 @@ +{"one":{"one":1},"two":{"two":2},"multiinherit":{"_extends":["one","two"]}} \ No newline at end of file diff --git a/test/_files/nested.json b/test/_files/nested.json new file mode 100644 index 0000000..11835d8 --- /dev/null +++ b/test/_files/nested.json @@ -0,0 +1,54 @@ +{ + "testing": { + "definitions": [ + { + "class": "Zend\\Di\\TestAsset\\Struct", + "params": { + "param1": "foo", + "param2": "bar" + }, + "param_map": { + "param1": 0, + "param2": 1 + } + }, + { + "class": "Zend\\Di\\TestAsset\\DummyParams", + "constructor_callback": { + "class": "Zend\\Di\\TestAsset\\StaticFactory", + "method": "factory" + }, + "params": { + "struct": { "__reference": "struct" }, + "params": {"foo": "bar"} + }, + "param_map": { + "struct": 0, + "params": 1 + } + }, + { + "class": "Zend\\Di\\TestAsset\\InjectedMethod", + "methods": [ + { + "name": "setObject", + "args": [ { "__reference": "params" } ] + } + ] + }, + { + "class": "Zend\\Di\\TestAsset\\InspectedClass", + "params": { + "baz": "BAZ", + "foo": "FOO" + } + } + ], + "aliases": { + "struct": "Zend\\Di\\TestAsset\\Struct", + "params": "Zend\\Di\\TestAsset\\DummyParams", + "injected": "Zend\\Di\\TestAsset\\InjectedMethod", + "inspected": "Zend\\Di\\TestAsset\\InspectedClass" + } + } +} diff --git a/test/_files/nosections.json b/test/_files/nosections.json new file mode 100644 index 0000000..ac25dc3 --- /dev/null +++ b/test/_files/nosections.json @@ -0,0 +1 @@ +{"hostname":"all","one":{"two":"two","three":{"four":4,"five":5}}} \ No newline at end of file