source: Dev/branches/cakephp/cake/console/libs/testsuite.php @ 126

Last change on this file since 126 was 126, checked in by fpvanagthoven, 14 years ago

Cakephp branch.

File size: 9.8 KB
Line 
1<?php
2/**
3 * Test Suite Shell
4 *
5 * This Shell allows the running of test suites via the cake command line
6 *
7 * PHP versions 4 and 5
8 *
9 * CakePHP(tm) Tests <http://book.cakephp.org/view/1196/Testing>
10 * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
11 *
12 *  Licensed under The Open Group Test Suite License
13 *  Redistributions of files must retain the above copyright notice.
14 *
15 * @copyright     Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
16 * @link          http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
17 * @package       cake
18 * @subpackage    cake.cake.console.libs
19 * @since         CakePHP(tm) v 1.2.0.4433
20 * @license       http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
21 */
22class TestSuiteShell extends Shell {
23
24/**
25 * The test category, "app", "core" or the name of a plugin
26 *
27 * @var string
28 * @access public
29 */
30        var $category = '';
31
32/**
33 * "group", "case" or "all"
34 *
35 * @var string
36 * @access public
37 */
38        var $type = '';
39
40/**
41 * Path to the test case/group file
42 *
43 * @var string
44 * @access public
45 */
46        var $file = '';
47
48/**
49 * Storage for plugins that have tests
50 *
51 * @var string
52 * @access public
53 */
54        var $plugins = array();
55
56/**
57 * Convenience variable to avoid duplicated code
58 *
59 * @var string
60 * @access public
61 */
62        var $isPluginTest = false;
63
64/**
65 * Stores if the user wishes to get a code coverage analysis report
66 *
67 * @var string
68 * @access public
69 */
70        var $doCoverage = false;
71
72/**
73 * Initialization method installs Simpletest and loads all plugins
74 *
75 * @return void
76 * @access public
77 */
78        function initialize() {
79                $corePath = App::core('cake');
80                if (isset($corePath[0])) {
81                        define('TEST_CAKE_CORE_INCLUDE_PATH', rtrim($corePath[0], DS) . DS);
82                } else {
83                        define('TEST_CAKE_CORE_INCLUDE_PATH', CAKE_CORE_INCLUDE_PATH);
84                }
85
86                $this->__installSimpleTest();
87
88                require_once CAKE . 'tests' . DS . 'lib' . DS . 'test_manager.php';
89                require_once CAKE . 'tests' . DS . 'lib' . DS . 'reporter' . DS . 'cake_cli_reporter.php';
90
91                $plugins = App::objects('plugin');
92                foreach ($plugins as $p) {
93                        $this->plugins[] = Inflector::underscore($p);
94                }
95                $this->parseArgs();
96                $this->getManager();
97        }
98
99/**
100 * Parse the arguments given into the Shell object properties.
101 *
102 * @return void
103 * @access public
104 */
105        function parseArgs() {
106                if (empty($this->args)) {
107                        return;
108                }
109                $this->category = $this->args[0];
110
111                if (!in_array($this->category, array('app', 'core'))) {
112                        $this->isPluginTest = true;
113                }
114
115                if (isset($this->args[1])) {
116                        $this->type = $this->args[1];
117                }
118
119                if (isset($this->args[2])) {
120                        if ($this->args[2] == 'cov') {
121                                $this->doCoverage = true;
122                        } else {
123                                $this->file = Inflector::underscore($this->args[2]);
124                        }
125                }
126
127                if (isset($this->args[3]) && $this->args[3] == 'cov') {
128                        $this->doCoverage = true;
129                }
130        }
131
132/**
133 * Gets a manager instance, and set the app/plugin properties.
134 *
135 * @return void
136 */
137        function getManager() {
138                $this->Manager = new TestManager();
139                $this->Manager->appTest = ($this->category === 'app');
140                if ($this->isPluginTest) {
141                        $this->Manager->pluginTest = $this->category;
142                }
143        }
144
145/**
146 * Main entry point to this shell
147 *
148 * @return void
149 * @access public
150 */
151        function main() {
152                $this->out(__('CakePHP Test Shell', true));
153                $this->hr();
154
155                if (count($this->args) == 0) {
156                        $this->error(__('Sorry, you did not pass any arguments!', true));
157                }
158
159                if ($this->__canRun()) {
160                        $message = sprintf(__('Running %s %s %s', true), $this->category, $this->type, $this->file);
161                        $this->out($message);
162
163                        $exitCode = 0;
164                        if (!$this->__run()) {
165                                $exitCode = 1;
166                        }
167                        $this->_stop($exitCode);
168                } else {
169                        $this->error(__('Sorry, the tests could not be found.', true));
170                }
171        }
172
173/**
174 * Help screen
175 *
176 * @return void
177 * @access public
178 */
179        function help() {
180                $this->out('Usage: ');
181                $this->out("\tcake testsuite category test_type file");
182                $this->out("\t\t- category - \"app\", \"core\" or name of a plugin");
183                $this->out("\t\t- test_type - \"case\", \"group\" or \"all\"");
184                $this->out("\t\t- test_file - file name with folder prefix and without the (test|group).php suffix");
185                $this->out();
186                $this->out('Examples: ');
187                $this->out("\t\tcake testsuite app all");
188                $this->out("\t\tcake testsuite core all");
189                $this->out();
190                $this->out("\t\tcake testsuite app case behaviors/debuggable");
191                $this->out("\t\tcake testsuite app case models/my_model");
192                $this->out("\t\tcake testsuite app case controllers/my_controller");
193                $this->out();
194                $this->out("\t\tcake testsuite core case file");
195                $this->out("\t\tcake testsuite core case router");
196                $this->out("\t\tcake testsuite core case set");
197                $this->out();
198                $this->out("\t\tcake testsuite app group mygroup");
199                $this->out("\t\tcake testsuite core group acl");
200                $this->out("\t\tcake testsuite core group socket");
201                $this->out();
202                $this->out("\t\tcake testsuite bugs case models/bug");
203                $this->out("\t\t  // for the plugin 'bugs' and its test case 'models/bug'");
204                $this->out("\t\tcake testsuite bugs group bug");
205                $this->out("\t\t  // for the plugin bugs and its test group 'bug'");
206                $this->out();
207                $this->out('Code Coverage Analysis: ');
208                $this->out("\n\nAppend 'cov' to any of the above in order to enable code coverage analysis");
209        }
210
211/**
212 * Checks if the arguments supplied point to a valid test file and thus the shell can be run.
213 *
214 * @return bool true if it's a valid test file, false otherwise
215 * @access private
216 */
217        function __canRun() {
218                $isNeitherAppNorCore = !in_array($this->category, array('app', 'core'));
219                $isPlugin = in_array(Inflector::underscore($this->category), $this->plugins);
220
221                if ($isNeitherAppNorCore && !$isPlugin) {
222                        $message = sprintf(
223                                __('%s is an invalid test category (either "app", "core" or name of a plugin)', true),
224                                $this->category
225                        );
226                        $this->error($message);
227                        return false;
228                }
229
230                $folder = $this->__findFolderByCategory($this->category);
231                if (!file_exists($folder)) {
232                        $this->err(sprintf(__('%s not found', true), $folder));
233                        return false;
234                }
235
236                if (!in_array($this->type, array('all', 'group', 'case'))) {
237                        $this->err(sprintf(__('%s is invalid. Should be case, group or all', true), $this->type));
238                        return false;
239                }
240
241                $fileName = $this->__getFileName($folder, $this->isPluginTest);
242                if ($fileName === true || file_exists($folder . $fileName)) {
243                        return true;
244                }
245
246                $message = sprintf(
247                        __('%s %s %s is an invalid test identifier', true),
248                        $this->category, $this->type, $this->file
249                );
250                $this->err($message);
251                return false;
252        }
253/**
254 * Executes the tests depending on our settings
255 *
256 * @return void
257 * @access private
258 */
259        function __run() {
260                $Reporter = new CakeCliReporter('utf-8', array(
261                        'app' => $this->Manager->appTest,
262                        'plugin' => $this->Manager->pluginTest,
263                        'group' => ($this->type === 'group'),
264                        'codeCoverage' => $this->doCoverage
265                ));
266
267                if ($this->type == 'all') {
268                        return $this->Manager->runAllTests($Reporter);
269                }
270
271                if ($this->doCoverage) {
272                        if (!extension_loaded('xdebug')) {
273                                $this->out(__('You must install Xdebug to use the CakePHP(tm) Code Coverage Analyzation. Download it from http://www.xdebug.org/docs/install', true));
274                                $this->_stop(0);
275                        }
276                }
277
278                if ($this->type == 'group') {
279                        $ucFirstGroup = ucfirst($this->file);
280                        if ($this->doCoverage) {
281                                require_once CAKE . 'tests' . DS . 'lib' . DS . 'code_coverage_manager.php';
282                                CodeCoverageManager::init($ucFirstGroup, $Reporter);
283                                CodeCoverageManager::start();
284                        }
285                        $result = $this->Manager->runGroupTest($ucFirstGroup, $Reporter);
286                        return $result;
287                }
288
289                $folder = $folder = $this->__findFolderByCategory($this->category);
290                $case = $this->__getFileName($folder, $this->isPluginTest);
291
292                if ($this->doCoverage) {
293                        require_once CAKE . 'tests' . DS . 'lib' . DS . 'code_coverage_manager.php';
294                        CodeCoverageManager::init($case, $Reporter);
295                        CodeCoverageManager::start();
296                }
297                $result = $this->Manager->runTestCase($case, $Reporter);
298                return $result;
299        }
300
301/**
302 * Gets the concrete filename for the inputted test name and category/type
303 *
304 * @param string $folder Folder name to look for files in.
305 * @param boolean $isPlugin If the test case is a plugin.
306 * @return mixed Either string filename or boolean false on failure. Or true if the type is 'all'
307 * @access private
308 */
309        function __getFileName($folder, $isPlugin) {
310                $ext = $this->Manager->getExtension($this->type);
311                switch ($this->type) {
312                        case 'all':
313                                return true;
314                        case 'group':
315                                return $this->file . $ext;
316                        case 'case':
317                                if ($this->category == 'app' || $isPlugin) {
318                                        return $this->file . $ext;
319                                }
320                                $coreCase = $this->file . $ext;
321                                $coreLibCase = 'libs' . DS . $this->file . $ext;
322
323                                if ($this->category == 'core' && file_exists($folder . DS . $coreCase)) {
324                                        return $coreCase;
325                                } elseif ($this->category == 'core' && file_exists($folder . DS . $coreLibCase)) {
326                                        return $coreLibCase;
327                                }
328                }
329                return false;
330        }
331
332/**
333 * Finds the correct folder to look for tests for based on the input category and type.
334 *
335 * @param string $category The category of the test.  Either 'app', 'core' or a plugin name.
336 * @return string the folder path
337 * @access private
338 */
339        function __findFolderByCategory($category) {
340                $folder = '';
341                $paths = array(
342                        'core' => CAKE,
343                        'app' => APP
344                );
345                $typeDir = $this->type === 'group' ? 'groups' : 'cases';
346
347                if (array_key_exists($category, $paths)) {
348                        $folder = $paths[$category] . 'tests' . DS . $typeDir . DS;
349                } else {
350                        $pluginPath = App::pluginPath($category);
351                        if (is_dir($pluginPath . 'tests')) {
352                                $folder = $pluginPath . 'tests' . DS . $typeDir . DS;
353                        }
354                }
355                return $folder;
356        }
357
358/**
359 * tries to install simpletest and exits gracefully if it is not there
360 *
361 * @return void
362 * @access private
363 */
364        function __installSimpleTest() {
365                if (!App::import('Vendor', 'simpletest' . DS . 'reporter')) {
366                        $this->err(__('Sorry, Simpletest could not be found. Download it from http://simpletest.org and install it to your vendors directory.', true));
367                        exit;
368                }
369        }
370}
Note: See TracBrowser for help on using the repository browser.