comparison cake/console/libs/testsuite.php @ 0:261e66bd5a0c

hg init
author Shoshi TAMAKI <shoshi@cr.ie.u-ryukyu.ac.jp>
date Sun, 24 Jul 2011 21:08:31 +0900
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:261e66bd5a0c
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-2010, 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-2010, 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 */
22 class 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 }