dokuwiki/_test/core/DokuWikiTest.php

275 lines
8.8 KiB
PHP

<?php
if(!class_exists('PHPUnit_Framework_TestCase')) {
/**
* phpunit 5/6 compatibility
*/
class PHPUnit_Framework_TestCase extends PHPUnit\Framework\TestCase {
/**
* setExpectedException is deprecated in PHPUnit 6
*
* @param string $class
* @param null|string $message
*/
public function setExpectedException($class, $message=null) {
$this->expectException($class);
if(!is_null($message)) {
$this->expectExceptionMessage($message);
}
}
}
}
/**
* Helper class to provide basic functionality for tests
*
* @uses PHPUnit_Framework_TestCase and thus PHPUnit 5.7+ is required
*/
abstract class DokuWikiTest extends PHPUnit_Framework_TestCase {
/**
* tests can override this
*
* @var array plugins to enable for test class
*/
protected $pluginsEnabled = array();
/**
* tests can override this
*
* @var array plugins to disable for test class
*/
protected $pluginsDisabled = array();
/**
* Setup the data directory
*
* This is ran before each test class
*/
public static function setUpBeforeClass() {
// just to be safe not to delete something undefined later
if(!defined('TMP_DIR')) die('no temporary directory');
if(!defined('DOKU_TMP_DATA')) die('no temporary data directory');
self::setupDataDir();
self::setupConfDir();
}
/**
* Reset the DokuWiki environment before each test run. Makes sure loaded config,
* language and plugins are correct.
*
* @throws Exception if plugin actions fail
* @return void
*/
public function setUp() {
// reload config
global $conf, $config_cascade;
$conf = array();
foreach (array('default','local','protected') as $config_group) {
if (empty($config_cascade['main'][$config_group])) continue;
foreach ($config_cascade['main'][$config_group] as $config_file) {
if (file_exists($config_file)) {
include($config_file);
}
}
}
// reload license config
global $license;
$license = array();
// load the license file(s)
foreach (array('default','local') as $config_group) {
if (empty($config_cascade['license'][$config_group])) continue;
foreach ($config_cascade['license'][$config_group] as $config_file) {
if(file_exists($config_file)){
include($config_file);
}
}
}
// reload some settings
$conf['gzip_output'] &= (strpos($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip') !== false);
if($conf['compression'] == 'bz2' && !DOKU_HAS_BZIP) {
$conf['compression'] = 'gz';
}
if($conf['compression'] == 'gz' && !DOKU_HAS_GZIP) {
$conf['compression'] = 0;
}
// make real paths and check them
init_paths();
init_files();
// reset loaded plugins
global $plugin_controller_class, $plugin_controller;
/** @var Doku_Plugin_Controller $plugin_controller */
$plugin_controller = new $plugin_controller_class();
// disable all non-default plugins
global $default_plugins;
foreach ($plugin_controller->getList() as $plugin) {
if (!in_array($plugin, $default_plugins)) {
if (!$plugin_controller->disable($plugin)) {
throw new Exception('Could not disable plugin "'.$plugin.'"!');
}
}
}
// disable and enable configured plugins
foreach ($this->pluginsDisabled as $plugin) {
if (!$plugin_controller->disable($plugin)) {
throw new Exception('Could not disable plugin "'.$plugin.'"!');
}
}
foreach ($this->pluginsEnabled as $plugin) {
/* enable() returns false but works...
if (!$plugin_controller->enable($plugin)) {
throw new Exception('Could not enable plugin "'.$plugin.'"!');
}
*/
$plugin_controller->enable($plugin);
}
// reset event handler
global $EVENT_HANDLER;
$EVENT_HANDLER = new Doku_Event_Handler();
// reload language
$local = $conf['lang'];
trigger_event('INIT_LANG_LOAD', $local, 'init_lang', true);
global $INPUT;
$INPUT = new \dokuwiki\Input\Input();
}
/**
* Reinitialize the data directory for this class run
*/
public static function setupDataDir() {
// remove any leftovers from the last run
if(is_dir(DOKU_TMP_DATA)) {
// clear indexer data and cache
idx_get_indexer()->clear();
TestUtils::rdelete(DOKU_TMP_DATA);
}
// populate default dirs
TestUtils::rcopy(TMP_DIR, __DIR__ . '/../data/');
}
/**
* Reinitialize the conf directory for this class run
*/
public static function setupConfDir() {
$defaults = [
'acronyms.conf',
'dokuwiki.php',
'entities.conf',
'interwiki.conf',
'license.php',
'manifest.json',
'mediameta.php',
'mime.conf',
'plugins.php',
'plugins.required.php',
'scheme.conf',
'smileys.conf',
'wordblock.conf'
];
// clear any leftovers
if(is_dir(DOKU_CONF)) {
TestUtils::rdelete(DOKU_CONF);
}
mkdir(DOKU_CONF);
// copy defaults
foreach($defaults as $file) {
copy(DOKU_INC . '/conf/' . $file, DOKU_CONF . $file);
}
// copy test files
TestUtils::rcopy(TMP_DIR, __DIR__ . '/../conf');
}
/**
* Waits until a new second has passed
*
* The very first call will return immeadiately, proceeding calls will return
* only after at least 1 second after the last call has passed.
*
* When passing $init=true it will not return immeadiately but use the current
* second as initialization. It might still return faster than a second.
*
* @param bool $init wait from now on, not from last time
* @return int new timestamp
*/
protected function waitForTick($init = false) {
static $last = 0;
if($init) $last = time();
while($last === $now = time()) {
usleep(100000); //recheck in a 10th of a second
}
$last = $now;
return $now;
}
/**
* Allow for testing inaccessible methods (private or protected)
*
* This makes it easier to test protected methods without needing to create intermediate
* classes inheriting and changing the access.
*
* @link https://stackoverflow.com/a/8702347/172068
* @param object $obj Object in which to call the method
* @param string $func The method to call
* @param array $args The arguments to call the method with
* @return mixed
* @throws ReflectionException when the given obj/func does not exist
*/
protected static function callInaccessibleMethod($obj, $func, array $args) {
$class = new \ReflectionClass($obj);
$method = $class->getMethod($func);
$method->setAccessible(true);
return $method->invokeArgs($obj, $args);
}
/**
* Allow for reading inaccessible properties (private or protected)
*
* This makes it easier to check internals of tested objects. This should generally
* be avoided.
*
* @param object $obj Object on which to access the property
* @param string $prop name of the property to access
* @return mixed
* @throws ReflectionException when the given obj/prop does not exist
*/
protected static function getInaccessibleProperty($obj, $prop) {
$class = new \ReflectionClass($obj);
$property = $class->getProperty($prop);
$property->setAccessible(true);
return $property->getValue($obj);
}
/**
* Allow for reading inaccessible properties (private or protected)
*
* This makes it easier to set internals of tested objects. This should generally
* be avoided.
*
* @param object $obj Object on which to access the property
* @param string $prop name of the property to access
* @param mixed $value new value to set the property to
* @return void
* @throws ReflectionException when the given obj/prop does not exist
*/
protected static function setInaccessibleProperty($obj, $prop, $value) {
$class = new \ReflectionClass($obj);
$property = $class->getProperty($prop);
$property->setAccessible(true);
$property->setValue($obj, $value);
}
}