Beispiel #1
0
 /**
  *    Scans the now complete ignore list, and adds
  *    all parent classes to the list. If a class
  *    is not a runnable test case, then it's parents
  *    wouldn't be either. This is syntactic sugar
  *    to cut down on ommissions of ignore()'s or
  *    missing abstract declarations. This cannot
  *    be done whilst loading classes wiithout forcing
  *    a particular order on the class declarations and
  *    the ignore() calls. It's just nice to have the ignore()
  *    calls at the top of the file before the actual declarations.
  *    @param array $classes     Class names of interest.
  *    @static
  *    @access public
  */
 function ignoreParentsIfIgnored($classes) {
     $registry = &SimpleTest::_getRegistry();
     foreach ($classes as $class) {
         if (SimpleTest::isIgnored($class)) {
             $reflection = new SimpleReflection($class);
             if ($parent = $reflection->getParent()) {
                 SimpleTest::ignore($parent);
             }
         }
     }
 }
Beispiel #2
0
 /**
  *    Scans the now complete ignore list, and adds
  *    all parent classes to the list. If a class
  *    is not a runnable test case, then it's parents
  *    wouldn't be either. This is syntactic sugar
  *    to cut down on ommissions of ignore()'s or
  *    missing abstract declarations. This cannot
  *    be done whilst loading classes wiithout forcing
  *    a particular order on the class declarations and
  *    the ignore() calls. It's just nice to have the ignore()
  *    calls at the top of the file before the actual declarations.
  *    @param array $classes     Class names of interest.
  */
 public static function ignoreParentsIfIgnored($classes)
 {
     foreach ($classes as $class) {
         if (SimpleTest::isIgnored($class)) {
             $reflection = new SimpleReflection($class);
             $parent = $reflection->getParent();
             if ($parent) {
                 SimpleTest::ignore($parent);
             }
         }
     }
 }
 public static function call_simpletest(pakeTask $task, $type = 'text', $dirs = array())
 {
     if (!class_exists('TestSuite')) {
         throw new pakeException('You must install SimpleTest to use this task.');
     }
     SimpleTest::ignore('UnitTestCase');
     $base_test_dir = 'test';
     $test_dirs = array();
     // run tests only in these subdirectories
     if ($dirs) {
         foreach ($dirs as $dir) {
             $test_dirs[] = $base_test_dir . DIRECTORY_SEPARATOR . $dir;
         }
     } else {
         $test_dirs[] = $base_test_dir;
     }
     $files = pakeFinder::type('file')->name('*Test.php')->in($test_dirs);
     if (count($files) == 0) {
         throw new pakeException('No test to run.');
     }
     $test = new TestSuite('Test suite in (' . implode(', ', $test_dirs) . ')');
     foreach ($files as $file) {
         $test->addFile($file);
     }
     ob_start();
     if ($type == 'html') {
         $result = $test->run(new HtmlReporter());
     } else {
         if ($type == 'xml') {
             $result = $test->run(new XmlReporter());
         } else {
             $result = $test->run(new TextReporter());
         }
     }
     $content = ob_get_contents();
     ob_end_clean();
     if ($task->is_verbose()) {
         echo $content;
     }
 }
Beispiel #4
0
 /**
  *    Calculates the incoming test cases from a before
  *    and after list of loaded classes. Skips abstract
  *    classes.
  *    @param array $existing_classes   Classes before require().
  *    @param array $new_classes        Classes after require().
  *    @return array                    New classes which are test
  *                                     cases that shouldn't be ignored.
  *    @access private
  */
 function _selectRunnableTests($existing_classes, $new_classes)
 {
     $classes = array();
     foreach ($new_classes as $class) {
         if (in_array($class, $existing_classes)) {
             continue;
         }
         if ($this->_getBaseTestCase($class)) {
             $reflection = new SimpleReflection($class);
             if ($reflection->isAbstract()) {
                 SimpleTest::ignore($class);
             }
             $classes[] = $class;
         }
     }
     return $classes;
 }
/**
 * CakeWebTestCase a simple wrapper around WebTestCase
 *
 * PHP versions 4 and 5
 *
 * CakePHP(tm) Tests <http://book.cakephp.org/view/1196/Testing>
 * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
 *
 *  Licensed under The Open Group Test Suite License
 *  Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
 * @link          http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
 * @package       cake
 * @subpackage    cake.cake.tests.lib
 * @since         CakePHP(tm) v 1.2.0.4433
 * @license       http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
 */
