xref: /dokuwiki/_test/core/DokuWikiTest.php (revision 836f6efbf31a2a263102aea61ef0cc5d577aa9bb)
1f8369d7dSTobias Sarnowski<?php
201ef6ea2SAndreas Gohrif(!class_exists('PHPUnit_Framework_TestCase')) {
301ef6ea2SAndreas Gohr    /**
401ef6ea2SAndreas Gohr     * phpunit 5/6 compatibility
501ef6ea2SAndreas Gohr     */
601ef6ea2SAndreas Gohr    class PHPUnit_Framework_TestCase extends PHPUnit\Framework\TestCase {
701ef6ea2SAndreas Gohr        /**
83c1490b3SPhy         * setExpectedException is deprecated in PHPUnit 6
93c1490b3SPhy         *
1001ef6ea2SAndreas Gohr         * @param string $class
1101ef6ea2SAndreas Gohr         * @param null|string $message
1201ef6ea2SAndreas Gohr         */
1301ef6ea2SAndreas Gohr        public function setExpectedException($class, $message=null) {
1401ef6ea2SAndreas Gohr            $this->expectException($class);
1501ef6ea2SAndreas Gohr            if(!is_null($message)) {
1601ef6ea2SAndreas Gohr                $this->expectExceptionMessage($message);
1701ef6ea2SAndreas Gohr            }
1801ef6ea2SAndreas Gohr        }
1901ef6ea2SAndreas Gohr    }
2001ef6ea2SAndreas Gohr}
2101ef6ea2SAndreas Gohr
22f8369d7dSTobias Sarnowski/**
23f8369d7dSTobias Sarnowski * Helper class to provide basic functionality for tests
243c1490b3SPhy *
253c1490b3SPhy * @uses PHPUnit_Framework_TestCase and thus PHPUnit 5.7+ is required
26f8369d7dSTobias Sarnowski */
2701ef6ea2SAndreas Gohrabstract class DokuWikiTest extends PHPUnit_Framework_TestCase {
28f8369d7dSTobias Sarnowski
29f8369d7dSTobias Sarnowski    /**
30f8369d7dSTobias Sarnowski     * tests can override this
31f8369d7dSTobias Sarnowski     *
32f8369d7dSTobias Sarnowski     * @var array plugins to enable for test class
33f8369d7dSTobias Sarnowski     */
34f8369d7dSTobias Sarnowski    protected $pluginsEnabled = array();
35f8369d7dSTobias Sarnowski
36f8369d7dSTobias Sarnowski    /**
37f8369d7dSTobias Sarnowski     * tests can override this
38f8369d7dSTobias Sarnowski     *
39f8369d7dSTobias Sarnowski     * @var array plugins to disable for test class
40f8369d7dSTobias Sarnowski     */
41f8369d7dSTobias Sarnowski    protected $pluginsDisabled = array();
42f8369d7dSTobias Sarnowski
43f8369d7dSTobias Sarnowski    /**
440644090aSAndreas Gohr     * Setup the data directory
450644090aSAndreas Gohr     *
460644090aSAndreas Gohr     * This is ran before each test class
470644090aSAndreas Gohr     */
480644090aSAndreas Gohr    public static function setUpBeforeClass() {
490644090aSAndreas Gohr        // just to be safe not to delete something undefined later
500644090aSAndreas Gohr        if(!defined('TMP_DIR')) die('no temporary directory');
510644090aSAndreas Gohr        if(!defined('DOKU_TMP_DATA')) die('no temporary data directory');
520644090aSAndreas Gohr
530644090aSAndreas Gohr        // remove any leftovers from the last run
540644090aSAndreas Gohr        if(is_dir(DOKU_TMP_DATA)){
554f708321SMichael Hamann            // clear indexer data and cache
564f708321SMichael Hamann            idx_get_indexer()->clear();
570644090aSAndreas Gohr            TestUtils::rdelete(DOKU_TMP_DATA);
580644090aSAndreas Gohr        }
590644090aSAndreas Gohr
600644090aSAndreas Gohr        // populate default dirs
610644090aSAndreas Gohr        TestUtils::rcopy(TMP_DIR, dirname(__FILE__).'/../data/');
620644090aSAndreas Gohr    }
630644090aSAndreas Gohr
640644090aSAndreas Gohr    /**
65f8369d7dSTobias Sarnowski     * Reset the DokuWiki environment before each test run. Makes sure loaded config,
66f8369d7dSTobias Sarnowski     * language and plugins are correct.
67f8369d7dSTobias Sarnowski     *
68f8369d7dSTobias Sarnowski     * @throws Exception if plugin actions fail
69f8369d7dSTobias Sarnowski     * @return void
70f8369d7dSTobias Sarnowski     */
71f8369d7dSTobias Sarnowski    public function setUp() {
720644090aSAndreas Gohr
73f8369d7dSTobias Sarnowski        // reload config
74f8369d7dSTobias Sarnowski        global $conf, $config_cascade;
75f8369d7dSTobias Sarnowski        $conf = array();
76f8369d7dSTobias Sarnowski        foreach (array('default','local','protected') as $config_group) {
77f8369d7dSTobias Sarnowski            if (empty($config_cascade['main'][$config_group])) continue;
78f8369d7dSTobias Sarnowski            foreach ($config_cascade['main'][$config_group] as $config_file) {
7979e79377SAndreas Gohr                if (file_exists($config_file)) {
80f8369d7dSTobias Sarnowski                    include($config_file);
81f8369d7dSTobias Sarnowski                }
82f8369d7dSTobias Sarnowski            }
83f8369d7dSTobias Sarnowski        }
84f8369d7dSTobias Sarnowski
85f8369d7dSTobias Sarnowski        // reload license config
86f8369d7dSTobias Sarnowski        global $license;
87f8369d7dSTobias Sarnowski        $license = array();
88f8369d7dSTobias Sarnowski
89f8369d7dSTobias Sarnowski        // load the license file(s)
90f8369d7dSTobias Sarnowski        foreach (array('default','local') as $config_group) {
91f8369d7dSTobias Sarnowski            if (empty($config_cascade['license'][$config_group])) continue;
92f8369d7dSTobias Sarnowski            foreach ($config_cascade['license'][$config_group] as $config_file) {
9379e79377SAndreas Gohr                if(file_exists($config_file)){
94f8369d7dSTobias Sarnowski                    include($config_file);
95f8369d7dSTobias Sarnowski                }
96f8369d7dSTobias Sarnowski            }
97f8369d7dSTobias Sarnowski        }
98f48e16abSGerrit Uitslag        // reload some settings
99f48e16abSGerrit Uitslag        $conf['gzip_output'] &= (strpos($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip') !== false);
100f8369d7dSTobias Sarnowski
101f48e16abSGerrit Uitslag        if($conf['compression'] == 'bz2' && !DOKU_HAS_BZIP) {
102f48e16abSGerrit Uitslag            $conf['compression'] = 'gz';
103f48e16abSGerrit Uitslag        }
104f48e16abSGerrit Uitslag        if($conf['compression'] == 'gz' && !DOKU_HAS_GZIP) {
105f48e16abSGerrit Uitslag            $conf['compression'] = 0;
106f48e16abSGerrit Uitslag        }
107f8369d7dSTobias Sarnowski        // make real paths and check them
108f8369d7dSTobias Sarnowski        init_paths();
109f8369d7dSTobias Sarnowski        init_files();
110f8369d7dSTobias Sarnowski
111f8369d7dSTobias Sarnowski        // reset loaded plugins
112f8369d7dSTobias Sarnowski        global $plugin_controller_class, $plugin_controller;
113e3ab6fc5SMichael Hamann        /** @var Doku_Plugin_Controller $plugin_controller */
114f8369d7dSTobias Sarnowski        $plugin_controller = new $plugin_controller_class();
115f8369d7dSTobias Sarnowski
116f8369d7dSTobias Sarnowski        // disable all non-default plugins
117f8369d7dSTobias Sarnowski        global $default_plugins;
118f8369d7dSTobias Sarnowski        foreach ($plugin_controller->getList() as $plugin) {
119f8369d7dSTobias Sarnowski            if (!in_array($plugin, $default_plugins)) {
120f8369d7dSTobias Sarnowski                if (!$plugin_controller->disable($plugin)) {
121f8369d7dSTobias Sarnowski                    throw new Exception('Could not disable plugin "'.$plugin.'"!');
122f8369d7dSTobias Sarnowski                }
123f8369d7dSTobias Sarnowski            }
124f8369d7dSTobias Sarnowski        }
125f8369d7dSTobias Sarnowski
126f8369d7dSTobias Sarnowski        // disable and enable configured plugins
127f8369d7dSTobias Sarnowski        foreach ($this->pluginsDisabled as $plugin) {
128f8369d7dSTobias Sarnowski            if (!$plugin_controller->disable($plugin)) {
129f8369d7dSTobias Sarnowski                throw new Exception('Could not disable plugin "'.$plugin.'"!');
130f8369d7dSTobias Sarnowski            }
131f8369d7dSTobias Sarnowski        }
132f8369d7dSTobias Sarnowski        foreach ($this->pluginsEnabled as $plugin) {
133f8369d7dSTobias Sarnowski            /*  enable() returns false but works...
134f8369d7dSTobias Sarnowski            if (!$plugin_controller->enable($plugin)) {
135f8369d7dSTobias Sarnowski                throw new Exception('Could not enable plugin "'.$plugin.'"!');
136f8369d7dSTobias Sarnowski            }
137f8369d7dSTobias Sarnowski            */
138f8369d7dSTobias Sarnowski            $plugin_controller->enable($plugin);
139f8369d7dSTobias Sarnowski        }
140f8369d7dSTobias Sarnowski
141f8369d7dSTobias Sarnowski        // reset event handler
142f8369d7dSTobias Sarnowski        global $EVENT_HANDLER;
143f8369d7dSTobias Sarnowski        $EVENT_HANDLER = new Doku_Event_Handler();
144f8369d7dSTobias Sarnowski
145f8369d7dSTobias Sarnowski        // reload language
146f8369d7dSTobias Sarnowski        $local = $conf['lang'];
147f8369d7dSTobias Sarnowski        trigger_event('INIT_LANG_LOAD', $local, 'init_lang', true);
148c01cdb70SChristopher Smith
149c01cdb70SChristopher Smith        global $INPUT;
150c01cdb70SChristopher Smith        $INPUT = new Input();
151f8369d7dSTobias Sarnowski    }
152db5867f1SAndreas Gohr
153db5867f1SAndreas Gohr    /**
154d732617bSAndreas Gohr     * Waits until a new second has passed
155d732617bSAndreas Gohr     *
156d732617bSAndreas Gohr     * The very first call will return immeadiately, proceeding calls will return
157d732617bSAndreas Gohr     * only after at least 1 second after the last call has passed.
158d732617bSAndreas Gohr     *
159d732617bSAndreas Gohr     * When passing $init=true it will not return immeadiately but use the current
160d732617bSAndreas Gohr     * second as initialization. It might still return faster than a second.
161d732617bSAndreas Gohr     *
162d732617bSAndreas Gohr     * @param bool $init wait from now on, not from last time
163d732617bSAndreas Gohr     * @return int new timestamp
164d732617bSAndreas Gohr     */
165d732617bSAndreas Gohr    protected function waitForTick($init = false) {
166d732617bSAndreas Gohr        static $last = 0;
167d732617bSAndreas Gohr        if($init) $last = time();
168d732617bSAndreas Gohr        while($last === $now = time()) {
169d732617bSAndreas Gohr            usleep(100000); //recheck in a 10th of a second
170d732617bSAndreas Gohr        }
171d732617bSAndreas Gohr        $last = $now;
172d732617bSAndreas Gohr        return $now;
173d732617bSAndreas Gohr    }
174210ff133SAndreas Gohr
175210ff133SAndreas Gohr    /**
176210ff133SAndreas Gohr     * Allow for testing inaccessible methods (private or protected)
177210ff133SAndreas Gohr     *
178210ff133SAndreas Gohr     * This makes it easier to test protected methods without needing to create intermediate
179210ff133SAndreas Gohr     * classes inheriting and changing the access.
180210ff133SAndreas Gohr     *
181210ff133SAndreas Gohr     * @link https://stackoverflow.com/a/8702347/172068
182210ff133SAndreas Gohr     * @param object $obj Object in which to call the method
183210ff133SAndreas Gohr     * @param string $func The method to call
184210ff133SAndreas Gohr     * @param array $args The arguments to call the method with
185210ff133SAndreas Gohr     * @return mixed
186210ff133SAndreas Gohr     * @throws ReflectionException when the given obj/func does not exist
187210ff133SAndreas Gohr     */
188210ff133SAndreas Gohr    protected static function callInaccessibleMethod($obj, $func, array $args) {
189210ff133SAndreas Gohr        $class = new \ReflectionClass($obj);
190210ff133SAndreas Gohr        $method = $class->getMethod($func);
191210ff133SAndreas Gohr        $method->setAccessible(true);
192210ff133SAndreas Gohr        return $method->invokeArgs($obj, $args);
193210ff133SAndreas Gohr    }
194*836f6efbSAndreas Gohr
195*836f6efbSAndreas Gohr    /**
196*836f6efbSAndreas Gohr     * Allow for reading inaccessible properties (private or protected)
197*836f6efbSAndreas Gohr     *
198*836f6efbSAndreas Gohr     * This makes it easier to check internals of tested objects. This should generally
199*836f6efbSAndreas Gohr     * be avoided.
200*836f6efbSAndreas Gohr     *
201*836f6efbSAndreas Gohr     * @param object $obj Object on which to access the property
202*836f6efbSAndreas Gohr     * @param string $prop name of the property to access
203*836f6efbSAndreas Gohr     * @return mixed
204*836f6efbSAndreas Gohr     * @throws ReflectionException  when the given obj/prop does not exist
205*836f6efbSAndreas Gohr     */
206*836f6efbSAndreas Gohr    protected static function getInaccessibleProperty($obj, $prop) {
207*836f6efbSAndreas Gohr        $class = new \ReflectionClass($obj);
208*836f6efbSAndreas Gohr        $property = $class->getProperty($prop);
209*836f6efbSAndreas Gohr        $property->setAccessible(true);
210*836f6efbSAndreas Gohr        return $property->getValue($obj);
211*836f6efbSAndreas Gohr    }
212*836f6efbSAndreas Gohr
213*836f6efbSAndreas Gohr    /**
214*836f6efbSAndreas Gohr     * Allow for reading inaccessible properties (private or protected)
215*836f6efbSAndreas Gohr     *
216*836f6efbSAndreas Gohr     * This makes it easier to set internals of tested objects. This should generally
217*836f6efbSAndreas Gohr     * be avoided.
218*836f6efbSAndreas Gohr     *
219*836f6efbSAndreas Gohr     * @param object $obj Object on which to access the property
220*836f6efbSAndreas Gohr     * @param string $prop name of the property to access
221*836f6efbSAndreas Gohr     * @param mixed $value new value to set the property to
222*836f6efbSAndreas Gohr     * @return void
223*836f6efbSAndreas Gohr     * @throws ReflectionException when the given obj/prop does not exist
224*836f6efbSAndreas Gohr     */
225*836f6efbSAndreas Gohr    protected static function setInaccessibleProperty($obj, $prop, $value) {
226*836f6efbSAndreas Gohr        $class = new \ReflectionClass($obj);
227*836f6efbSAndreas Gohr        $property = $class->getProperty($prop);
228*836f6efbSAndreas Gohr        $property->setAccessible(true);
229*836f6efbSAndreas Gohr        $property->setValue($obj, $value);
230*836f6efbSAndreas Gohr    }
231f8369d7dSTobias Sarnowski}
232