xref: /dokuwiki/_test/core/DokuWikiTest.php (revision 1c0be3ebd170acad3e1fddf2aca104afaf2416ee)
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
53*1c0be3ebSAndreas Gohr        self::setupDataDir();
54*1c0be3ebSAndreas Gohr        self::setupConfDir();
550644090aSAndreas Gohr    }
560644090aSAndreas Gohr
570644090aSAndreas Gohr    /**
58f8369d7dSTobias Sarnowski     * Reset the DokuWiki environment before each test run. Makes sure loaded config,
59f8369d7dSTobias Sarnowski     * language and plugins are correct.
60f8369d7dSTobias Sarnowski     *
61f8369d7dSTobias Sarnowski     * @throws Exception if plugin actions fail
62f8369d7dSTobias Sarnowski     * @return void
63f8369d7dSTobias Sarnowski     */
64f8369d7dSTobias Sarnowski    public function setUp() {
650644090aSAndreas Gohr
66f8369d7dSTobias Sarnowski        // reload config
67f8369d7dSTobias Sarnowski        global $conf, $config_cascade;
68f8369d7dSTobias Sarnowski        $conf = array();
69f8369d7dSTobias Sarnowski        foreach (array('default','local','protected') as $config_group) {
70f8369d7dSTobias Sarnowski            if (empty($config_cascade['main'][$config_group])) continue;
71f8369d7dSTobias Sarnowski            foreach ($config_cascade['main'][$config_group] as $config_file) {
7279e79377SAndreas Gohr                if (file_exists($config_file)) {
73f8369d7dSTobias Sarnowski                    include($config_file);
74f8369d7dSTobias Sarnowski                }
75f8369d7dSTobias Sarnowski            }
76f8369d7dSTobias Sarnowski        }
77f8369d7dSTobias Sarnowski
78f8369d7dSTobias Sarnowski        // reload license config
79f8369d7dSTobias Sarnowski        global $license;
80f8369d7dSTobias Sarnowski        $license = array();
81f8369d7dSTobias Sarnowski
82f8369d7dSTobias Sarnowski        // load the license file(s)
83f8369d7dSTobias Sarnowski        foreach (array('default','local') as $config_group) {
84f8369d7dSTobias Sarnowski            if (empty($config_cascade['license'][$config_group])) continue;
85f8369d7dSTobias Sarnowski            foreach ($config_cascade['license'][$config_group] as $config_file) {
8679e79377SAndreas Gohr                if(file_exists($config_file)){
87f8369d7dSTobias Sarnowski                    include($config_file);
88f8369d7dSTobias Sarnowski                }
89f8369d7dSTobias Sarnowski            }
90f8369d7dSTobias Sarnowski        }
91f48e16abSGerrit Uitslag        // reload some settings
92f48e16abSGerrit Uitslag        $conf['gzip_output'] &= (strpos($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip') !== false);
93f8369d7dSTobias Sarnowski
94f48e16abSGerrit Uitslag        if($conf['compression'] == 'bz2' && !DOKU_HAS_BZIP) {
95f48e16abSGerrit Uitslag            $conf['compression'] = 'gz';
96f48e16abSGerrit Uitslag        }
97f48e16abSGerrit Uitslag        if($conf['compression'] == 'gz' && !DOKU_HAS_GZIP) {
98f48e16abSGerrit Uitslag            $conf['compression'] = 0;
99f48e16abSGerrit Uitslag        }
100f8369d7dSTobias Sarnowski        // make real paths and check them
101f8369d7dSTobias Sarnowski        init_paths();
102f8369d7dSTobias Sarnowski        init_files();
103f8369d7dSTobias Sarnowski
104f8369d7dSTobias Sarnowski        // reset loaded plugins
105f8369d7dSTobias Sarnowski        global $plugin_controller_class, $plugin_controller;
106e3ab6fc5SMichael Hamann        /** @var Doku_Plugin_Controller $plugin_controller */
107f8369d7dSTobias Sarnowski        $plugin_controller = new $plugin_controller_class();
108f8369d7dSTobias Sarnowski
109f8369d7dSTobias Sarnowski        // disable all non-default plugins
110f8369d7dSTobias Sarnowski        global $default_plugins;
111f8369d7dSTobias Sarnowski        foreach ($plugin_controller->getList() as $plugin) {
112f8369d7dSTobias Sarnowski            if (!in_array($plugin, $default_plugins)) {
113f8369d7dSTobias Sarnowski                if (!$plugin_controller->disable($plugin)) {
114f8369d7dSTobias Sarnowski                    throw new Exception('Could not disable plugin "'.$plugin.'"!');
115f8369d7dSTobias Sarnowski                }
116f8369d7dSTobias Sarnowski            }
117f8369d7dSTobias Sarnowski        }
118f8369d7dSTobias Sarnowski
119f8369d7dSTobias Sarnowski        // disable and enable configured plugins
120f8369d7dSTobias Sarnowski        foreach ($this->pluginsDisabled as $plugin) {
121f8369d7dSTobias Sarnowski            if (!$plugin_controller->disable($plugin)) {
122f8369d7dSTobias Sarnowski                throw new Exception('Could not disable plugin "'.$plugin.'"!');
123f8369d7dSTobias Sarnowski            }
124f8369d7dSTobias Sarnowski        }
125f8369d7dSTobias Sarnowski        foreach ($this->pluginsEnabled as $plugin) {
126f8369d7dSTobias Sarnowski            /*  enable() returns false but works...
127f8369d7dSTobias Sarnowski            if (!$plugin_controller->enable($plugin)) {
128f8369d7dSTobias Sarnowski                throw new Exception('Could not enable plugin "'.$plugin.'"!');
129f8369d7dSTobias Sarnowski            }
130f8369d7dSTobias Sarnowski            */
131f8369d7dSTobias Sarnowski            $plugin_controller->enable($plugin);
132f8369d7dSTobias Sarnowski        }
133f8369d7dSTobias Sarnowski
134f8369d7dSTobias Sarnowski        // reset event handler
135f8369d7dSTobias Sarnowski        global $EVENT_HANDLER;
136f8369d7dSTobias Sarnowski        $EVENT_HANDLER = new Doku_Event_Handler();
137f8369d7dSTobias Sarnowski
138f8369d7dSTobias Sarnowski        // reload language
139f8369d7dSTobias Sarnowski        $local = $conf['lang'];
140f8369d7dSTobias Sarnowski        trigger_event('INIT_LANG_LOAD', $local, 'init_lang', true);
141c01cdb70SChristopher Smith
142c01cdb70SChristopher Smith        global $INPUT;
143c01cdb70SChristopher Smith        $INPUT = new Input();
144f8369d7dSTobias Sarnowski    }
145db5867f1SAndreas Gohr
146db5867f1SAndreas Gohr    /**
147*1c0be3ebSAndreas Gohr     * Reinitialize the data directory for this class run
148*1c0be3ebSAndreas Gohr     */
149*1c0be3ebSAndreas Gohr    public static function setupDataDir() {
150*1c0be3ebSAndreas Gohr        // remove any leftovers from the last run
151*1c0be3ebSAndreas Gohr        if(is_dir(DOKU_TMP_DATA)) {
152*1c0be3ebSAndreas Gohr            // clear indexer data and cache
153*1c0be3ebSAndreas Gohr            idx_get_indexer()->clear();
154*1c0be3ebSAndreas Gohr            TestUtils::rdelete(DOKU_TMP_DATA);
155*1c0be3ebSAndreas Gohr        }
156*1c0be3ebSAndreas Gohr
157*1c0be3ebSAndreas Gohr        // populate default dirs
158*1c0be3ebSAndreas Gohr        TestUtils::rcopy(TMP_DIR, __DIR__ . '/../data/');
159*1c0be3ebSAndreas Gohr    }
160*1c0be3ebSAndreas Gohr
161*1c0be3ebSAndreas Gohr    /**
162*1c0be3ebSAndreas Gohr     * Reinitialize the conf directory for this class run
163*1c0be3ebSAndreas Gohr     */
164*1c0be3ebSAndreas Gohr    public static function setupConfDir() {
165*1c0be3ebSAndreas Gohr        $defaults = [
166*1c0be3ebSAndreas Gohr            'acronyms.conf',
167*1c0be3ebSAndreas Gohr            'dokuwiki.php',
168*1c0be3ebSAndreas Gohr            'entities.conf',
169*1c0be3ebSAndreas Gohr            'interwiki.conf',
170*1c0be3ebSAndreas Gohr            'license.php',
171*1c0be3ebSAndreas Gohr            'manifest.json',
172*1c0be3ebSAndreas Gohr            'mediameta.php',
173*1c0be3ebSAndreas Gohr            'mime.conf',
174*1c0be3ebSAndreas Gohr            'plugins.php',
175*1c0be3ebSAndreas Gohr            'plugins.required.php',
176*1c0be3ebSAndreas Gohr            'scheme.conf',
177*1c0be3ebSAndreas Gohr            'smileys.conf',
178*1c0be3ebSAndreas Gohr            'wordblock.conf'
179*1c0be3ebSAndreas Gohr        ];
180*1c0be3ebSAndreas Gohr
181*1c0be3ebSAndreas Gohr        // clear any leftovers
182*1c0be3ebSAndreas Gohr        if(is_dir(DOKU_CONF)) {
183*1c0be3ebSAndreas Gohr            TestUtils::rdelete(DOKU_CONF);
184*1c0be3ebSAndreas Gohr        }
185*1c0be3ebSAndreas Gohr        mkdir(DOKU_CONF);
186*1c0be3ebSAndreas Gohr
187*1c0be3ebSAndreas Gohr        // copy defaults
188*1c0be3ebSAndreas Gohr        foreach($defaults as $file) {
189*1c0be3ebSAndreas Gohr            copy(DOKU_INC . '/conf/' . $file, DOKU_CONF . $file);
190*1c0be3ebSAndreas Gohr        }
191*1c0be3ebSAndreas Gohr
192*1c0be3ebSAndreas Gohr        // copy test files
193*1c0be3ebSAndreas Gohr        TestUtils::rcopy(TMP_DIR, __DIR__ . '/../conf');
194*1c0be3ebSAndreas Gohr    }
195*1c0be3ebSAndreas Gohr
196*1c0be3ebSAndreas Gohr    /**
197d732617bSAndreas Gohr     * Waits until a new second has passed
198d732617bSAndreas Gohr     *
199d732617bSAndreas Gohr     * The very first call will return immeadiately, proceeding calls will return
200d732617bSAndreas Gohr     * only after at least 1 second after the last call has passed.
201d732617bSAndreas Gohr     *
202d732617bSAndreas Gohr     * When passing $init=true it will not return immeadiately but use the current
203d732617bSAndreas Gohr     * second as initialization. It might still return faster than a second.
204d732617bSAndreas Gohr     *
205d732617bSAndreas Gohr     * @param bool $init wait from now on, not from last time
206d732617bSAndreas Gohr     * @return int new timestamp
207d732617bSAndreas Gohr     */
208d732617bSAndreas Gohr    protected function waitForTick($init = false) {
209d732617bSAndreas Gohr        static $last = 0;
210d732617bSAndreas Gohr        if($init) $last = time();
211d732617bSAndreas Gohr        while($last === $now = time()) {
212d732617bSAndreas Gohr            usleep(100000); //recheck in a 10th of a second
213d732617bSAndreas Gohr        }
214d732617bSAndreas Gohr        $last = $now;
215d732617bSAndreas Gohr        return $now;
216d732617bSAndreas Gohr    }
217210ff133SAndreas Gohr
218210ff133SAndreas Gohr    /**
219210ff133SAndreas Gohr     * Allow for testing inaccessible methods (private or protected)
220210ff133SAndreas Gohr     *
221210ff133SAndreas Gohr     * This makes it easier to test protected methods without needing to create intermediate
222210ff133SAndreas Gohr     * classes inheriting and changing the access.
223210ff133SAndreas Gohr     *
224210ff133SAndreas Gohr     * @link https://stackoverflow.com/a/8702347/172068
225210ff133SAndreas Gohr     * @param object $obj Object in which to call the method
226210ff133SAndreas Gohr     * @param string $func The method to call
227210ff133SAndreas Gohr     * @param array $args The arguments to call the method with
228210ff133SAndreas Gohr     * @return mixed
229210ff133SAndreas Gohr     * @throws ReflectionException when the given obj/func does not exist
230210ff133SAndreas Gohr     */
231210ff133SAndreas Gohr    protected static function callInaccessibleMethod($obj, $func, array $args) {
232210ff133SAndreas Gohr        $class = new \ReflectionClass($obj);
233210ff133SAndreas Gohr        $method = $class->getMethod($func);
234210ff133SAndreas Gohr        $method->setAccessible(true);
235210ff133SAndreas Gohr        return $method->invokeArgs($obj, $args);
236210ff133SAndreas Gohr    }
237f8369d7dSTobias Sarnowski}
238