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