/**
 * Ignore base class.
 */
SimpleTest::ignore('CakeWebTestCase');
/**
 * Simple wrapper for the WebTestCase provided by SimpleTest
 *
 * @package       cake
 * @subpackage    cake.cake.tests.lib
 */
class CakeWebTestCase extends WebTestCase
{
}
<?php

require_once dirname(__FILE__) . '/../autorun.php';
SimpleTest::ignore('HTML5_TokenizerHarness');
abstract class HTML5_TokenizerHarness extends HTML5_JSONHarness
{
    public function invoke($test)
    {
        //echo get_class($this) . ': ' . $test->description ."\n";
        if (!isset($test->contentModelFlags)) {
            $test->contentModelFlags = array('PCDATA');
        }
        if (!isset($test->ignoreErrorOrder)) {
            $test->ignoreErrorOrder = false;
        }
        // Get expected result array (and maybe error count).
        $expect = array();
        $expectedErrorCount = 0;
        // This is only used when ignoreErrorOrder = true.
        foreach ($test->output as $tok) {
            // If we're ignoring error order and this is a parse error, just count.
            if ($test->ignoreErrorOrder && $tok === 'ParseError') {
                $expectedErrorCount++;
            } else {
                // Normalize character tokens from the test
                if ($expect && $tok[0] === 'Character' && $expect[count($expect) - 1][0] === 'Character') {
                    $expect[count($expect) - 1][1] .= $tok[1];
                } else {
                    $expect[] = $tok;
                }
            }
Beispiel #7
0
<?php

/**
 * Implementation specifically for JSON format files.
 */
SimpleTest::ignore('HTML5_JSONHarness');
abstract class HTML5_JSONHarness extends HTML5_DataHarness
{
    protected $data;
    public function __construct()
    {
        parent::__construct();
        $this->data = json_decode(file_get_contents($this->filename));
    }
    public function getDescription($test)
    {
        return $test->description;
    }
    public function getDataTests()
    {
        return isset($this->data->tests) ? $this->data->tests : array();
        // could be a weird xmlViolationsTest
    }
}
<?php

// $Id$
require_once dirname(__FILE__) . '/../autorun.php';
require_once dirname(__FILE__) . '/../xml.php';
Mock::generate('SimpleScorer');
if (!function_exists('xml_parser_create')) {
    SimpleTest::ignore('TestOfXmlStructureParsing');
    SimpleTest::ignore('TestOfXmlResultsParsing');
}
class TestOfNestingTags extends UnitTestCase
{
    function testGroupSize()
    {
        $nesting = new NestingGroupTag(array('SIZE' => 2));
        $this->assertEqual($nesting->getSize(), 2);
    }
}
class TestOfXmlStructureParsing extends UnitTestCase
{
    function testValidXml()
    {
        $listener = new MockSimpleScorer();
        $listener->expectNever('paintGroupStart');
        $listener->expectNever('paintGroupEnd');
        $listener->expectNever('paintCaseStart');
        $listener->expectNever('paintCaseEnd');
        $parser = new SimpleTestXmlParser($listener);
        $this->assertTrue($parser->parse("<?xml version=\"1.0\"?>\n"));
        $this->assertTrue($parser->parse("<run>\n"));
        $this->assertTrue($parser->parse("</run>\n"));
Beispiel #9
0
<?php

// $Id$
require_once dirname(__FILE__) . '/../autorun.php';
require_once dirname(__FILE__) . '/../simpletest.php';
SimpleTest::ignore('ShouldNeverBeRunEither');
class ShouldNeverBeRun extends UnitTestCase
{
    function testWithNoChanceOfSuccess()
    {
        $this->fail('Should be ignored');
    }
}
class ShouldNeverBeRunEither extends ShouldNeverBeRun
{
}
class TestOfStackTrace extends UnitTestCase
{
    function testCanFindAssertInTrace()
    {
        $trace = new SimpleStackTrace(array('assert'));
        $this->assertEqual($trace->traceMethod(array(array('file' => '/my_test.php', 'line' => 24, 'function' => 'assertSomething'))), ' at [/my_test.php line 24]');
    }
}
class DummyResource
{
}
class TestOfContext extends UnitTestCase
{
    function testCurrentContextIsUnique()
    {
Beispiel #10
0
 * @since         CakePHP v 1.2.0.4487
 * @version       $Revision$
 * @modifiedby    $LastChangedBy$
 * @lastmodified  $Date$
 * @license       http://www.opensource.org/licenses/mit-license.php The MIT License
 */
App::import('Core', 'CakeTestCase');
if (!class_exists('AppController')) {
    require_once LIBS . 'controller' . DS . 'app_controller.php';
} elseif (!defined('APP_CONTROLLER_EXISTS')) {
    define('APP_CONTROLLER_EXISTS', true);
}
Mock::generate('CakeHtmlReporter');
Mock::generate('CakeTestCase', 'CakeDispatcherMockTestCase');
SimpleTest::ignore('SubjectCakeTestCase');
SimpleTest::ignore('CakeDispatcherMockTestCase');
/**
 * SubjectCakeTestCase
 *
 * @package       cake
 * @subpackage    cake.tests.cases.libs
 */
class SubjectCakeTestCase extends CakeTestCase
{
    /**
     * Feed a Mocked Reporter to the subject case
     * prevents its pass/fails from affecting the real test
     *
     * @param string $reporter
     * @access public
     * @return void
Beispiel #11
0
 * This test is ignored as it is used by {@link TestRunnerForLeftOverAndNotEnoughErrors}
 * to verify that it fails as expected.
 *
 * @ignore
 */
class TestOfLeftOverErrors extends UnitTestCase
{
    function testExpectOneErrorGetTwo()
    {
        $this->expectError('Error 1');
        trigger_error('Error 1');
        trigger_error('Error 2');
    }
}
SimpleTest::ignore('TestOfAnythingErrors');
SimpleTest::ignore('TestOfLeftOverAnythingErrors');
/**
 * This test is ignored as it is used by {@link TestRunnerForLeftOverAndNotEnoughErrors}
 * to verify that it fails as expected.
 *
 * @ignore
 */
class TestOfAnythingErrors extends UnitTestCase
{
    function testExpectOneErrorGetTwo()
    {
        $this->expectError(new AnythingExpectation());
        trigger_error('Error 1');
        trigger_error('Error 2');
    }
}
 *
 * @copyright		Copyright 2010, Jeremy Harris
 * @link			http://42pixels.com Jeremy Harris
 * @package			extended_test_case
 * @subpackage		extended_test_case.libs
 * @license			MIT License (http://www.opensource.org/licenses/mit-license.php)
 */
/**
 * Includes
 */
require_once APP . 'config' . DS . 'routes.php';
/**
 * Ensure SimpleTest doesn't think this is a test case and that it starts from
 * scratch
 */
SimpleTest::ignore('ExtendedTestCase');
ClassRegistry::flush();
/**
 * ExtendedTestCase class
 *
 * Extends the functionality of CakeTestCase, namely, `testAction()`
 *
 * @package			extended_test_case
 * @subpackage		extended_test_case.libs
 */
class ExtendedTestCase extends CakeTestCase
{
    /**
     * Whether or not the components have initialized yet
     *
     * @var boolean
     * CakePHP will connect to the test database. (For more information look at
     * DATABASE_CONFIG::__construct() in database.php!)
     *
     * This function is called automatically in startTest() before a test is run,
     * so please remember to call parent::startTest() if you override it in your
     * tests!
     */
    function identifyAsWebtest()
    {
        $this->addHeader('User-Agent: CakePHP/Webtest');
    }
}
/**
 * Ignore base class.
 */
SimpleTest::ignore('CakeWebTestCaseWithFixtures');
/**
 * Implements (copies) 1:1 all the variables and methods that CakeTestCase
 * defines.
 *
 * The reason for this is that by default CakeWebTestCase does not offer any
 * functionality to load fixtures into the database as it is known from
 * CakeTestCase. So we just steal it from there, harhar!
 *
 * TODO: We may just wrap this stuff instead of copying it! --zivi-muh
 */
class CakeWebTestCaseWithDbFunctionality extends CakeWebTestCase
{
    ////////////////////////////////////////////////////////////////////
    // BEGIN OF CODE COPY&PASTING FROM cake/tests/lib/cake_test_case.php
    /**
    }
    function getTests()
    {
        $test_methods = array();
        foreach (array_keys($this->_scenarios) as $num) {
            $test_methods[] = 'test' . $num;
        }
        return $test_methods;
    }
    function __call($name, $arguments)
    {
        if (!preg_match('/^test(\\d+)$/', $name, $matches)) {
            throw new Exception('Called invalid Test Case: ' . $name);
        }
        $scenario_num = intval($matches[1]);
        $this->runScenario($this->_scenarios[$scenario_num]);
    }
    function runScenario($scenario)
    {
        $this->get('http://localdev.mytribehr.com/');
        foreach ($scenario->getSteps() as $step) {
            $this->runStep($this, $step);
        }
    }
    function runStep(&$browser, $step)
    {
        FeatureContext::step($browser, $step);
    }
}
SimpleTest::ignore('FeatureTestCase');
Beispiel #15
0
<?php

// $Id$
require_once dirname(__FILE__) . '/../simpletest.php';
SimpleTest::ignore('ShouldNeverBeRun');
class ShouldNeverBeRun extends UnitTestCase
{
    function testWithNoChanceOfSuccess()
    {
        $this->fail('Should be ignored');
    }
}
<?php

require_once dirname(__FILE__) . '/../autorun.php';
SimpleTest::ignore('HTML5_TreeBuilderHarness');
class HTML5_TreeBuilderHarness extends HTML5_TestDataHarness
{
    public function assertIdentical($expect, $actual, $test = array())
    {
        $input = $test['data'];
        if (isset($test['document-fragment'])) {
            $input .= "\nFragment: " . $test['document-fragment'];
        }
        parent::assertIdentical($expect, $actual, "Identical expectation failed\nInput:\n{$input}\n\nExpected:\n{$expect}\n\nActual:\n{$actual}\n");
    }
    public function invoke($test)
    {
        // this is totally the wrong interface to use, but
        // for now we need testing
        $tokenizer = new HTML5_Tokenizer($test['data']);
        $GLOBALS['TIME'] -= get_microtime();
        if (isset($test['document-fragment'])) {
            $tokenizer->parseFragment($test['document-fragment']);
        } else {
            $tokenizer->parse();
        }
        $GLOBALS['TIME'] += get_microtime();
        $this->assertIdentical($test['document'], HTML5_TestData::strDom($tokenizer->save()), $test);
    }
}
HTML5_TestData::generateTestCases('HTML5_TreeBuilderHarness', 'HTML5_TreeBuilderTestOf', 'tree-construction', '*.dat');
Beispiel #17
0
 *  Redistributions of files must retain the above copyright notice.
 *
 * @filesource
 * @copyright     Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
 * @link          https://trac.cakephp.org/wiki/Developement/TestSuite CakePHP(tm) Tests
 * @package       cake
 * @subpackage    cake.tests.cases.libs.model
 * @since         CakePHP(tm) v 1.2.0.4206
 * @version       $Revision$
 * @modifiedby    $LastChangedBy$
 * @lastmodified  $Date$
 * @license       http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
 */
App::import('Core', array('AppModel', 'Model'));
require_once dirname(__FILE__) . DS . 'models.php';
SimpleTest::ignore('BaseModelTest');
/**
 * BaseModelTest
 *
 * @package       cake
 * @subpackage    cake.tests.cases.libs.model
 */
class BaseModelTest extends CakeTestCase
{
    /**
     * autoFixtures property
     *
     * @var bool false
     * @access public
     */
    var $autoFixtures = false;
Beispiel #18
0
 * @subpackage media.tests.cases.models.behaviors
 * @copyright  2007-2010 David Persson <*****@*****.**>
 * @license    http://www.opensource.org/licenses/mit-license.php The MIT License
 * @link       http://github.com/davidpersson/media
 */
App::Import('Model', 'App');
require_once CORE_TEST_CASES . DS . 'libs' . DS . 'model' . DS . 'models.php';
require_once dirname(dirname(__FILE__)) . DS . 'models.php';
require_once dirname(dirname(dirname(dirname(__FILE__)))) . DS . 'fixtures' . DS . 'test_data.php';
if (!defined('MEDIA')) {
    define('MEDIA', TMP . 'tests' . DS);
} elseif (MEDIA != TMP . 'tests' . DS) {
    trigger_error('MEDIA constant already defined and not pointing to tests directory.', E_USER_ERROR);
}
require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . DS . 'config' . DS . 'core.php';
SimpleTest::ignore('BaseBehaviorTestCase');
/**
 * Base Behavior Test Case Class
 *
 * @package    media
 * @subpackage media.tests.cases.models.behaviors
 */
class BaseBehaviorTestCase extends CakeTestCase
{
    var $fixtures = array('plugin.media.song', 'core.image');
    var $_behaviorSettings = array();
    function start()
    {
        parent::start();
        if (in_array('plugin.media.song', $this->fixtures)) {
            $this->loadFixtures('Song');
Beispiel #19
0
            }
        }
        print "<strong class=\"case\">{$test_name}</strong> <small>{$caseType}</small><br/><blockquote>\n";
    }
    function paintCaseEnd($test_name)
    {
        parent::paintCaseEnd($test_name);
        print "</blockquote>\n";
    }
    function paintMethodStart($test_name)
    {
        parent::paintMethodStart($test_name);
        print "<small>{$test_name}</small><br/>\n";
    }
    function paintFail($message)
    {
        // We need to bypass parent::paintFail to increment failures without printing its message.
        SimpleReporter::paintFail($message);
        print "<blockquote><strong><span class=\"fail\">Fail</span>: {$message}</strong></blockquote>\n";
    }
    function getCss()
    {
        return parent::getCss() . ' blockquote {margin: 0 0 0 2em;}';
    }
}
//SimpleTest::prefer(new ShowPasses());
// This is necessary because the core WebTestCase class is not abstract.
SimpleTest::ignore('WebTestCase');
require_once 'http.php';
require_once 'model.php';
require_once 'registry.php';
Beispiel #20
0
 * Add proxy class paths
 */
App::build(array('components' => array(TESTS . 'proxies' . DS . 'components' . DS), 'controllers' => array(TESTS . 'proxies' . DS . 'controllers' . DS), 'helpers' => array(TESTS . 'proxies' . DS . 'helpers' . DS)));
/**
 * Includes
 */
App::import('Component', 'Acl');
require_once APP . 'config' . DS . 'routes.php';
/**
 * Mocks
 */
Mock::generatePartial('AclComponent', 'MockAclComponent', array('check'));
/**
 * Ensure SimpleTest doesn't think this is a test case
 */
SimpleTest::ignore('CoreTestCase');
ClassRegistry::flush();
/**
 * CoreTestCase class
 *
 * Extends the functionality of CakeTestCase
 *
 * @package       core
 * @subpackage    core.lib
 */
class CoreTestCase extends CakeTestCase
{
    /**
     * Fixtures needed for test. Overwrite if you don't need them all.
     *
     * @var array
Beispiel #21
0
 /**
  *    Calculates the incoming test cases. Skips abstract
  *    and ignored classes.
  *    @param array $candidates   Candidate classes.
  *    @return array              New classes which are test
  *                               cases that shouldn't be ignored.
  *    @access public
  */
 function selectRunnableTests($candidates) {
     $classes = array();
     foreach ($candidates as $class) {
         if (TestSuite::getBaseTestCase($class)) {
             $reflection = new SimpleReflection($class);
             if ($reflection->isAbstract()) {
                 SimpleTest::ignore($class);
             } else {
                 $classes[] = $class;
             }
         }
     }
     return $classes;
 }
Beispiel #22
0
<?php

/**
 * Modified test-case supertype for running tests that are not
 * test method based, but based off of test data that resides in
 * files.
 */
SimpleTest::ignore('HTML5_DataHarness');
abstract class HTML5_DataHarness extends UnitTestCase
{
    /**
     * Filled in by HTML5_TestData::generateTestCases()
     */
    protected $filename;
    private $tests;
    /**
     * Invoked by the runner, it is the function responsible for executing
     * the test and delivering results.
     * @param $test Some easily usable representation of the test
     */
    public abstract function invoke($test);
    /**
     * Returns a list of tests that can be executed. The list members will
     * be passed to invoke(). Return an iterator if you don't want to load
     * all test into memory
     */
    public abstract function getDataTests();
    /**
     * Returns a description of the test
     */
    public abstract function getDescription($test);
Beispiel #23
0
<?php

// $Id: live_test.php 1505 2007-04-30 23:39:59Z lastcraft $
require_once dirname(__FILE__) . '/../autorun.php';
require_once dirname(__FILE__) . '/../socket.php';
require_once dirname(__FILE__) . '/../http.php';
require_once dirname(__FILE__) . '/../compatibility.php';
if (SimpleTest::getDefaultProxy()) {
    SimpleTest::ignore('LiveHttpTestCase');
}
class LiveHttpTestCase extends UnitTestCase
{
    function testBadSocket()
    {
        $socket =& new SimpleSocket('bad_url', 111, 5);
        $this->assertTrue($socket->isError());
        $this->assertPattern('/Cannot open \\[bad_url:111\\] with \\[/', $socket->getError());
        $this->assertFalse($socket->isOpen());
        $this->assertFalse($socket->write('A message'));
    }
    function testSocketClosure()
    {
        $socket =& new SimpleSocket('www.lastcraft.com', 80, 15, 8);
        $this->assertTrue($socket->isOpen());
        $this->assertTrue($socket->write("GET /test/network_confirm.php HTTP/1.0\r\n"));
        $socket->write("Host: www.lastcraft.com\r\n");
        $socket->write("Connection: close\r\n\r\n");
        $this->assertEqual($socket->read(), "HTTP/1.1");
        $socket->close();
        $this->assertIdentical($socket->read(), false);
    }
<?php

// $Id: collector_test.php 1505 2007-04-30 23:39:59Z lastcraft $
require_once dirname(__FILE__) . '/../autorun.php';
require_once dirname(__FILE__) . '/../collector.php';
SimpleTest::ignore('MockTestSuite');
Mock::generate('TestSuite');
class PathEqualExpectation extends EqualExpectation
{
    function PathEqualExpectation($value, $message = '%s')
    {
        $this->EqualExpectation(str_replace("\\", '/', $value), $message);
    }
    function test($compare)
    {
        return parent::test(str_replace("\\", '/', $compare));
    }
}
class TestOfCollector extends UnitTestCase
{
    function testCollectionIsAddedToGroup()
    {
        $suite =& new MockTestSuite();
        $suite->expectMinimumCallCount('addTestFile', 2);
        $suite->expectArguments('addTestFile', array(new PatternExpectation('/collectable\\.(1|2)$/')));
        $collector =& new SimpleCollector();
        $collector->collect($suite, dirname(__FILE__) . '/support/collector/');
    }
}
class TestOfPatternCollector extends UnitTestCase
{
Beispiel #25
0
/**
 * This test is ignored as it is used by {@link TestRunnerForLeftOverAndNotEnoughErrors}
 * to verify that it fails as expected.
 *
 * @ignore
 */
class TestOfNotEnoughErrors extends UnitTestCase
{
    function testExpectTwoErrorsThrowOne()
    {
        $this->expectError('Error 1');
        trigger_error('Error 1');
        $this->expectError('Error 2');
    }
}
SimpleTest::ignore('TestOfLeftOverErrors');
/**
 * This test is ignored as it is used by {@link TestRunnerForLeftOverAndNotEnoughErrors}
 * to verify that it fails as expected.
 *
 * @ignore
 */
class TestOfLeftOverErrors extends UnitTestCase
{
    function testExpectOneErrorGetTwo()
    {
        $this->expectError('Error 1');
        trigger_error('Error 1');
        trigger_error('Error 2');
    }
}
Beispiel #26
0
 /**
  *    Calculates the incoming test cases. Skips abstract
  *    and ignored classes.
  *    @param array $candidates   Candidate classes.
  *    @return array              New classes which are test
  *                               cases that shouldn't be ignored.
  *    @access public
  */
 function selectRunnableTests($candidates)
 {
     $classes = array();
     foreach ($candidates as $class) {
         if (TestSuite::getBaseTestCase($class)) {
             $reflection = new SimpleReflection($class);
             if ($reflection->isAbstract()) {
                 SimpleTest::ignore($class);
             } else {
                 // only pick classes which do have test methods we can run:
                 $methods = $reflection->getMethods();
                 foreach ($methods as $method) {
                     if (SimpleTestCase::isTest($class, $method)) {
                         $classes[] = $class;
                         break;
                     }
                 }
             }
         }
     }
     return $classes;
 }