1<?php
2/*
3 * This file is part of PHPUnit.
4 *
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11/**
12 * Base class for all test runners.
13 */
14abstract class PHPUnit_Runner_BaseTestRunner
15{
16    const STATUS_PASSED     = 0;
17    const STATUS_SKIPPED    = 1;
18    const STATUS_INCOMPLETE = 2;
19    const STATUS_FAILURE    = 3;
20    const STATUS_ERROR      = 4;
21    const STATUS_RISKY      = 5;
22    const STATUS_WARNING    = 6;
23    const SUITE_METHODNAME  = 'suite';
24
25    /**
26     * Returns the loader to be used.
27     *
28     * @return PHPUnit_Runner_TestSuiteLoader
29     */
30    public function getLoader()
31    {
32        return new PHPUnit_Runner_StandardTestSuiteLoader;
33    }
34
35    /**
36     * Returns the Test corresponding to the given suite.
37     * This is a template method, subclasses override
38     * the runFailed() and clearStatus() methods.
39     *
40     * @param string $suiteClassName
41     * @param string $suiteClassFile
42     * @param mixed  $suffixes
43     *
44     * @return PHPUnit_Framework_Test
45     */
46    public function getTest($suiteClassName, $suiteClassFile = '', $suffixes = '')
47    {
48        if (is_dir($suiteClassName) &&
49            !is_file($suiteClassName . '.php') && empty($suiteClassFile)) {
50            $facade = new File_Iterator_Facade;
51            $files  = $facade->getFilesAsArray(
52                $suiteClassName,
53                $suffixes
54            );
55
56            $suite = new PHPUnit_Framework_TestSuite($suiteClassName);
57            $suite->addTestFiles($files);
58
59            return $suite;
60        }
61
62        try {
63            $testClass = $this->loadSuiteClass(
64                $suiteClassName,
65                $suiteClassFile
66            );
67        } catch (PHPUnit_Framework_Exception $e) {
68            $this->runFailed($e->getMessage());
69
70            return;
71        }
72
73        try {
74            $suiteMethod = $testClass->getMethod(self::SUITE_METHODNAME);
75
76            if (!$suiteMethod->isStatic()) {
77                $this->runFailed(
78                    'suite() method must be static.'
79                );
80
81                return;
82            }
83
84            try {
85                $test = $suiteMethod->invoke(null, $testClass->getName());
86            } catch (ReflectionException $e) {
87                $this->runFailed(
88                    sprintf(
89                        "Failed to invoke suite() method.\n%s",
90                        $e->getMessage()
91                    )
92                );
93
94                return;
95            }
96        } catch (ReflectionException $e) {
97            try {
98                $test = new PHPUnit_Framework_TestSuite($testClass);
99            } catch (PHPUnit_Framework_Exception $e) {
100                $test = new PHPUnit_Framework_TestSuite;
101                $test->setName($suiteClassName);
102            }
103        }
104
105        $this->clearStatus();
106
107        return $test;
108    }
109
110    /**
111     * Returns the loaded ReflectionClass for a suite name.
112     *
113     * @param string $suiteClassName
114     * @param string $suiteClassFile
115     *
116     * @return ReflectionClass
117     */
118    protected function loadSuiteClass($suiteClassName, $suiteClassFile = '')
119    {
120        $loader = $this->getLoader();
121
122        return $loader->load($suiteClassName, $suiteClassFile);
123    }
124
125    /**
126     * Clears the status message.
127     */
128    protected function clearStatus()
129    {
130    }
131
132    /**
133     * Override to define how to handle a failed loading of
134     * a test suite.
135     *
136     * @param string $message
137     */
138    abstract protected function runFailed($message);
139}
140