5
* This Shell allows the running of test suites via the cake command line
9
* CakePHP(tm) Tests <http://book.cakephp.org/view/1196/Testing>
10
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
12
* Licensed under The Open Group Test Suite License
13
* Redistributions of files must retain the above copyright notice.
15
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
16
* @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
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
22
class TestSuiteShell extends Shell {
25
* The test category, "app", "core" or the name of a plugin
33
* "group", "case" or "all"
41
* Path to the test case/group file
49
* Storage for plugins that have tests
54
var $plugins = array();
57
* Convenience variable to avoid duplicated code
62
var $isPluginTest = false;
65
* Stores if the user wishes to get a code coverage analysis report
70
var $doCoverage = false;
73
* Initialization method installs Simpletest and loads all plugins
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);
83
define('TEST_CAKE_CORE_INCLUDE_PATH', CAKE_CORE_INCLUDE_PATH);
86
$this->__installSimpleTest();
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';
91
$plugins = App::objects('plugin');
92
foreach ($plugins as $p) {
93
$this->plugins[] = Inflector::underscore($p);
100
* Parse the arguments given into the Shell object properties.
105
function parseArgs() {
106
if (empty($this->args)) {
109
$this->category = $this->args[0];
111
if (!in_array($this->category, array('app', 'core'))) {
112
$this->isPluginTest = true;
115
if (isset($this->args[1])) {
116
$this->type = $this->args[1];
119
if (isset($this->args[2])) {
120
if ($this->args[2] == 'cov') {
121
$this->doCoverage = true;
123
$this->file = Inflector::underscore($this->args[2]);
127
if (isset($this->args[3]) && $this->args[3] == 'cov') {
128
$this->doCoverage = true;
133
* Gets a manager instance, and set the app/plugin properties.
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;
146
* Main entry point to this shell
152
$this->out(__('CakePHP Test Shell', true));
155
if (count($this->args) == 0) {
156
$this->error(__('Sorry, you did not pass any arguments!', true));
159
if ($this->__canRun()) {
160
$message = sprintf(__('Running %s %s %s', true), $this->category, $this->type, $this->file);
161
$this->out($message);
164
if (!$this->__run()) {
167
$this->_stop($exitCode);
169
$this->error(__('Sorry, the tests could not be found.', true));
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");
186
$this->out('Examples: ');
187
$this->out("\t\tcake testsuite app all");
188
$this->out("\t\tcake testsuite core all");
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");
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");
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");
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'");
207
$this->out('Code Coverage Analysis: ');
208
$this->out("\n\nAppend 'cov' to any of the above in order to enable code coverage analysis");
212
* Checks if the arguments supplied point to a valid test file and thus the shell can be run.
214
* @return bool true if it's a valid test file, false otherwise
217
function __canRun() {
218
$isNeitherAppNorCore = !in_array($this->category, array('app', 'core'));
219
$isPlugin = in_array(Inflector::underscore($this->category), $this->plugins);
221
if ($isNeitherAppNorCore && !$isPlugin) {
223
__('%s is an invalid test category (either "app", "core" or name of a plugin)', true),
226
$this->error($message);
230
$folder = $this->__findFolderByCategory($this->category);
231
if (!file_exists($folder)) {
232
$this->err(sprintf(__('%s not found', true), $folder));
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));
241
$fileName = $this->__getFileName($folder, $this->isPluginTest);
242
if ($fileName === true || file_exists($folder . $fileName)) {
247
__('%s %s %s is an invalid test identifier', true),
248
$this->category, $this->type, $this->file
250
$this->err($message);
254
* Executes the tests depending on our settings
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
267
if ($this->type == 'all') {
268
return $this->Manager->runAllTests($Reporter);
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));
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();
285
$result = $this->Manager->runGroupTest($ucFirstGroup, $Reporter);
289
$folder = $folder = $this->__findFolderByCategory($this->category);
290
$case = $this->__getFileName($folder, $this->isPluginTest);
292
if ($this->doCoverage) {
293
require_once CAKE . 'tests' . DS . 'lib' . DS . 'code_coverage_manager.php';
294
CodeCoverageManager::init($case, $Reporter);
295
CodeCoverageManager::start();
297
$result = $this->Manager->runTestCase($case, $Reporter);
302
* Gets the concrete filename for the inputted test name and category/type
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'
309
function __getFileName($folder, $isPlugin) {
310
$ext = $this->Manager->getExtension($this->type);
311
switch ($this->type) {
315
return $this->file . $ext;
317
if ($this->category == 'app' || $isPlugin) {
318
return $this->file . $ext;
320
$coreCase = $this->file . $ext;
321
$coreLibCase = 'libs' . DS . $this->file . $ext;
323
if ($this->category == 'core' && file_exists($folder . DS . $coreCase)) {
325
} elseif ($this->category == 'core' && file_exists($folder . DS . $coreLibCase)) {
333
* Finds the correct folder to look for tests for based on the input category and type.
335
* @param string $category The category of the test. Either 'app', 'core' or a plugin name.
336
* @return string the folder path
339
function __findFolderByCategory($category) {
345
$typeDir = $this->type === 'group' ? 'groups' : 'cases';
347
if (array_key_exists($category, $paths)) {
348
$folder = $paths[$category] . 'tests' . DS . $typeDir . DS;
350
$pluginPath = App::pluginPath($category);
351
if (is_dir($pluginPath . 'tests')) {
352
$folder = $pluginPath . 'tests' . DS . $typeDir . DS;
359
* tries to install simpletest and exits gracefully if it is not there
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));