Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: xylophoneio/xylophone
base: 39e622bf9d
...
head fork: xylophoneio/xylophone
compare: 8df6d9b7ad
Checking mergeability… Don't worry, you can still create the pull request.
  • 6 commits
  • 19 files changed
  • 0 commit comments
  • 1 contributor
Commits on Feb 12, 2014
@dchill42 dchill42 Moved Config test
Signed-off-by: Darren Hill <dchill42@gmail.com>
112d2c9
Commits on Feb 18, 2014
@dchill42 dchill42 Moved exceptions to individual files for autoloading
Signed-off-by: Darren Hill <dchill42@gmail.com>
e4f35dd
@dchill42 dchill42 Restructured Travis test suites
Signed-off-by: Darren Hill <dchill42@gmail.com>
4011a89
@dchill42 dchill42 Converted XylophoneTest to use getMock()
Signed-off-by: Darren Hill <dchill42@gmail.com>
c611643
@dchill42 dchill42 Converted exit to exception, removed systemUrl(), and did test-based …
…cleanup

Signed-off-by: Darren Hill <dchill42@gmail.com>
6027865
@dchill42 dchill42 Added ConfigTest
Signed-off-by: Darren Hill <dchill42@gmail.com>
8df6d9b
View
22 .travis.yml
@@ -5,14 +5,16 @@ php:
- 5.4
- 5.5
-#env:
-# - DB=mysql
-# - DB=mysqli
-# - DB=pgsql
-# - DB=sqlite
-# - DB=pdo/mysql
-# - DB=pdo/pgsql
-# - DB=pdo/sqlite
+env:
+ - SUITE=core
+# - SUITE=libraries
+# - SUITE=database/mysql
+# - SUITE=database/mysqli
+# - SUITE=database/pgsql
+# - SUITE=database/sqlite
+# - SUITE=database/pdo/mysql
+# - SUITE=database/pdo/pgsql
+# - SUITE=database/pdo/sqlite
before_script:
- composer install --dev --no-progress
@@ -20,8 +22,8 @@ before_script:
# - sh -c "if [ '$DB' = 'pgsql' ] || [ '$DB' = 'pdo/pgsql' ]; then psql -c 'create database ci_test;' -U postgres; fi"
# - sh -c "if [ '$DB' = 'mysql' ] || [ '$DB' = 'mysqli' ] || [ '$DB' = 'pdo/mysql' ]; then mysql -e 'create database IF NOT EXISTS ci_test;'; fi"
-#script: phpunit --coverage-text --configuration tests/travis/$DB.phpunit.xml
-script: phpunit --coverage-text --configuration tests/phpunit.xml
+script: phpunit --coverage-text --configuration tests/travis/$SUITE/phpunit.xml
+#script: phpunit --coverage-text --configuration tests/phpunit.xml
branches:
only:
View
49 system/core/AlFineException.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Xylophone
+ *
+ * An open source HMVC application development framework for PHP 5.3 or newer
+ * Derived from CodeIgniter, Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to licensing@xylophone.io
+ * so we can send you a copy immediately.
+ *
+ * @package Xylophone
+ * @author Xylophone Dev Team, EllisLab Dev Team
+ * @copyright Copyright (c) 2014, Xylophone Team (http://xylophone.io/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://xylophone.io
+ * @since Version 1.0
+ * @filesource
+ */
+namespace Xylophone\core;
+
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * Al Fine Exception
+ *
+ * This exception may be thrown when the application has completed its output
+ * (early) and needs to skip to the end (al fine) of processing and exit cleanly.
+ * It is particularly useful when a module takes over the request and generates
+ * output in place of the normal controller output (such as a login prompt).
+ *
+ * @codeCoverageIgnore
+ *
+ * @package Xylophone
+ * @subpackage core
+ */
+class AlFineException extends \Exception
+{
+ // Nothing to see here - just a name
+}
+
View
49 system/core/AutoloadException.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Xylophone
+ *
+ * An open source HMVC application development framework for PHP 5.3 or newer
+ * Derived from CodeIgniter, Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to licensing@xylophone.io
+ * so we can send you a copy immediately.
+ *
+ * @package Xylophone
+ * @author Xylophone Dev Team, EllisLab Dev Team
+ * @copyright Copyright (c) 2014, Xylophone Team (http://xylophone.io/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://xylophone.io
+ * @since Version 1.0
+ * @filesource
+ */
+namespace Xylophone\core;
+
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * Autoloader Exception
+ *
+ * This exception is thrown by the autoloader when a class file cannot be found.
+ * Doing so bypasses the fatal class-not-found PHP error and lets the framework
+ * catch the exception and try another namespace, generating its own error if
+ * none are found.
+ *
+ * @codeCoverageIgnore
+ *
+ * @package Xylophone
+ * @subpackage core
+ */
+class AutoloadException extends \Exception
+{
+ // Nothing to see here - just a name
+}
+
View
72 system/core/Config.php
@@ -61,10 +61,9 @@ public function __construct()
// Read the config file
$this->config = $this->get('config.php', 'config');
if (!is_array($this->config)) {
- header('HTTP/1.1 503 Service Unavailable.', true, 503);
- echo $this->config === false ? 'The configuration file does not exist.' :
+ $msg = ($this->config === false) ? 'The configuration file does not exist.' :
'The configuration file is invalid.';
- exit(EXIT_CONFIG);
+ throw new ExitException($msg);
}
// Set the base_url automatically if none was provided
@@ -110,24 +109,24 @@ public function load($file = '', $sections = false, $graceful = false)
if ($graceful) {
return false;
}
- $XY->showError('The configuration file '.$name.'.php does not exist.');
+ return $XY->showError('The configuration file '.$name.'.php does not exist.');
}
else if (is_string($config)) {
if ($graceful) {
return false;
}
- $XY->showError('Your '.$name.'.php file does not appear to contain a valid configuration array.');
+ return $XY->showError('Your '.$name.'.php file does not appear to contain a valid configuration array.');
}
// Check for sections
if ($sections === true) {
// Merge or set section
$this->config[$name] = isset($this->config[$name]) ?
- array_merge_recursive($this->config[$name], $config) : $this->config[$name] = $config;
+ array_replace_recursive($this->config[$name], $config) : $this->config[$name] = $config;
}
else {
// Merge config
- $this->config = array_merge_recursive($this->config, $config);
+ $this->config = array_replace_recursive($this->config, $config);
}
// Mark file as loaded
@@ -193,7 +192,8 @@ public function getExtra($_file, $_name, &$_extras)
if ($_extras !== false) {
// Get associative array of public vars
foreach (get_defined_vars() as $_key => $_var) {
- $_key[0] !== '_' && $_key !== $_name && $_extras[$_key] = $_var;
+ $_key[0] !== '_' && $_key !== $_name && $_key !== 'this' && $_key != 'XY' &&
+ $_extras[$_key] = $_var;
}
}
@@ -235,7 +235,7 @@ public function item($item, $index = '')
if ($index === '') {
return isset($this->config[$item]) ? $this->config[$item] : null;
}
- return isset($this->config[$index], $this->config[$index][$item]) ? $this->config[$index][$item] : null;
+ return isset($this->config[$index][$item]) ? $this->config[$index][$item] : null;
}
/**
@@ -269,34 +269,37 @@ public function slashItem($item)
*/
public function siteUrl($uri = '', $protocol = null)
{
+ // Get base URL and replace protocol if specified
$base_url = $this->slashItem('base_url');
isset($protocol) && $base_url = $protocol.substr($base_url, strpos($base_url, '://'));
+ // Check for URI
if (empty($uri)) {
+ // Done here
return $base_url.$this->item('index_page');
}
+ // Clean URI string and check for query strings
$uri = $this->uriString($uri);
+ if ($this->item('enable_query_strings')) {
+ // Assemble base URL with URI string
+ return $base_url.$this->item('index_page').$uri;
+ }
- if ($this->item('enable_query_strings') === false) {
- $suffix = isset($this->config['url_suffix']) ? $this->config['url_suffix'] : '';
-
- if ($suffix !== '') {
- if (($offset = strpos($uri, '?')) !== false) {
- $uri = substr($uri, 0, $offset).$suffix.substr($uri, $offset);
- }
- else {
- $uri .= $suffix;
- }
+ // Check for URL suffix
+ $suffix = isset($this->config['url_suffix']) ? $this->config['url_suffix'] : '';
+ if ($suffix !== '') {
+ // Add suffix before any query string
+ if (($offset = strpos($uri, '?')) === false) {
+ $uri .= $suffix;
+ }
+ else {
+ $uri = substr($uri, 0, $offset).$suffix.substr($uri, $offset);
}
-
- return $base_url.$this->slashItem('index_page').$uri;
- }
- elseif (strpos($uri, '?') === false) {
- $uri = '?'.$uri;
}
- return $base_url.$this->item('index_page').$uri;
+ // Return base URL with URI string
+ return $base_url.$this->slashItem('index_page').$uri;
}
/**
@@ -328,30 +331,19 @@ public function baseUrl($uri = '', $protocol = null)
*/
protected function uriString($uri)
{
- if ($this->item('enable_query_strings') === false) {
+ if (!$this->item('enable_query_strings')) {
is_array($uri) && $uri = implode('/', $uri);
return trim($uri, '/');
}
elseif (is_array($uri)) {
- return http_build_query($uri);
+ $uri = http_build_query($uri);
}
+ strpos($uri, '?') === false && $uri = '?'.$uri;
return $uri;
}
/**
- * System URL
- *
- * @return string System URL
- */
- public function systemUrl()
- {
- global $XY;
- $x = explode('/', preg_replace('|/*(.+?)/*$|', '\\1', $XY->system_path));
- return $this->slashItem('base_url').end($x).'/';
- }
-
- /**
* Set a config file item
*
* @param mixed $item Config item key or array of config items
@@ -363,7 +355,7 @@ public function setItem($item, $value = '')
// Check for multiple items
if (is_array($item)) {
// Merge into config
- $this->config = array_merge_recursive($this->config, $item);
+ $this->config = array_replace_recursive($this->config, $item);
}
else {
// Set single item
View
47 system/core/ExitException.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Xylophone
+ *
+ * An open source HMVC application development framework for PHP 5.3 or newer
+ * Derived from CodeIgniter, Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to licensing@xylophone.io
+ * so we can send you a copy immediately.
+ *
+ * @package Xylophone
+ * @author Xylophone Dev Team, EllisLab Dev Team
+ * @copyright Copyright (c) 2014, Xylophone Team (http://xylophone.io/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://xylophone.io
+ * @since Version 1.0
+ * @filesource
+ */
+namespace Xylophone\core;
+
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * Exit Exception
+ *
+ * This exception may be thrown anywhere the application needs to exit with
+ * a message and an error code.
+ *
+ * @codeCoverageIgnore
+ *
+ * @package Xylophone
+ * @subpackage core
+ */
+class ExitException extends \Exception
+{
+ // Nothing to see here - just a name
+}
+
View
54 system/core/Xylophone.php
@@ -30,49 +30,6 @@
defined('BASEPATH') OR exit('No direct script access allowed');
/**
- * Al Fine Exception
- *
- * This exception may be thrown when the application has completed its output
- * (early) and needs to skip to the end (al fine) of processing and exit cleanly.
- * It is particularly useful when a module takes over the request and generates
- * output in place of the normal controller output (such as a login prompt).
- *
- * @codeCoverageIgnore
- *
- * @package Xylophone
- * @subpackage core
- */
-class AlFineException extends \Exception { }
-
-/**
- * Exit Exception
- *
- * This exception may be thrown anywhere the application needs to exit with
- * a message and an error code.
- *
- * @codeCoverageIgnore
- *
- * @package Xylophone
- * @subpackage core
- */
-class ExitException extends \Exception { }
-
-/**
- * Autoloader Exception
- *
- * This exception is thrown by the autoloader when a class file cannot be found.
- * Doing so bypasses the fatal class-not-found PHP error and lets the framework
- * catch the exception and try another namespace, generating its own error if
- * none are found.
- *
- * @codeCoverageIgnore
- *
- * @package Xylophone
- * @subpackage core
- */
-class AutoloadException extends \Exception { }
-
-/**
* Xylophone Framework Class
*
* @package Xylophone
@@ -188,6 +145,7 @@ public static function instance($init = null)
// Check namespaces after application
if (!$app && !$ns) {
// Fail out
+ include_once('ExitException.php');
$msg = 'The global namespace is reserved for application classes. '.
'Please specify a namespace for your additional path in the following file: '.
basename($_SERVER['PHP_SELF']);
@@ -207,6 +165,7 @@ public static function instance($init = null)
}
if (!$resolved) {
// Fail out
+ include_once('ExitException.php');
$msg = ($app ? 'Your application folder path does not appear to be set correctly.' :
'The "'.$ns.'" namespace path does not appear to be set correctly.').
' Please fix it in the following file: '.basename($_SERVER['PHP_SELF']);
@@ -479,7 +438,7 @@ protected function playVerse($benchmark)
try {
$this->callController($this->router->route) || $this->show404($class.'/'.$method);
} catch (AlFineException $ex) {
- // Finished early - nothing to do herek
+ // Finished early - nothing to do here but carry on to the end
}
// Mark end time, display output unless overridden, and call post_system
@@ -638,7 +597,7 @@ public function loadClass($name, $hint, $param = null, $param2 = null)
* @param string $path Path to source files
* @return bool TRUE on success, otherwise FALSE
*/
- public function addNamespace($namespace, $path)
+ public function addNamespace($namespace, $path = '')
{
// Convert to array
is_array($namespace) || $namespace = array($namespace => $path);
@@ -966,7 +925,10 @@ public function autoloader($class)
}
}
- // File not found - throw exception
+ // File not found - throw exception (unless it WAS the exception)
+ if (trim($class, '\\') == 'Xylophone\core\AutoloadException') {
+ return;
+ }
throw new AutoloadException('Could not find class "'.$class.'"');
}
View
231 tests/Mocks/core/Xylophone.php
@@ -37,29 +37,11 @@ class Xylophone extends \Xylophone\core\Xylophone
/** @var array Relative path resolution bases (made public) */
public $resolve_bases = array();
- /** @var array PHP version comparison results (made public) */
- public $is_php = array();
-
/** @var string Autoloader hint (made public) */
public $loader_hint = '';
- /** @var array Pre-loaded classes to return from loadClass() */
- public $load_class = array();
-
- /** @var bool Return value for callController() */
- public $call_controller = null;
-
- /** @var array Test arguments for play() */
- public $play_args = array();
-
- /** @var array Arguments passed to show404() */
- public $show_404 = null;
-
- /** @var bool Skip initialize() flag */
- public static $skip_init = false;
-
- /** @var bool Skip setHandlers() flag */
- public static $skip_handlers = false;
+ /** @var bool Skip tune() flag */
+ public static $skip_tune = false;
/**
* Initialize framework
@@ -69,215 +51,10 @@ class Xylophone extends \Xylophone\core\Xylophone
* @param array $init Initialization parameters
* @return void
*/
- public function initialize($init)
+ public function tune($init)
{
// Call the real method unless we're skipping
- self::$skip_init || parent::initialize($init);
- }
-
- /**
- * Load a class
- *
- * This overalod allows us to return mock objects instead of running the real method.
- *
- * @param string $name Class name with optional namespace
- * @param string $hint Namespace hint (if namespace not provided) - forward slashes
- * @param mixed $param Optional constructor parameter
- * @param mixed $param2 Optional second constructor parameter
- * @return object Class object on success, otherwise NULL
- */
- public function loadClass($name, $hint, $param = null, $param2 = null)
- {
- // Intercept pre-loaded classes
- $class = $hint.'\\'.$name;
- if (isset($this->load_class[$class])) {
- return $this->load_class[$class];
- }
-
- // Otherwise call the real method
- return parent::loadClass($name, $hint, $param, $param2);
- }
-
- /**
- * Call a controller method
- *
- * This overload allows us to conditionally run the real callController method.
- *
- * @param mixed $class Class name string or route stack array
- * @param string $method Method name (unless $class is stack)
- * @param array $args Arguments array (unless $class is stack)
- * @param string $name Optional object name
- * @param bool $return Whether to return output
- * @return mixed Output if $return, TRUE on success, otherwise FALSE
- */
- public function callController($class, $method = '', array $args = array(), $name = '', $return = false)
- {
- // Check for return value
- if ($this->call_controller !== null) {
- // Check for exception to throw
- if (is_string($this->call_controller)) {
- throw new $this->call_controller();
- }
-
- // Swap return value with $class arg and return
- $ret = $this->call_controller;
- $this->call_controller = $class;
- return $ret;
- }
-
- // Otherwise call the real method
- return parent::callController($class, $method, $args, $name, $return);
- }
-
- /**
- * Play Introduction
- *
- * This overload allows us to conditionally run the real playIntro method.
- *
- * @param mixed $benchmark Initial benchmark time or FALSE
- * @param array $config Reference to bootstrap config items
- * @return array Reference to autoload config array
- */
- public function &playIntro($benchmark, &$config)
- {
- // Check for test args
- if (isset($this->play_args['intro_atl'])) {
- $this->play_args['intro_bmk'] = $benchmark;
- $this->play_args['intro_cfg'] =& $config;
- return $this->play_args['intro_atl'];
- }
-
- // Otherwise call the real method
- return parent::playIntro($benchmark, $config);
- }
-
- /**
- * Play Bridge
- *
- * This overload allows us to conditionally run the real playBridge method.
- *
- * @param array $routing Routing overrides
- * @return void
- */
- public function playBridge(&$routing)
- {
- // Check for test args
- if (!empty($this->play_args)) {
- $this->play_args['bridge_rtg'] =& $routing;
- return;
- }
-
- // Otherwise call the real method
- return parent::playBridge($routing);
- }
-
- /**
- * Play Coda
- *
- * This overload allows us to conditionally run the real playCoda method.
- *
- * @return bool TRUE if cache output, otherwise FALSE
- */
- public function playCoda()
- {
- // Check for test args
- if (isset($this->play_args['coda_ret'])) {
- return $this->play_args['coda_ret'];
- }
-
- // Otherwise call the real method
- return parent::playCoda();
- }
-
- /**
- * Play Chorus
- *
- * This overload allows us to conditionally run the real playChorus method.
- *
- * @param mixed $benchmark Benchmark flag
- * @param array $autoload Reference to autoload config array
- * @return void
- */
- public function playChorus($benchmark, &$autoload)
- {
- // Check for test args
- if (!empty($this->play_args)) {
- $this->play_args['chorus_bmk'] = $benchmark;
- $this->play_args['chorus_atl'] =& $autoload;
- return;
- }
-
- // Otherwise call the real method
- return parent::playChorus($benchmark, $autoload);
- }
-
- /**
- * Play Verse
- *
- * This overload allows us to conditionally run the real playVerse method.
- *
- * @param mixed $benchmark Benchmark flag
- * @return void
- */
- public function playVerse($benchmark)
- {
- // Check for test args
- if (!empty($this->play_args)) {
- $this->play_args['verse_bmk'] = $benchmark;
- return;
- }
-
- // Otherwise call the real method
- return parent::playVerse($benchmark);
- }
-
- /**
- * Show 404 error to user
- *
- * This function is similar to showError() above, but it displays a 404 error.
- *
- * @param string $page Page URL
- * @param bool $log_error Whether to log the error
- * @return void
- */
- public function show404($page = '', $log_error = true)
- {
- // Check for arguments array
- if (is_array($this->show_404)) {
- // Add page argument to array
- $this->show_404[] = $page;
- return;
- }
-
- // Otherwise call the real method
- return parent::show404($page, $log_error);
- }
-
- /**
- * Register autoloader, error, and shutdown handlers
- *
- * This overload allows us to conditionally run the real registerHandlers method.
- *
- * @return void
- */
- public function registerHandlers()
- {
- // Call the real method unless we're skipping
- self::$skip_handlers || parent::registerHandlers();
- }
-
- /**
- * Get real path
- *
- * This abstraction of the realpath call allows overriding for unit testing
- *
- * @param string $path Path to resolve
- * @return string Real path
- */
- protected function realpath($path)
- {
- // Just trim trailing slash since realpath() fails on VFS urls
- return rtrim($path, '\/');
+ self::$skip_tune || parent::tune($init);
}
}
View
801 tests/Xylophone/core/ConfigTest.php
@@ -0,0 +1,801 @@
+<?php
+/**
+ * Xylophone
+ *
+ * An open source HMVC application development framework for PHP 5.3 or newer
+ * Derived from CodeIgniter, Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to licensing@xylophone.io
+ * so we can send you a copy immediately.
+ *
+ * @package Xylophone
+ * @author Xylophone Dev Team, EllisLab Dev Team
+ * @copyright Copyright (c) 2014, Xylophone Team (http://xylophone.io/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://xylophone.io
+ * @since Version 1.0
+ * @filesource
+ */
+
+/**
+ * Config Unit Test
+ *
+ * @package Xylophone
+ */
+class ConfigTest extends XyTestCase
+{
+ /**
+ * Test __construct()
+ */
+ public function testConstruct()
+ {
+ // Mock Config and set up call
+ $config = $this->getMock('Xylophone\core\Config', array('get'), array(), '', false);
+ $cfg = array('base_url' => 'http://example.com/');
+ $config->expects($this->once())->method('get')->
+ with($this->equalTo('config.php'), $this->equalTo('config'))->
+ will($this->returnValue($cfg));
+
+ // Verify config and is_loaded are empty
+ $this->assertEmpty($config->config);
+ $this->assertEmpty($config->is_loaded);
+
+ // Call __construct() (yes, after instantiation) and confirm base config
+ $config->__construct();
+ $this->assertEquals($cfg, $config->config);
+ }
+
+ /**
+ * Test __construct() with no config
+ */
+ public function testConstructNoConfig()
+ {
+ // Mock Config and set up call
+ $config = $this->getMock('Xylophone\core\Config', array('get'), array(), '', false);
+ $config->expects($this->once())->method('get')->will($this->returnValue(false));
+
+ // Call __construct() (yes, again) and confirm exception
+ $this->setExpectedException('Xylophone\core\ExitException', 'The configuration file does not exist.');
+ $config->__construct();
+ }
+
+ /**
+ * Test __construct() with a bad config
+ */
+ public function testConstructBadConfig()
+ {
+ // Mock Config and set up call
+ $config = $this->getMock('Xylophone\core\Config', array('get'), array(), '', false);
+ $config->expects($this->once())->method('get')->will($this->returnValue('/some/bad/path'));
+
+ // Call __construct() (some more) and confirm exception
+ $this->setExpectedException('Xylophone\core\ExitException', 'The configuration file is invalid.');
+ $config->__construct();
+ }
+
+ /**
+ * Test __construct() with no base_url
+ */
+ public function testConstructNoBase()
+ {
+ global $XY;
+
+ // Set up args
+ $path = '/test/path/';
+ $host = 'testhost.com';
+ $url = 'http://'.$host.$path;
+
+ // Mock Xylophone and Config and set up calls
+ $XY = $this->getMock('Xylophone\core\Xylophone', array(), array(), '', false);
+ $config = $this->getMock('Xylophone\core\Config', array('get', 'setItem'), array(), '', false);
+ $config->expects($this->once())->method('get')->will($this->returnValue(array()));
+ $config->expects($this->once())->method('setItem')->
+ with($this->equalTo('base_url'), $this->equalTo($url));
+ $XY->expects($this->once())->method('isHttps')->will($this->returnValue(false));
+
+ // Set server vars
+ $http = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null;
+ $_SERVER['HTTP_HOST'] = $host;
+ $script = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : null;
+ $_SERVER['SCRIPT_NAME'] = $path.'file';
+
+ // Call __construct() (ad nauseum)
+ $config->__construct();
+
+ // Clean up
+ if ($script === null) {
+ unset($_SERVER['SCRIPT_NAME']);
+ }
+ else {
+ $_SERVER['SCRIPT_NAME'] = $script;
+ }
+ if ($http === null) {
+ unset($_SERVER['HTTP_HOST']);
+ }
+ else {
+ $_SERVER['HTTP_HOST'] = $http;
+ }
+ }
+
+ /**
+ * Test __construct() with no base_url and no host
+ */
+ public function testConstructNoBaseHost()
+ {
+ // Mock Config and set up calls
+ $config = $this->getMock('Xylophone\core\Config', array('get', 'setItem'), array(), '', false);
+ $config->expects($this->once())->method('get')->will($this->returnValue(array()));
+ $config->expects($this->once())->method('setItem')->
+ with($this->equalTo('base_url'), $this->equalTo('http://localhost/'));
+
+ // Set server vars
+ $http = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null;
+ unset($_SERVER['HTTP_HOST']);
+
+ // Call __construct() (one last time)
+ $config->__construct();
+
+ // Clean up
+ $http === null || $_SERVER['HTTP_HOST'] = $http;
+ }
+
+ /**
+ * Test load()
+ */
+ public function testLoad()
+ {
+ global $XY;
+
+ // Set up args
+ $name = 'testcfg';
+ $file = $name.'.php';
+ $cfg = array('one' => '1', 'two' => '2', 'three' => '3');
+
+ // Mock Xylophone and Config and Logger and set up calls
+ $XY = new stdClass();
+ $config = $this->getMock('Xylophone\core\Config', array('get'), array(), '', false);
+ $config->expects($this->once())->method('get')->with($this->equalTo($file), $this->equalTo('config'))->
+ will($this->returnValue($cfg));
+ $XY->logger = $this->getMock('Xylophone\core\Logger', array('debug'), array(), '', false);
+ $XY->logger->expects($this->once())->method('debug')->
+ with($this->equalTo('Config file loaded: '.$name.'.php'));
+
+ // Call load() and verify results
+ $this->assertTrue($config->load($file));
+ $this->assertEquals($cfg, $config->config);
+ $this->assertEquals(array($name), $config->is_loaded);
+ }
+
+ /**
+ * Test load() with sections
+ */
+ public function testLoadSections()
+ {
+ global $XY;
+
+ // Set up args
+ $name = 'sectcfg';
+ $file = $name.'.php';
+ $cfg = array('red' => 'apple', 'blue' => 'berry');
+
+ // Mock Xylophone and Config and Logger and set up calls
+ $XY = new stdClass();
+ $config = $this->getMock('Xylophone\core\Config', array('get'), array(), '', false);
+ $config->expects($this->once())->method('get')->with($this->equalTo($file), $this->equalTo('config'))->
+ will($this->returnValue($cfg));
+ $XY->logger = $this->getMock('Xylophone\core\Logger', array('debug'), array(), '', false);
+ $XY->logger->expects($this->once())->method('debug')->
+ with($this->equalTo('Config file loaded: '.$name.'.php'));
+
+ // Call load() and verify results
+ $this->assertTrue($config->load($file, true));
+ $this->assertArrayHasKey($name, $config->config);
+ $this->assertEquals($cfg, $config->config[$name]);
+ $this->assertEquals(array($name), $config->is_loaded);
+ }
+
+ /**
+ * Test load() with non-existent file
+ */
+ public function testLoadNone()
+ {
+ global $XY;
+
+ // Set up args
+ $name = 'figment';
+
+ // Mock Xylophone and Config and set up calls
+ $XY = $this->getMock('Xylophone\core\Xylophone', array(), array(), '', false);
+ $config = $this->getMock('Xylophone\core\Config', array('get'), array(), '', false);
+ $config->expects($this->once())->method('get')->
+ with($this->equalTo($name.'.php'), $this->equalTo('config'))->
+ will($this->returnValue(false));
+ $XY->expects($this->once())->method('showError')->
+ with($this->equalTo('The configuration file '.$name.'.php does not exist.'))->
+ will($this->throwException(new InvalidArgumentException));
+
+ // Call load()
+ $this->setExpectedException('InvalidArgumentException');
+ $config->load($name);
+ }
+
+ /**
+ * Test load() with graceful non-existent file
+ */
+ public function testLoadNoneGraceful()
+ {
+ // Set up args
+ $name1 = 'exists';
+ $name2 = 'graceful';
+
+ // Mock Config and set up calls
+ $config = $this->getMock('Xylophone\core\Config', array('get'), array(), '', false);
+ $config->expects($this->once())->method('get')->
+ with($this->equalTo($name2.'.php'), $this->equalTo('config'))->
+ will($this->returnValue(false));
+
+ // Set first file as loaded
+ $config->is_loaded[] = $name1;
+
+ // Call load() and verify results
+ $this->assertFalse($config->load(array($name1, $name2), false, true));
+ $this->assertEquals(array($name1), $config->is_loaded);
+ }
+
+ /**
+ * Test load() with bad file
+ */
+ public function testLoadBad()
+ {
+ global $XY;
+
+ // Set up args
+ $name = 'badcfg';
+
+ // Mock Xylophone and Config and set up calls
+ $XY = $this->getMock('Xylophone\core\Xylophone', array(), array(), '', false);
+ $config = $this->getMock('Xylophone\core\Config', array('get'), array(), '', false);
+ $config->expects($this->once())->method('get')->
+ with($this->equalTo($name.'.php'), $this->equalTo('config'))->
+ will($this->returnValue('/some/bad/path'));
+ $XY->expects($this->once())->method('showError')->
+ with($this->equalTo('Your '.$name.'.php file does not appear to contain a valid configuration array.'))->
+ will($this->throwException(new InvalidArgumentException));
+
+ // Call load()
+ $this->setExpectedException('InvalidArgumentException');
+ $config->load($name);
+ }
+
+ /**
+ * Test load() with graceful bad file
+ */
+ public function testLoadBadGraceful()
+ {
+ // Set up args
+ $name = 'badgrace';
+
+ // Mock Config and set up calls
+ $config = $this->getMock('Xylophone\core\Config', array('get'), array(), '', false);
+ $config->expects($this->once())->method('get')->with($this->equalTo($name.'.php'), $this->equalTo('config'))->
+ will($this->returnValue('/bad/file/path'));
+
+ // Call load() and verify results
+ $this->assertFalse($config->load($name, false, true));
+ }
+
+ /**
+ * Test get()
+ */
+ public function testGet()
+ {
+ // Set up args
+ $file = 'somecfg.php';
+ $name = 'config';
+ $retval = array('key' => 'val');
+
+ // Mock Config and set up call
+ $config = $this->getMock('Xylophone\core\Config', array('getExtra'), array(), '', false);
+ $config->expects($this->once())->method('getExtra')->
+ with($this->equalTo($file), $this->equalTo($name), $this->isFalse())->
+ will($this->returnValue($retval));
+
+ // Call get()
+ $config->get($file, $name);
+ }
+
+ /**
+ * Test getExtra() with no file
+ */
+ public function testGetExtraNone()
+ {
+ global $XY;
+
+ // Set up VFS
+ $this->vfsInit();
+
+ // Mock Xylophone and Config
+ $XY = new stdClass();
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+
+ // Set empty environment and config paths
+ $XY->environment = '';
+ $XY->config_paths = array($this->vfs_app_path.'/');
+
+ // Call getExtra() with non-existent file and confirm failure
+ $extras = false;
+ $this->assertFalse($config->getExtra('dummy', 'config', $extras));
+ }
+
+ /**
+ * Test getExtra() with no array
+ */
+ public function testGetExtraEmpty()
+ {
+ global $XY;
+
+ // Set up args
+ $file = 'empty.php';
+ $extras = false;
+
+ // Set up VFS and make file
+ $this->vfsInit();
+ $this->vfsCreate('config/'.$file, '<?php $foo = \'bar\';', $this->vfs_app_dir);
+
+ // Mock Xylophone and Config
+ $XY = new stdClass();
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+
+ // Set empty environment and config path
+ $XY->environment = '';
+ $XY->config_paths = array($this->vfs_app_path.'/');
+
+ // Call getExtra() and confirm result
+ $this->assertEquals($this->vfs_app_path.'/config/'.$file, $config->getExtra($file, 'config', $extras));
+ }
+
+ /**
+ * Test getExtra() with no name
+ */
+ public function testGetExtraNoName()
+ {
+ global $XY;
+
+ // Set up args
+ $file = 'global';
+ $key = 'warming';
+ $val = 'trend';
+ $extras = false;
+
+ // Set up VFS and make file
+ $this->vfsInit();
+ $this->vfsCreate('config/'.$file.'.php', '<?php $GLOBALS[\''.$key.'\'] = \''.$val.'\';', $this->vfs_app_dir);
+
+ // Mock Xylophone and Config
+ $XY = new stdClass();
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+
+ // Set empty environment and config path
+ $XY->environment = '';
+ $XY->config_paths = array($this->vfs_app_path.'/');
+
+ // Call getExtra() and confirm result
+ $this->assertTrue($config->getExtra($file, '', $extras));
+ $this->assertArrayHasKey($key, $GLOBALS);
+ $this->assertEquals($val, $GLOBALS[$key]);
+ }
+
+ /**
+ * Test getExtra()
+ */
+ public function testGetExtra()
+ {
+ global $XY;
+
+ // Set up args
+ $file = 'vars.php';
+ $cfg1 = array('one' => '1', 'two' => '3');
+ $cfg2 = array('two' => '2');
+ $result = array('one' => '1', 'two' => '2');
+ $key1 = 'pickme';
+ $key2 = 'andme';
+ $nokey = '_notme';
+ $val1 = 'first';
+ $val2 = 'second';
+ $noval = 'ignore';
+ $extras = array();
+
+ // Make file contents
+ $content1 = '<?php $config = '.var_export($cfg1, true).'; $'.$key1.' = \''.$val1.'\';';
+ $content2 = '<?php $config = '.var_export($cfg2, true).'; $'.$key2.' = \''.$val2.'\'; '.
+ '$'.$nokey.' = \''.$noval.'\';';
+
+ // Set up VFS and make files
+ $this->vfsInit();
+ $tp_dir = $this->vfsMkdir('third-party', $this->vfs_base_dir);
+ $this->vfsCreate('config/'.$file, $content1, $tp_dir);
+ $this->vfsCreate('config/'.$file, $content2, $this->vfs_app_dir);
+
+ // Mock Xylophone and Config
+ $XY = new stdClass();
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+
+ // Set empty environment and config paths
+ $XY->environment = '';
+ $XY->config_paths = array($tp_dir->url().'/', $this->vfs_app_path.'/');
+
+ // Call getExtra() and confirm result
+ $this->assertEquals($result, $config->getExtra($file, 'config', $extras));
+ $this->assertEquals(array($key1 => $val1, $key2 => $val2), $extras);
+ }
+
+ /**
+ * Test item() fail
+ */
+ public function testItemFail()
+ {
+ // Mock Config
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+
+ // Call item() and confirm missing item fail
+ $this->assertNull($config->item('missing'));
+ }
+
+ /**
+ * Test item()
+ */
+ public function testItem()
+ {
+ // Set args
+ $key = 'findme';
+ $val = 'yay';
+
+ // Mock Config and set item
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+ $config->config[$key] = $val;
+
+ // Call item() and confirm result
+ $this->assertEquals($val, $config->item($key));
+ }
+
+ /**
+ * Test item() fail with index
+ */
+ public function testItemIndexFail()
+ {
+ // Set arg
+ $key = 'empty';
+
+ // Mock Config and set item
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+ $config->config[$key] = array();
+
+ // Call item() and confirm missing item index fail
+ $this->assertNull($config->item($key, 'nothere'));
+ }
+
+ /**
+ * Test item() with index
+ */
+ public function testItemIndex()
+ {
+ // Set args
+ $key1 = 'group';
+ $key2 = 'member';
+ $val = 'ship';
+
+ // Mock Config and set item
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+ $config->config[$key1] = array($key2 => $val);
+
+ // Call item() and confirm item index
+ $this->assertEquals($val, $config->item($key2, $key1));
+ }
+
+ /**
+ * Test setItem()
+ */
+ public function testSetItem()
+ {
+ // Set up args
+ $key1 = 'single';
+ $val1 = 'value';
+ $key2 = 'multi';
+ $val2 = array($key2 => array('gets' => 'newval', 'newkey' => 'added'));
+ $pre2 = array('stays' => 'same', 'gets' => 'replaced');
+ $result = array('stays' => 'same', 'gets' => 'newval', 'newkey' => 'added');
+
+ // Mock Config and set previous value
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+ $config[$key2] = $pre2;
+
+ // Call setItem() and confirm results
+ $config->setItem($key1, $val1);
+ $this->assertArrayHasKey($key1, $config->config);
+ $this->assertEquals($val1, $config->config[$key1]);
+ $config->setItem($val2);
+ $this->assertEquals($result, $config->config[$key2]);
+ }
+
+ /**
+ * Test slashItem() fail
+ */
+ public function testSlashItemFail()
+ {
+ // Mock Config
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+
+ // Call slashItem() and confirm missing item fail
+ $this->assertNull($config->slashItem('missing'));
+ }
+
+ /**
+ * Test slashItem() with empty value
+ */
+ public function testSlashItemEmpty()
+ {
+ // Set arg
+ $key = 'blank';
+
+ // Mock Config and set item
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+ $config->config[$key] = ' ';
+
+ // Call slashItem() and confirm result
+ $this->assertEmpty($config->slashItem($key));
+ }
+
+ /**
+ * Test slashItem()
+ */
+ public function testSlashItem()
+ {
+ // Set args
+ $key = 'path';
+ $val = '/fake/dir';
+
+ // Mock Config and set item
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+ $config->config[$key] = $val;
+
+ // Call slashItem() and confirm results
+ $this->assertEquals($val.'/', $config->slashItem($key));
+ $config->config[$key] = $val.'/';
+ $this->assertEquals($val.'/', $config->slashItem($key));
+ }
+
+ /**
+ * Test siteUrl()
+ */
+ public function testSiteUrl()
+ {
+ // Set up args
+ $base = 'http://testserver.net/testapp/';
+ $index = 'main';
+
+ // Mock Config and set up calls
+ $config = $this->getMock('Xylophone\core\Config', array('slashitem', 'item'), array(), '', false);
+ $config->expects($this->once())->method('slashItem')->with($this->equalTo('base_url'))->
+ will($this->returnValue($base));
+ $config->expects($this->once())->method('item')->with($this->equalTo('index_page'))->
+ will($this->returnValue($index));
+
+ // Call siteUrl() and verify result
+ $this->assertEquals($base.$index, $config->siteUrl());
+ }
+
+ /**
+ * Test siteUrl() with a URI string and a URL suffix
+ */
+ public function testSiteUrlUriSuffix()
+ {
+ // Set up args
+ $base = 'http://myserver.com/someapp/';
+ $index = 'home';
+ $uri = 'some/args';
+ $suffix = 'ctlr';
+
+ // Mock Config and set up calls
+ $config = $this->getMock('Xylophone\core\Config', array('slashitem', 'item', 'uriString'),
+ array(), '', false);
+ $config->expects($this->at(0))->method('slashItem')->with($this->equalTo('base_url'))->
+ will($this->returnValue($base));
+ $config->expects($this->at(1))->method('uriString')->with($this->equalTo($uri))->
+ will($this->returnArgument(0));
+ $config->expects($this->at(2))->method('item')->with($this->equalTo('enable_query_strings'))->
+ will($this->returnValue(false));
+ $config->expects($this->at(3))->method('slashItem')->with($this->equalTo('index_page'))->
+ will($this->returnValue($index));
+ $config->config['url_suffix'] = $suffix;
+
+ // Call siteUrl() and verify result
+ $this->assertEquals($base.$index.$uri.$suffix, $config->siteUrl($uri));
+ }
+
+ /**
+ * Test siteUrl() with a split URI string and a URL suffix
+ */
+ public function testSiteUrlSuffixUri()
+ {
+ // Set up args
+ $base = 'http://test.org/myapp/';
+ $index = 'index/';
+ $dir = 'sub';
+ $query = '?arg';
+ $uri = $dir.$query;
+ $suffix = '.php';
+
+ // Mock Config and set up calls
+ $config = $this->getMock('Xylophone\core\Config', array('slashitem', 'item', 'uriString'),
+ array(), '', false);
+ $config->expects($this->at(0))->method('slashItem')->with($this->equalTo('base_url'))->
+ will($this->returnValue($base));
+ $config->expects($this->at(1))->method('uriString')->with($this->equalTo($uri))->
+ will($this->returnArgument(0));
+ $config->expects($this->at(2))->method('item')->with($this->equalTo('enable_query_strings'))->
+ will($this->returnValue(false));
+ $config->expects($this->at(3))->method('slashItem')->with($this->equalTo('index_page'))->
+ will($this->returnValue($index));
+ $config->config['url_suffix'] = $suffix;
+
+ // Call siteUrl() and verify result
+ $this->assertEquals($base.$index.$dir.$suffix.$query, $config->siteUrl($uri));
+ }
+
+ /**
+ * Test siteUrl() with a URI string, a protocol, and query strings
+ */
+ public function testSiteUrlProtoQuery()
+ {
+ // Set up args
+ $proto1 = 'http';
+ $proto2 = 'https';
+ $base = '://testing.us/somemore/';
+ $index = 'with';
+ $uri = '?this&that';
+
+ // Mock Config and set up calls
+ $config = $this->getMock('Xylophone\core\Config', array('slashitem', 'item', 'uriString'),
+ array(), '', false);
+ $config->expects($this->at(0))->method('slashItem')->with($this->equalTo('base_url'))->
+ will($this->returnValue($proto1.$base));
+ $config->expects($this->at(1))->method('uriString')->with($this->equalTo($uri))->
+ will($this->returnArgument(0));
+ $config->expects($this->at(2))->method('item')->with($this->equalTo('enable_query_strings'))->
+ will($this->returnValue(true));
+ $config->expects($this->at(3))->method('item')->with($this->equalTo('index_page'))->
+ will($this->returnValue($index));
+
+ // Call siteUrl() and verify result
+ $this->assertEquals($proto2.$base.$index.$uri, $config->siteUrl($uri, $proto2));
+ }
+
+ /**
+ * Test baseUrl()
+ */
+ public function testBaseUrl()
+ {
+ // Set up args
+ $proto1 = 'https';
+ $proto2 = 'http';
+ $base = '://localhost/localtest/';
+ $uri = 'foo/bar';
+
+ // Mock Config and set up calls
+ $config = $this->getMock('Xylophone\core\Config', array('slashItem', 'item'), array(), '', false);
+ $config->expects($this->once())->method('slashItem')->with($this->equalTo('base_url'))->
+ will($this->returnValue($proto1.$base));
+ $config->expects($this->once())->method('item')->with($this->equalTo('enable_query_strings'))->
+ will($this->returnValue(false));
+
+ // Call baseUrl() and verify reult
+ $this->assertEquals($proto2.$base.$uri, $config->baseUrl('/'.$uri.'/', $proto2));
+ }
+
+ /**
+ * Test baseUrl() with query strings
+ */
+ public function testBaseUrlQuery()
+ {
+ // Set up args
+ $base = 'http://localhost/querytest/';
+ $key1 = 'first';
+ $val1 = 'arg';
+ $key2 = 'second';
+ $val2 = 'param';
+ $uri = array($key1 => $val1, $key2 => $val2);
+
+ // Mock Config and set up calls
+ $config = $this->getMock('Xylophone\core\Config', array('slashItem', 'item'), array(), '', false);
+ $config->expects($this->once())->method('slashItem')->with($this->equalTo('base_url'))->
+ will($this->returnValue($base));
+ $config->expects($this->once())->method('item')->with($this->equalTo('enable_query_strings'))->
+ will($this->returnValue(true));
+
+ // Call baseUrl() and verify reult
+ $this->assertEquals($base.'?'.$key1.'='.$val1.'&'.$key2.'='.$val2, $config->baseUrl($uri));
+ }
+
+ /**
+ * Test offsetExists()
+ */
+ public function testOffsetExists()
+ {
+ // Set args
+ $key = 'good';
+
+ // Mock Config and set item
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+ $config->config[$key] = true;
+
+ // Test via array access
+ $this->assertTrue(isset($config[$key]));
+ $this->assertFalse(isset($config['bad']));
+ }
+
+ /**
+ * Test offsetGet()
+ */
+ public function testOffsetGet()
+ {
+ // Set args
+ $key = 'real';
+ $val = 'value';
+
+ // Mock Config and set item
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+ $config->config[$key] = $val;
+
+ // Test via array access
+ $this->assertEquals($val, $config[$key]);
+ $this->assertNull($config['figment']);
+ }
+
+ /**
+ * Test offsetSet()
+ */
+ public function testOffsetSet()
+ {
+ // Set args
+ $number = 0;
+ $key = 'foo';
+ $val = 'bar';
+
+ // Mock Config
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+
+ // Test via array access
+ $config[$number] = 'nothing';
+ $this->assertArrayNotHasKey($number, $config->config);
+ $config[$key] = $val;
+ $this->assertArrayHasKey($key, $config->config);
+ $this->assertEquals($val, $config->config[$key]);
+ }
+
+ /**
+ * Test offsetUnset()
+ */
+ public function testOffsetUnset()
+ {
+ // Set arg
+ $key = 'nowyouseeme';
+
+ // Mock Config and set item
+ $config = $this->getMock('Xylophone\core\Config', null, array(), '', false);
+ $config->config[$key] = 'nowyoudont';
+
+ // Test via array access
+ unset($config[$key]);
+ $this->assertArrayNotHasKey($key, $config->config);
+ }
+}
+
View
915 tests/Xylophone/core/XylophoneTest.php
@@ -87,10 +87,13 @@ public function setUp()
// manually include source file and mock source
include_once BASEPATH.'system/core/Xylophone.php';
include_once TESTPATH.'Mocks/core/Xylophone.php';
+ }
- // Default to skipping handlers
- Mocks\core\Xylophone::$skip_handlers = true;
-
+ /**
+ * Load our virtual filesystem
+ */
+ private function loadFilesystem()
+ {
// Initialize our VFS
$this->vfsInit();
@@ -126,7 +129,7 @@ public function testInstanceAppFail()
$this->setExpectedException('Xylophone\core\ExitException',
'Your application folder path does not appear to be set correctly.'.
' Please fix it in the following file: '.basename($_SERVER['PHP_SELF']), EXIT_XY);
- $XY = Mocks\core\Xylophone::instance($init);
+ Xylophone\core\Xylophone::instance($init);
}
/**
@@ -134,13 +137,16 @@ public function testInstanceAppFail()
*/
public function testInstanceNsFail()
{
+ // Load VFS
+ $this->vfsInit();
+
// Call instance with a bad (missing) namespace
$init = array('environment' => 'production', 'ns_paths' => array('' => $this->vfs_app_path, 'badpath/'));
$this->setExpectedException('Xylophone\core\ExitException',
'The global namespace is reserved for application classes. '.
'Please specify a namespace for your additional path in the following file: '.
basename($_SERVER['PHP_SELF']), EXIT_XY);
- $XY = Mocks\core\Xylophone::instance($init);
+ Xylophone\core\Xylophone::instance($init);
}
/**
@@ -148,13 +154,16 @@ public function testInstanceNsFail()
*/
public function testInstanceNsPathFail()
{
+ // Load VFS
+ $this->vfsInit();
+
// Call instance with a bad ns path
$ns = 'BadSpace';
$init = array('environment' => 'production', 'ns_paths' => array('' => $this->vfs_app_path, $ns => 'badpath/'));
$this->setExpectedException('Xylophone\core\ExitException',
'The "'.$ns.'" namespace path does not appear to be set correctly.'.
' Please fix it in the following file: '.basename($_SERVER['PHP_SELF']), EXIT_XY);
- $XY = Mocks\core\Xylophone::instance($init);
+ Xylophone\core\Xylophone::instance($init);
}
/**
@@ -167,17 +176,15 @@ public function testInstance()
// Call instance to get a new instance, skipping tune()
// We pass the Mocks namespace so our mock overload gets used
// This will be the instance for the rest of the tests below
- Mocks\core\Xylophone::$skip_init = true;
+ Mocks\core\Xylophone::$skip_tune = true;
$init = array('ns_paths' => array('Mocks' => TESTPATH.'Mocks/'));
- $XY = Mocks\core\Xylophone::instance($init);
+ $XY = Xylophone\core\Xylophone::instance($init);
$this->assertInstanceOf('Xylophone\core\Xylophone', $XY);
// Call again and check for same object
- $XY2 = Mocks\core\Xylophone::instance();
- $this->assertEquals($XY, $XY2);
-
- // Say we're not on 5.4 - some things are easier that way
- $XY->is_php['5.4'] = false;
+ $xy = Xylophone\core\Xylophone::instance();
+ $this->assertSame($XY, $xy);
+ Mocks\core\Xylophone::$skip_tune = false;
// Return our instance for use later
return $XY;
@@ -185,14 +192,17 @@ public function testInstance()
/**
* Test tune() defaults
- *
- * @depends testInstance
- * @return object Mock Xylophone instance
*/
- public function testTuneDefault($XY)
+ public function testTuneDefault()
{
+ // Mock Xylophone and set up calls
+ $XY = $this->getMock('Xylophone\core\Xylophone', array('isPhp', 'addViewPath', 'registerHandlers'),
+ array(), '', false);
+ $XY->expects($this->once())->method('isPhp')->with($this->equalTo('5.4'))->will($this->returnValue(true));
+ $XY->expects($this->once())->method('addViewPath')->with($this->equalTo(array('')));
+ $XY->expects($this->once())->method('registerHandlers');
+
// Call tune with empty parameters
- Mocks\core\Xylophone::$skip_init = false;
$XY->tune(array());
// Check environment and base and system paths
@@ -206,26 +216,24 @@ public function testTuneDefault($XY)
$this->assertEquals('', $XY->app_ns);
$this->assertEquals($app_path, $XY->app_path);
- // Check config and view paths
+ // Check config paths
$this->assertEquals(array($app_path), $XY->config_paths);
- $this->assertEquals(array('' => $app_path.'views/'), $XY->view_paths);
// Check override flags
$this->assertFalse($XY->override_core);
$this->assertFalse($XY->library_search);
-
- // Return instance for reinitialization
- return $XY;
}
/**
* Test tune()
*
- * @depends testTuneDefault
* @return object Mock Xylophone instance
*/
- public function testTune($XY)
+ public function testTune()
{
+ // Load the filesystem
+ $this->loadFilesystem();
+
// Set up test parameter vars
$env = 'development';
$basedir = $this->vfs_base_path.'/';
@@ -236,6 +244,13 @@ public function testTune($XY)
$nspath = array($appns => $appdir, $this->share_ns => $shdir, 'Mocks' => TESTPATH.'Mocks/');
$appvwnm = 'views/';
+ // Mock Xylophone and set up calls
+ $XY = $this->getMock('Xylophone\core\Xylophone', array('isPhp', 'addViewPath', 'registerHandlers'),
+ array(), '', false);
+ $XY->expects($this->once())->method('isPhp')->with($this->equalTo('5.4'))->will($this->returnValue(true));
+ $XY->expects($this->once())->method('addViewPath')->with($this->equalTo(array($appvwnm)));
+ $XY->expects($this->once())->method('registerHandlers');
+
// Call tune with parameters
$init = array(
'environment' => $env,
@@ -259,9 +274,8 @@ public function testTune($XY)
$this->assertEquals($appns, $XY->app_ns);
$this->assertEquals($appdir, $XY->app_path);
- // Check config and view paths
+ // Check config paths
$this->assertEquals($XY->config_paths, array($shdir, $appdir));
- $this->assertEquals(array($appvwnm => $appdir.$appvwnm), $XY->view_paths);
// Check override flags
$this->assertFalse($XY->override_core);
@@ -273,24 +287,51 @@ public function testTune($XY)
/**
* Test autoloader() fail
- *
- * @depends testTune
*/
- public function testAutoloaderFail($XY)
+ public function testAutoloaderFail()
{
+ // Load vfs
+ $this->vfsinit();
+
+ // Mock xylophone and set system path
+ $XY = $this->getmock('xylophone\core\xylophone', null, array(), '', false);
+ $XY->system_path = $this->vfs_sys_path.'/';
+
// Try to load a non-existent class
- $class = 'Xylophone\core\BadClass';
- $this->setExpectedException('\Xylophone\core\AutoloadException', 'Could not find class "'.$class.'"');
+ $class = 'Xylophone\core\badclass';
+ $this->setExpectedException('\Xylophone\Core\AutoloadException', 'Could not find class "'.$class.'"');
+ $XY->autoloader($class);
+ }
+
+ /**
+ * Test autoloader() with its own exception
+ */
+ public function testAutoloaderException()
+ {
+ // Load vfs
+ $this->vfsinit();
+
+ // Mock xylophone and set system path
+ $XY = $this->getmock('xylophone\core\xylophone', null, array(), '', false);
+ $XY->system_path = $this->vfs_sys_path.'/';
+
+ // Try to load exception without file
+ $class = 'Xylophone\core\AutoloadException';
$XY->autoloader($class);
}
/**
* Test autoloader()
- *
- * @depends testTune
*/
- public function testAutoloader($XY)
+ public function testAutoloader()
{
+ // Load the filesystem
+ $this->loadFilesystem();
+
+ // Mock Xylophone and set ns paths
+ $XY = $this->getMock('Xylophone\core\Xylophone', null, array(), '', false);
+ $XY->ns_paths = array('' => $this->vfs_app_path.'/', $this->share_ns => $this->share_path.'/');
+
// Create dummy class file
$dir = 'libraries';
$file = 'TestLib';
@@ -304,11 +345,16 @@ public function testAutoloader($XY)
/**
* Test autoloader() with a hint
- *
- * @depends testTune
*/
- public function testAutoloaderHint($XY)
+ public function testAutoloaderHint()
{
+ // Load VFS
+ $this->vfsInit();
+
+ // Mock Xylophone and set ns paths
+ $XY = $this->getMock('Mocks\core\Xylophone', null, array(), '', false);
+ $XY->ns_paths = array('' => $this->vfs_app_path.'/');
+
// Create dummy class file
$dir = 'core';
$file = 'Hint';
@@ -319,18 +365,16 @@ public function testAutoloaderHint($XY)
$this->expectOutputString($output);
$XY->loader_hint = $dir;
$XY->autoloader($file);
-
- // Clean up
- $XY->loader_hint = '';
}
/**
* Test loadClass() fail
- *
- * @depends testTune
*/
- public function testLoadClassFail($XY)
+ public function testLoadClassFail()
{
+ // Mock Xylophone
+ $XY = $this->getMock('Xylophone\core\Xylophone', null, array(), '', false);
+
// Make a class that emulates the autoloader not-found behavior
$hint = 'core';
$class = 'MissingClass';
@@ -342,11 +386,16 @@ public function testLoadClassFail($XY)
/**
* Test loadClass() with a global class
- *
- * @depends testTune
*/
- public function testLoadClassGlobal($XY)
+ public function testLoadClassGlobal()
{
+ // Mock Xylophone
+ $XY = $this->getMock('Mocks\core\Xylophone', null, array(), '', false);
+
+ // Enable library search and set ns_paths
+ $XY->library_search = true;
+ $XY->ns_paths = array('' => '/dont/need/path/');
+
// Make a global class that takes one param
$class = 'GlobalClass';
$member = 'passed';
@@ -366,11 +415,16 @@ public function testLoadClassGlobal($XY)
/**
* Test loadClass() with a namespace
- *
- * @depends testTune
*/
- public function testLoadClassNs($XY)
+ public function testLoadClassNs()
{
+ // Load the filesystem
+ $this->loadFilesystem();
+
+ // Mock Xylophone and set ns paths
+ $XY = $this->getMock('Xylophone\core\Xylophone', null, array(), '', false);
+ $XY->ns_paths = array('' => $this->vfs_app_path.'/', $this->share_ns => $this->share_path.'/');
+
// Make a class that takes two ctor params
$hint = 'models';
$class = 'SharedClass';
@@ -393,11 +447,12 @@ public function testLoadClassNs($XY)
/**
* Test callController() with a bad class
- *
- * @depends testTune
*/
- public function testCallControllerFail($XY)
+ public function testCallControllerFail()
{
+ // Mock Xylophone
+ $XY = $this->getMock('Xylophone\core\Xylophone', null, array(), '', false);
+
// Pass a non-existent class and an invalid route stack and confirm failure
$this->assertFalse($XY->callController('BadClass'));
$this->assertFalse($XY->callController(array('method' => 'index')));
@@ -405,11 +460,13 @@ public function testCallControllerFail($XY)
/**
* Test callController() with a bad method
- *
- * @depends testTune
*/
- public function testCallControllerBadMethod($XY)
+ public function testCallControllerBadMethod()
{
+ // Mock Xylophone and set up call
+ $XY = $this->getMock('Xylophone\core\Xylophone', array('isCallable'), array(), '', false);
+ $XY->expects($this->any())->method('isCallable')->will($this->returnValue(false));
+
// Create dummy class with no index method
$class = 'EmptyClass';
$this->makeClass($class, 'none');
@@ -420,20 +477,22 @@ public function testCallControllerBadMethod($XY)
// Call class (with default 'index') and confirm failure
$this->assertFalse($XY->callController(array('class' => $class)));
-
- // Clean up
- unset($XY->$name);
}
/**
* Test callController() with a remap method
- *
- * @depends testTune
*/
- public function testCallControllerRemap($XY)
+ public function testCallControllerRemap()
{
- // Create controller with remap method
+ // Set up args
$class = 'RemapCtlr';
+
+ // Mock Xylophone and set up call
+ $XY = $this->getMock('Xylophone\core\Xylophone', array('isCallable'), array(), '', false);
+ $XY->expects($this->once())->method('isCallable')->with($this->equalTo($class), $this->equalTo('xyRemap'))->
+ will($this->returnValue(true));
+
+ // Create controller with remap method
$member1 = 'passed1';
$member2 = 'passed2';
$this->makeClass($class, 'xyRemap', array($member1, $member2));
@@ -453,33 +512,34 @@ public function testCallControllerRemap($XY)
$this->assertEquals($method, $XY->$name->$member1);
$this->assertObjectHasAttribute($member2, $XY->$name);
$this->assertEquals($args, $XY->$name->$member2);
-
- // Clean up
- unset($XY->$name);
}
/**
* Test callController() with output capture
- *
- * @depends testTune
*/
- public function testCallControllerOutput($XY)
+ public function testCallControllerOutput()
{
- // Create controller with remap method
+ // Set up args
$class = 'TestOutCtlr';
$method = 'makeOut';
- $member = 'passed';
- $this->makeClass($class, $method, array($member));
+ $output = 'My Controller Made This';
- // Attach instance
+ // Mock Xylophone and Output and set up calls
+ $XY = $this->getMock('Xylophone\core\Xylophone', array('isCallable'), array(), '', false);
+ $XY->expects($this->at(0))->method('isCallable')->with($this->equalTo($class), $this->equalTo('xyRemap'))->
+ will($this->returnValue(false));
+ $XY->expects($this->at(1))->method('isCallable')->with($this->equalTo($class), $this->equalTo($method))->
+ will($this->returnValue(true));
+ $XY->output = $this->getMock('Xylophone\core\Output', array('stackPush', 'stackPop'), array(), '', false);
+ $XY->output->expects($this->once())->method('stackPush');
+ $XY->output->expects($this->once())->method('stackPop')->will($this->returnValue($output));
+
+ // Create controller and attach
$name = strtolower($class);
+ $member = 'passed';
+ $this->makeClass($class, $method, array($member));
$XY->$name = new $class();
- // Create mock Output class with stack calls
- $output = 'My Controller Made This';
- $XY->output = $this->getMock('Xylophone\core\Output', array(), array(), '', false);
- $XY->output->expects($this->any())->method('stackPop')->will($this->returnValue($output));
-
// Call class and confirm output
$param = 'session';
$this->assertEquals($output, $XY->callController($class, $method, array($param), '', true));
@@ -487,75 +547,54 @@ public function testCallControllerOutput($XY)
// Verify passed argument
$this->assertObjectHasAttribute($member, $XY->$name);
$this->assertEquals($param, $XY->$name->$member);
-
- // Clean up
- unset($XY->$name);
- unset($XY->output);
}
/**
* Test play()
- *
- * @depends testTune
*/
- public function testPlay($XY)
+ public function testPlay()
{
- // Set up play test arguments
- $XY->play_args['intro_atl'] = array('foo' => 'bar', 'bar' => 'baz');
- $XY->play_args['coda_ret'] = false;
+ // Set up args
+ $autoload = array('foo' => 'bar', 'bar' => 'baz');
$benchmark = 'time';
$config = array('name' => 'value');
$routing = array('dir' => 'empty', 'ctlr' => 'none', 'meth' => 'blank');
- // Call play and check args
- $XY->play($benchmark, $config, $routing);
- $this->assertArrayHasKey('intro_bmk', $XY->play_args);
- $this->assertEquals($benchmark, $XY->play_args['intro_bmk']);
- $this->assertArrayHasKey('intro_cfg', $XY->play_args);
- $this->assertEquals($config, $XY->play_args['intro_cfg']);
- $this->assertArrayHasKey('bridge_rtg', $XY->play_args);
-