├── .gitignore
├── .travis.install.sh
├── .travis.yml
├── README.md
├── composer.json
├── phpunit-integration.xml.dist
├── phpunit-unit.xml.dist
├── src
└── PHPUnit
│ └── Runner
│ └── CleverAndSmart
│ ├── Exception
│ ├── PropertyReflectionException.php
│ ├── RuntimeException.php
│ └── StorageException.php
│ ├── PriorityQueue.php
│ ├── PrioritySorter.php
│ ├── Run.php
│ ├── SegmentedQueue.php
│ ├── Storage
│ ├── MockedStorage.php
│ ├── Sqlite3Storage.php
│ └── StorageInterface.php
│ ├── TestListener.php
│ └── Util.php
└── tests
└── PHPUnit
└── Tests
└── Runner
└── CleverAndSmart
├── Benchmark
├── RunSuiteEvent.php
└── bootstrap.php
├── Integration
├── fixture
│ ├── DependentTest.php
│ ├── FatalErrorTest.php
│ ├── Nested
│ │ ├── DataTest.php
│ │ └── NestedTest.php
│ ├── SimpleTest.php
│ └── SkipTest.php
├── phpunit-error-failure.xml
├── phpunit-error.xml
├── phpunit-failure.xml
├── phpunit-fatal.xml
├── phpunit-skip.xml
├── phpunit-success.xml
└── tests
│ └── IntegrationTest.php
└── Unit
├── PrioritySorterTest.php
├── SegmentedQueueTest.php
├── Storage
└── Sqlite3StorageTest.php
└── UtilTest.php
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 | /tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/result-*.xml
3 | /tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/.phpunit-cas.db
4 | /.phpunit-cas.db
5 | /composer.lock
6 |
--------------------------------------------------------------------------------
/.travis.install.sh:
--------------------------------------------------------------------------------
1 | set -x
2 | if [ "$TRAVIS_PHP_VERSION" = 'hhvm' ]; then
3 | export DEBIAN_FRONTEND=noninteractive
4 | sudo apt-get purge -q -y hhvm
5 | sudo add-apt-repository -y ppa:mapnik/boost
6 | sudo apt-get update -q -y
7 | sudo apt-get install -q -y hhvm-nightly
8 | hhvm --version
9 |
10 | curl -sS https://getcomposer.org/installer > composer-installer.php
11 | hhvm composer-installer.php
12 | hhvm -v ResourceLimit.SocketDefaultTimeout=30 -v Http.SlowQueryThreshold=30000 composer.phar require phpunit/phpunit=$PHPUNIT_VERSION
13 | hhvm -v ResourceLimit.SocketDefaultTimeout=30 -v Http.SlowQueryThreshold=30000 composer.phar install
14 | else
15 | composer require phpunit/phpunit=$PHPUNIT_VERSION
16 | composer install
17 | fi
18 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | sudo: false
4 |
5 | php:
6 | - 5.3
7 | - 5.4
8 | - 5.5
9 | - 5.6
10 | - hhvm
11 |
12 | env:
13 | - PHPUNIT_VERSION="3.7.*"
14 | - PHPUNIT_VERSION="3.8.*"
15 | - PHPUNIT_VERSION="4.0.*"
16 | - PHPUNIT_VERSION="4.1.*"
17 | - PHPUNIT_VERSION="4.2.*"
18 | - PHPUNIT_VERSION="4.3.*"
19 | - PHPUNIT_VERSION="4.4.*"
20 | - PHPUNIT_VERSION="4.5.*"
21 | - PHPUNIT_VERSION="dev-master"
22 |
23 | matrix:
24 | allow_failures:
25 | - php: hhvm
26 |
27 | before_script:
28 | - ./.travis.install.sh
29 |
30 | script:
31 | - vendor/bin/phpunit --configuration phpunit-unit.xml.dist
32 | - vendor/bin/phpunit --configuration phpunit-integration.xml.dist
33 | - vendor/bin/athletic --path tests/PHPUnit/Tests/Runner/CleverAndSmart/Benchmark --bootstrap tests/PHPUnit/Tests/Runner/CleverAndSmart/Benchmark/bootstrap.php --formatter GroupedFormatter
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Clever Test Runner for PHPUnit
2 | [](http://travis-ci.org/lstrojny/phpunit-clever-and-smart) [](https://www.versioneye.com/user/projects/542d5df4fc3f5cd7000001fb) [](http://isitmaintained.com/project/lstrojny/phpunit-clever-and-smart "Average time to resolve an issue") [](http://isitmaintained.com/project/lstrojny/phpunit-clever-and-smart "Percentage of issues still open")
3 |
4 | ## Mission
5 | Enable fast feedback cycles by storing test case results in a database and reorder tests on consecutive runs in the
6 | following order:
7 | 1. Failures and errors
8 | 2. So far unrecorded tests
9 | 3. Remaining tests by execution time in ascendant order (fastest first)
10 |
11 | It’s probably not yet very stable but try it out.
12 |
13 | ### What it does
14 |
15 | Run a test suite once with errors
16 |
17 | ```
18 | PHPUnit 3.7.28 by Sebastian Bergmann.
19 |
20 | .............................................FSFS.............. 63 / 280 ( 22%)
21 | ............................................................... 126 / 280 ( 45%)
22 | ............................................................... 189 / 280 ( 67%)
23 | ............................................................... 252 / 280 ( 90%)
24 | .........................
25 | ```
26 |
27 | Rerun that test suite and see how the previous failing tests have been sorted to the beginning of the test run:
28 |
29 |
30 | ```
31 | PHPUnit 3.7.28 by Sebastian Bergmann.
32 |
33 | FSFS........................................................... 63 / 280 ( 22%)
34 | ............................................................... 126 / 280 ( 45%)
35 | ............................................................... 189 / 280 ( 67%)
36 | ............................................................... 252 / 280 ( 90%)
37 | .........................
38 | ```
39 |
40 | ## Installation
41 |
42 | add the following line to your projects' composer.json `require-dev` section.
43 |
44 | ```json
45 | "lstrojny/phpunit-clever-and-smart": "0.*"
46 | ```
47 |
48 | ## Configuration
49 | To play around with it, add this to your `phpunit.xml(.dist)`
50 |
51 | ```xml
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | ```
60 |
61 | you might alter the location of the sqlite storage file, by passing a path to the Sqlite3Storage class:
62 |
63 | ```xml
64 |
65 |
66 |
67 |
72 |
73 |
74 |
75 | ```
76 |
77 | ## Roadmap
78 |
79 | - Test it with as many test suites as possible
80 | - Stabilize
81 | - Merge into PHPUnit core
82 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lstrojny/phpunit-clever-and-smart",
3 | "description": "A clever test runner for PHPUnit",
4 | "license": "MIT",
5 | "minimum-stability": "dev",
6 | "require": {
7 | "phpunit/phpunit": "*",
8 | "ext-sqlite3": "*"
9 | },
10 | "require-dev": {
11 | "symfony/process": "2.*",
12 | "athletic/athletic": "~0.1"
13 | },
14 | "authors": [
15 | {
16 | "name": "Lars Strojny",
17 | "email": "lars@strojny.net"
18 | }
19 | ],
20 | "autoload": {
21 | "psr-0": {
22 | "PHPUnit\\Runner\\CleverAndSmart": "src/"
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/phpunit-integration.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | ./tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/tests/
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/phpunit-unit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | ./tests/PHPUnit/Tests/Runner/CleverAndSmart/Unit
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/PHPUnit/Runner/CleverAndSmart/Exception/PropertyReflectionException.php:
--------------------------------------------------------------------------------
1 | errors = $errors;
22 | $this->timings = $timings;
23 | }
24 |
25 | public function sort(TestSuite $suite)
26 | {
27 | $this->sortTestSuite($suite);
28 | }
29 |
30 | private function sortTestSuite(TestSuite $suite)
31 | {
32 | $tests = $suite->tests();
33 |
34 | $testsOrderResult = array(static::SORT_NONE, null);
35 |
36 | foreach ($tests as $test) {
37 | if ($test instanceof TestCase && Util::getInvisibleProperty($test, 'dependencies', 'hasDependencies')) {
38 | return $testsOrderResult;
39 | }
40 | }
41 |
42 | $orderedTests = new SegmentedQueue($tests);
43 | foreach ($tests as $position => $test) {
44 | list($testOrderResult, $time) = $this->sortTest($test, $position, $orderedTests);
45 | if ($testsOrderResult[0] < $testOrderResult) {
46 | $testsOrderResult = array($testOrderResult, $time);
47 | }
48 | }
49 |
50 | $groups = Util::getInvisibleProperty($suite, 'groups', 'getGroupDetails');
51 | $groupsOrderResult = array(static::SORT_NONE, null);
52 | foreach ($groups as $groupName => $group) {
53 |
54 | $groupOrderResult = array(static::SORT_NONE, null);
55 | $orderedGroup = new SegmentedQueue($group);
56 | foreach ($group as $position => $test) {
57 | list($testOrderResult, $time) = $this->sortTest($test, $position, $orderedGroup);
58 | if ($groupOrderResult[0] < $testOrderResult) {
59 | $groupOrderResult = array($testOrderResult, $time);
60 | }
61 | }
62 |
63 | if ($groupOrderResult[0] > static::SORT_NONE) {
64 | $groups[$groupName] = iterator_to_array($orderedGroup);
65 |
66 | if ($groupsOrderResult[0] < $groupOrderResult[0]) {
67 | $groupsOrderResult = $groupOrderResult;
68 | }
69 | }
70 | }
71 |
72 | if ($testsOrderResult[0] > static::SORT_NONE) {
73 | Util::setInvisibleProperty($suite, 'tests', iterator_to_array($orderedTests), 'setTests');
74 | }
75 |
76 | if ($groupsOrderResult) {
77 | Util::setInvisibleProperty($suite, 'groups', $groups, 'setGroupDetails');
78 | }
79 |
80 | return $testsOrderResult[0] > $groupsOrderResult[0] ? $testsOrderResult : $groupsOrderResult;
81 | }
82 |
83 | private function sortTest($test, $position, SegmentedQueue $orderedTests)
84 | {
85 | if ($test instanceof TestSuite) {
86 |
87 | list($result, $time) = $this->sortTestSuite($test);
88 |
89 | if ($result === static::SORT_ERROR) {
90 |
91 | $orderedTests->unknown[$position] = null;
92 | $orderedTests->errors->push($test);
93 |
94 | } elseif ($result === static::SORT_TIMING) {
95 |
96 | $orderedTests->unknown[$position] = null;
97 | $orderedTests->timed->insert($test, $time);
98 |
99 | }
100 |
101 | return array($result, $time);
102 | }
103 |
104 | if ($test instanceof TestCase) {
105 |
106 | if ($this->isError($test)) {
107 |
108 | $orderedTests->unknown[$position] = null;
109 | $orderedTests->errors->push($test);
110 |
111 | return array(static::SORT_ERROR, null);
112 | }
113 |
114 | if ($time = $this->getTime($test)) {
115 |
116 | $orderedTests->unknown[$position] = null;
117 | $orderedTests->timed->insert($test, $time);
118 |
119 | return array(static::SORT_TIMING, $time);
120 | }
121 | }
122 |
123 | return array(static::SORT_NONE, null);
124 | }
125 |
126 | private function getTime(TestCase $test)
127 | {
128 | $name = $test->getName();
129 | $class = get_class($test);
130 |
131 | foreach ($this->timings as $timing) {
132 | if ($timing['class'] === $class && $timing['test'] === $name) {
133 | return $timing['time'];
134 | }
135 | }
136 | }
137 |
138 | private function isError(TestCase $test)
139 | {
140 | return in_array(array('class' => get_class($test), 'test' => $test->getName()), $this->errors);
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/src/PHPUnit/Runner/CleverAndSmart/Run.php:
--------------------------------------------------------------------------------
1 | runId = $runId ?: Util::createRunId();
17 | $this->ranAt = $ranAt ?: microtime(true);
18 | }
19 |
20 | /**
21 | * @return string
22 | */
23 | public function getRunIdentifier()
24 | {
25 | return $this->runId;
26 | }
27 |
28 | /**
29 | * @return float
30 | */
31 | public function getRanAt()
32 | {
33 | return $this->ranAt;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/PHPUnit/Runner/CleverAndSmart/SegmentedQueue.php:
--------------------------------------------------------------------------------
1 | unknown = new SplQueue();
23 | array_map(array($this->unknown, 'push'), $values);
24 | $this->errors = new SplQueue();
25 | $this->timed = new PriorityQueue();
26 | }
27 |
28 | public function getIterator()
29 | {
30 | return new ArrayIterator(
31 | array_values(
32 | array_filter(
33 | array_merge(
34 | iterator_to_array($this->errors),
35 | iterator_to_array($this->unknown),
36 | iterator_to_array($this->timed)
37 | )
38 | )
39 | )
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/PHPUnit/Runner/CleverAndSmart/Storage/MockedStorage.php:
--------------------------------------------------------------------------------
1 | db = new SQLite3($fileName);
25 |
26 | // method introduced in php 5.3.3
27 | if (method_exists($this->db, 'busyTimeout')) {
28 | $this->db->busyTimeout(1000 * 30);
29 | }
30 |
31 | // PRAGMA need to be set outside a transaction
32 | $this->query('PRAGMA foreign_keys = ON');
33 | $this->query('PRAGMA page_size = 4096');
34 | $this->query('PRAGMA cache_size = 10000');
35 | $this->query('PRAGMA synchronous = OFF');
36 | $this->query('PRAGMA journal_mode = MEMORY');
37 |
38 | $this->transactional(array($this, 'initDatabaseSchema'));
39 | }
40 |
41 | public function initDatabaseSchema()
42 | {
43 | $this->query(
44 | 'CREATE TABLE IF NOT EXISTS {{prefix}}run (
45 | run_id INTEGER PRIMARY KEY AUTOINCREMENT,
46 | run_identifier CHAR(128),
47 | run_ran_at DOUBLE
48 | )'
49 | );
50 | $this->query(
51 | 'CREATE UNIQUE INDEX IF NOT EXISTS
52 | u_{{prefix}}run_identifier_idx ON {{prefix}}run(run_identifier)'
53 | );
54 | $this->query(
55 | 'CREATE TABLE IF NOT EXISTS {{prefix}}result (
56 | result_id INTEGER PRIMARY KEY AUTOINCREMENT,
57 | run_id INTEGER,
58 | result_class VARCHAR(1024),
59 | result_test VARCHAR(1024),
60 | result_identifier CHAR(128),
61 | result_state TINYINT,
62 | result_time DOUBLE,
63 | FOREIGN KEY (run_id) REFERENCES {{prefix}}run(run_id) ON DELETE CASCADE
64 | )'
65 | );
66 | $this->query(
67 | 'CREATE INDEX IF NOT EXISTS
68 | {{prefix}}result_idx ON {{prefix}}result(result_state, result_identifier)'
69 | );
70 | }
71 |
72 | public function record(Run $run, TestCase $test, $time, $status)
73 | {
74 | $this->transactional(array($this, 'doRecord'), $run, $test, $time, $status);
75 | }
76 |
77 | public function doRecord(Run $run, TestCase $test, $time, $status)
78 | {
79 | $this->insertResult($this->storeRun($run), $test, $time, $status);
80 | }
81 |
82 | public function getRecordings(array $types, $includeTime = true)
83 | {
84 | $query = 'FROM {{prefix}}result
85 | WHERE result_state IN (%s)
86 | GROUP BY result_identifier
87 | ORDER BY COUNT(*) DESC';
88 |
89 | if ($includeTime) {
90 | $query = 'SELECT result_class AS class, result_test AS test, AVG(result_time) AS time ' . $query;
91 | } else {
92 | $query = 'SELECT result_class AS class, result_test AS test ' . $query;
93 | }
94 |
95 | return $this->select($query, array($types));
96 | }
97 |
98 | private function transactional($callable /*, ... $args */)
99 | {
100 | $this->query('BEGIN');
101 |
102 | $args = func_get_args();
103 | array_shift($args);
104 |
105 | try {
106 | $result = call_user_func_array($callable, $args);
107 | } catch (Exception $e) {
108 | $this->query('ROLLBACK');
109 | throw $e;
110 | }
111 |
112 | $this->query('COMMIT');
113 |
114 | return $result;
115 | }
116 |
117 | private function insertResult($runId, TestCase $test, $time, $status)
118 | {
119 | $className = get_class($test);
120 | $testName = $test->getName();
121 | $identifier = hash('sha512', $className . $testName);
122 |
123 | $this->query(
124 | "INSERT INTO {{prefix}}result
125 | (run_id, result_class, result_test, result_identifier, result_state, result_time)
126 | VALUES
127 | (%d, '%s', '%s', '%s', %d, %F)",
128 | array($runId, $className, $testName, $identifier, $status, $time)
129 | );
130 |
131 | if ($status < static::STATUS_FAILURE) {
132 | $this->query(
133 | "DELETE FROM {{prefix}}result
134 | WHERE result_identifier = '%s'
135 | AND (SELECT COUNT(*) FROM {{prefix}}result WHERE result_identifier = '%s' AND result_state < %d) >= 4",
136 | array($identifier, $identifier, StorageInterface::STATUS_FAILURE)
137 | );
138 | }
139 | }
140 |
141 | private function storeRun(Run $run)
142 | {
143 | $this->query(
144 | "INSERT OR IGNORE INTO {{prefix}}run (run_identifier, run_ran_at) VALUES ('%s', '%s')",
145 | array($run->getRunIdentifier(), $run->getRanAt())
146 | );
147 |
148 | return $this->selectOne(
149 | "SELECT run_id FROM {{prefix}}run WHERE run_identifier = '%s'",
150 | array($run->getRunIdentifier())
151 | );
152 | }
153 |
154 | public function query($query, array $params = array())
155 | {
156 | $query = $this->prepareQuery($query, $params);
157 |
158 | return $this->doQuery($query);
159 | }
160 |
161 | private function select($query, array $params = array())
162 | {
163 | $result = $this->query($query, $params);
164 |
165 | $rows = array();
166 | while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
167 | $rows[] = $row;
168 | }
169 |
170 | return $rows;
171 | }
172 |
173 | private function selectOne($query, array $params)
174 | {
175 | $rows = $this->select($query, $params);
176 |
177 | if ($rows) {
178 | return current(current($rows));
179 | }
180 | }
181 |
182 | private function doQuery($query)
183 | {
184 | $result = $this->db->query($query);
185 |
186 | if ($this->db->lastErrorCode() > 0) {
187 | throw StorageException::databaseError($this->db->lastErrorMsg(), $this->db->lastErrorCode());
188 | }
189 |
190 | return $result;
191 | }
192 |
193 | private function prepareQuery($query, array $params)
194 | {
195 | $query = str_replace('{{prefix}}', $this->getPrefix(), $query);
196 |
197 | $escapedParams = array();
198 | foreach ($params as $param) {
199 | if (is_string($param) || is_object($param)) {
200 | $escapedParams[] = $this->db->escapeString($param);
201 | } elseif (is_array($param)) {
202 | $escapedParams[] = "'" . join("', '", array_map(array($this->db, 'escapeString'), $param)) . "'";
203 | } else {
204 | $escapedParams[] = $param;
205 | }
206 | }
207 |
208 | return vsprintf($query, $escapedParams);
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/src/PHPUnit/Runner/CleverAndSmart/Storage/StorageInterface.php:
--------------------------------------------------------------------------------
1 | storage = $storage;
32 | $this->run = new Run();
33 | }
34 |
35 | public function addError(Test $test, Exception $e, $time)
36 | {
37 | $this->storage->record($this->run, $test, $time, StorageInterface::STATUS_ERROR);
38 | }
39 |
40 | public function addFailure(Test $test, AssertionFailedError $e, $time)
41 | {
42 | $this->storage->record($this->run, $test, $time, StorageInterface::STATUS_ERROR);
43 | }
44 |
45 | public function addRiskyTest(Test $test, Exception $e, $time)
46 | {
47 | }
48 |
49 | public function startTestSuite(TestSuite $suite)
50 | {
51 | if ($this->reordered) {
52 | return;
53 | }
54 | $this->reordered = true;
55 |
56 | $this->sort($suite);
57 |
58 | register_shutdown_function(array($this, 'onFatalError'));
59 | if (function_exists('pcntl_signal')) {
60 | pcntl_signal(SIGINT, array($this, 'onCancel'));
61 | }
62 | }
63 |
64 | private function sort(TestSuite $suite)
65 | {
66 | $sorter = new PrioritySorter(
67 | $this->storage->getRecordings(
68 | array(
69 | StorageInterface::STATUS_ERROR,
70 | StorageInterface::STATUS_FAILURE,
71 | StorageInterface::STATUS_CANCEL,
72 | StorageInterface::STATUS_FATAL_ERROR,
73 | StorageInterface::STATUS_SKIPPED,
74 | StorageInterface::STATUS_INCOMPLETE,
75 | ),
76 | false
77 | ),
78 | $this->storage->getRecordings(
79 | array(
80 | StorageInterface::STATUS_PASSED,
81 | )
82 | )
83 | );
84 | $sorter->sort($suite);
85 | }
86 |
87 | public function startTest(Test $test)
88 | {
89 | $this->currentTest = $test;
90 | }
91 |
92 | public function endTest(Test $test, $time)
93 | {
94 | $this->currentTest = null;
95 | if ($test instanceof TestCase && $test->getStatus() === TestRunner::STATUS_PASSED) {
96 | $this->storage->record($this->run, $test, $time, StorageInterface::STATUS_PASSED);
97 | }
98 | }
99 |
100 | public function addIncompleteTest(Test $test, Exception $e, $time)
101 | {
102 | $this->storage->record($this->run, $test, $time, StorageInterface::STATUS_INCOMPLETE);
103 | }
104 |
105 | public function addSkippedTest(Test $test, Exception $e, $time)
106 | {
107 | $this->storage->record($this->run, $test, $time, StorageInterface::STATUS_SKIPPED);
108 | }
109 |
110 | public function endTestSuite(TestSuite $suite)
111 | {
112 | }
113 |
114 | public function onFatalError()
115 | {
116 | $error = error_get_last();
117 | if (!$error || $error['type'] !== E_ERROR || !$this->currentTest) {
118 | return;
119 | }
120 |
121 | $this->storage->record($this->run, $this->currentTest, 0, StorageInterface::STATUS_FATAL_ERROR);
122 | }
123 |
124 | public function onCancel()
125 | {
126 | if (!$this->currentTest) {
127 | return;
128 | }
129 |
130 | $this->storage->record($this->run, $this->currentTest, 0, StorageInterface::STATUS_CANCEL);
131 |
132 | exit(1);
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/src/PHPUnit/Runner/CleverAndSmart/Util.php:
--------------------------------------------------------------------------------
1 | {$methodName}();
39 | }
40 |
41 | return static::getPropertyReflection($object, $propertyName)->getValue($object);
42 | }
43 |
44 | /**
45 | * Set an invisible property from an object (private or protected)
46 | *
47 | * @param object $object
48 | * @param string $propertyName
49 | * @param mixed $value
50 | * @param string $methodName
51 | */
52 | public static function setInvisibleProperty($object, $propertyName, $value, $methodName = null)
53 | {
54 | if (method_exists($object, $methodName)) {
55 | $object->{$methodName}($value);
56 | return;
57 | }
58 |
59 | static::getPropertyReflection($object, $propertyName)->setValue($object, $value);
60 | }
61 |
62 | /**
63 | * Get proper PropertyReflection object
64 | *
65 | * @param object $object
66 | * @param string $propertyName
67 | * @throws ReflectionException
68 | * @return ReflectionProperty
69 | */
70 | private static function getPropertyReflection($object, $propertyName)
71 | {
72 | $reflected = new ReflectionObject($object);
73 |
74 | $classHierarchy = array();
75 |
76 | do {
77 | try {
78 |
79 | $property = $reflected->getProperty($propertyName);
80 | $property->setAccessible(true);
81 |
82 | return $property;
83 |
84 | } catch (ReflectionException $e) {
85 |
86 | $classHierarchy[] = $reflected->getName();
87 | $e = PropertyReflectionException::propertyNotExistsInHierarchy($propertyName, $e, $classHierarchy);
88 |
89 | }
90 | } while ($reflected = $reflected->getParentClass());
91 |
92 | throw $e;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Benchmark/RunSuiteEvent.php:
--------------------------------------------------------------------------------
1 | sutRoot . 'phpunit.xml.dist';
18 | // plain config to run the suite as-is
19 | copy($org, $this->plainConfig);
20 |
21 | $this->patchPhpunitConfig($this->sqliteConfig, 'PHPUnit\Runner\CleverAndSmart\Storage\Sqlite3Storage');
22 | $this->patchPhpunitConfig($this->mockedConfig, 'PHPUnit\Runner\CleverAndSmart\Storage\MockedStorage');
23 | }
24 |
25 | private function patchPhpunitConfig($patchedConfigFilename, $storageClass) {
26 | $org = $this->sutRoot . 'phpunit.xml.dist';
27 |
28 | $testlistener = '
29 |
30 |
31 |
32 |
33 |
34 |
35 | ';
36 |
37 | $content = file_get_contents($org);
38 | $content = str_replace('', $testlistener. '', $content);
39 | file_put_contents($patchedConfigFilename, $content);
40 | }
41 |
42 | public function classTearDown()
43 | {
44 | unlink($this->plainConfig);
45 | unlink($this->mockedConfig);
46 | unlink($this->sqliteConfig);
47 | }
48 |
49 | /**
50 | * @baseline
51 | * @iterations 10
52 | */
53 | public function plainSuite()
54 | {
55 | $this->runSuite($this->plainConfig);
56 | }
57 |
58 | /**
59 | * @iterations 10
60 | */
61 | public function instrumentedMockedSuite()
62 | {
63 | $this->runSuite($this->mockedConfig);
64 | }
65 |
66 | /**
67 | * @iterations 10
68 | */
69 | public function instrumentedSqliteSuite()
70 | {
71 | $this->runSuite($this->sqliteConfig);
72 | }
73 |
74 | private function runSuite($config) {
75 | $cmd = 'phpunit --configuration '. $config .' '. $this->sutRoot;
76 |
77 | $process = new Process($cmd);
78 | $process->run();
79 |
80 | if (!$process->isSuccessful()) {
81 | throw new \RuntimeException($process->getErrorOutput());
82 | }
83 |
84 | // no need to output the generated phpunit report on success.
85 | // we are only interessted how long it took.
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Benchmark/bootstrap.php:
--------------------------------------------------------------------------------
1 | assertTrue(PHPUNIT_RUNNER_CLEVERANDSMART_SUCCESS);
13 | }
14 |
15 | /** @depends testSuccess */
16 | public function testFailure()
17 | {
18 | usleep(2000);
19 | $this->assertFalse(PHPUNIT_RUNNER_CLEVERANDSMART_FAILURE);
20 | }
21 |
22 | /** @depends testFailure */
23 | public function testError()
24 | {
25 | usleep(3000);
26 | if (PHPUNIT_RUNNER_CLEVERANDSMART_ERROR) {
27 | throw new \Exception();
28 | }
29 | $this->assertTrue(true);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/fixture/FatalErrorTest.php:
--------------------------------------------------------------------------------
1 | assertTrue(true);
13 | }
14 |
15 | public function testFatal()
16 | {
17 | if (PHPUNIT_RUNNER_CLEVERANDSMART_FATAL) {
18 | $this->invalidMethod();
19 | }
20 | $this->assertTrue(true);
21 | }
22 |
23 | public function testSuccess2()
24 | {
25 | usleep(2000);
26 | $this->assertTrue(true);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/fixture/Nested/DataTest.php:
--------------------------------------------------------------------------------
1 | assertFalse(PHPUNIT_RUNNER_CLEVERANDSMART_FAILURE);
25 | break;
26 |
27 | case 'PHPUNIT_RUNNER_CLEVERANDSMART_ERROR':
28 | usleep(2000);
29 | if (PHPUNIT_RUNNER_CLEVERANDSMART_ERROR) {
30 | throw new \Exception('ERROR');
31 | }
32 | $this->assertTrue(true);
33 | break;
34 |
35 | case PHPUNIT_RUNNER_CLEVERANDSMART_SUCCESS:
36 | usleep(3000);
37 | $this->assertTrue(PHPUNIT_RUNNER_CLEVERANDSMART_SUCCESS);
38 | break;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/fixture/Nested/NestedTest.php:
--------------------------------------------------------------------------------
1 | assertTrue(PHPUNIT_RUNNER_CLEVERANDSMART_SUCCESS);
13 | }
14 |
15 | public function testFailure()
16 | {
17 | usleep(2000);
18 | $this->assertFalse(PHPUNIT_RUNNER_CLEVERANDSMART_FAILURE);
19 | }
20 |
21 | public function testError()
22 | {
23 | usleep(3000);
24 | if (PHPUNIT_RUNNER_CLEVERANDSMART_ERROR) {
25 | throw new \Exception();
26 | }
27 | $this->assertTrue(true);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/fixture/SimpleTest.php:
--------------------------------------------------------------------------------
1 | assertTrue(PHPUNIT_RUNNER_CLEVERANDSMART_SUCCESS);
13 | }
14 |
15 | public function testFailure()
16 | {
17 | usleep(20000);
18 | $this->assertFalse(PHPUNIT_RUNNER_CLEVERANDSMART_FAILURE);
19 | }
20 |
21 | public function testError()
22 | {
23 | usleep(30000);
24 | if (PHPUNIT_RUNNER_CLEVERANDSMART_ERROR) {
25 | throw new \Exception();
26 | }
27 | $this->assertTrue(true);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/fixture/SkipTest.php:
--------------------------------------------------------------------------------
1 | assertTrue(true);
13 | }
14 |
15 | public function testSkipped()
16 | {
17 | if (PHPUNIT_RUNNER_CLEVERANDSMART_SKIP) {
18 | $this->markTestSkipped();
19 | }
20 | $this->assertTrue(true);
21 | usleep(2000);
22 | }
23 |
24 | public function testIncomplete()
25 | {
26 | if (PHPUNIT_RUNNER_CLEVERANDSMART_SKIP) {
27 | $this->markTestIncomplete();
28 | }
29 | $this->assertTrue(true);
30 | usleep(1000);
31 | }
32 |
33 | public function testSuccess2()
34 | {
35 | usleep(5000);
36 | $this->assertTrue(true);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/phpunit-error-failure.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ./fixture
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/phpunit-error.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ./fixture
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/phpunit-failure.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ./fixture
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/phpunit-fatal.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ./fixture
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/phpunit-skip.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ./fixture
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/phpunit-success.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ./fixture
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Integration/tests/IntegrationTest.php:
--------------------------------------------------------------------------------
1 | reset();
13 | }
14 |
15 | public function tearDown()
16 | {
17 | $this->reset();
18 | }
19 |
20 | private function reset()
21 | {
22 | $file = __DIR__ . '/../.phpunit-cas.db';
23 | if (file_exists($file)) {
24 | unlink($file);
25 | }
26 | }
27 |
28 | public function testSimpleCase_FailuresOnly()
29 | {
30 | $this->runTests('SimpleTest', 'failure', 'failure', false);
31 | $this->runTests('SimpleTest', 'success', 'success', true);
32 | $this->runTests('SimpleTest', 'success', 'retry', true);
33 |
34 | $this->assertTestSuitePosition('failure', 'SimpleTest', array(5, 1));
35 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'tests', 3);
36 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'failures', 1);
37 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'errors', 0);
38 | $this->assertTestPosition('failure', 'SimpleTest::testSuccess', 1);
39 | $this->assertTestPosition('failure', 'SimpleTest::testFailure', 2);
40 | $this->assertTestPosition('failure', 'SimpleTest::testError', 3);
41 |
42 | $this->assertTestSuitePosition('success', 'SimpleTest', 1);
43 | $this->assertTestSuiteResult('success', 'SimpleTest', 'tests', 3);
44 | $this->assertTestSuiteResult('success', 'SimpleTest', 'failures', 0);
45 | $this->assertTestSuiteResult('success', 'SimpleTest', 'errors', 0);
46 | $this->assertTestPosition('success', 'SimpleTest::testFailure', 1);
47 | $this->assertTestPosition('success', 'SimpleTest::testSuccess', 2);
48 | $this->assertTestPosition('success', 'SimpleTest::testError', 3);
49 |
50 | $this->assertTestSuitePosition('retry', 'SimpleTest', 1);
51 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'tests', 3);
52 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'failures', 0);
53 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'errors', 0);
54 | $this->assertTestPosition('retry', 'SimpleTest::testFailure', 1);
55 | $this->assertTestPosition('retry', 'SimpleTest::testSuccess', 2);
56 | $this->assertTestPosition('retry', 'SimpleTest::testError', 3);
57 | }
58 |
59 | public function testSimpleCase_ErrorsOnly()
60 | {
61 | $this->runTests('SimpleTest', 'error', 'failure', false);
62 | $this->runTests('SimpleTest', 'success', 'success', true);
63 | $this->runTests('SimpleTest', 'success', 'retry', true);
64 |
65 | $this->assertTestSuitePosition('failure', 'SimpleTest', array(5, 1));
66 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'tests', 3);
67 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'failures', 0);
68 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'errors', 1);
69 | $this->assertTestPosition('failure', 'SimpleTest::testSuccess', 1);
70 | $this->assertTestPosition('failure', 'SimpleTest::testFailure', 2);
71 | $this->assertTestPosition('failure', 'SimpleTest::testError', 3);
72 |
73 | $this->assertTestSuitePosition('success', 'SimpleTest', 1);
74 | $this->assertTestSuiteResult('success', 'SimpleTest', 'tests', 3);
75 | $this->assertTestSuiteResult('success', 'SimpleTest', 'failures', 0);
76 | $this->assertTestSuiteResult('success', 'SimpleTest', 'errors', 0);
77 | $this->assertTestPosition('success', 'SimpleTest::testError', 1);
78 | $this->assertTestPosition('success', 'SimpleTest::testSuccess', 2);
79 | $this->assertTestPosition('success', 'SimpleTest::testFailure', 3);
80 |
81 | $this->assertTestSuitePosition('retry', 'SimpleTest', 1);
82 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'tests', 3);
83 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'failures', 0);
84 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'errors', 0);
85 | $this->assertTestPosition('retry', 'SimpleTest::testError', 1);
86 | $this->assertTestPosition('retry', 'SimpleTest::testSuccess', 2);
87 | $this->assertTestPosition('retry', 'SimpleTest::testFailure', 3);
88 | }
89 |
90 | public function testSimpleCase_ErrorsAndFailures()
91 | {
92 | $this->runTests('SimpleTest', 'error-failure', 'failure', false);
93 | $this->runTests('SimpleTest', 'success', 'success', true);
94 | $this->runTests('SimpleTest', 'success', 'retry', true);
95 |
96 | $this->assertTestSuitePosition('failure', 'SimpleTest', array(5, 1));
97 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'tests', 3);
98 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'failures', 1);
99 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'errors', 1);
100 | $this->assertTestPosition('failure', 'SimpleTest::testSuccess', 1);
101 | $this->assertTestPosition('failure', 'SimpleTest::testFailure', 2);
102 | $this->assertTestPosition('failure', 'SimpleTest::testError', 3);
103 |
104 | $this->assertTestSuitePosition('success', 'SimpleTest', 1);
105 | $this->assertTestSuiteResult('success', 'SimpleTest', 'tests', 3);
106 | $this->assertTestSuiteResult('success', 'SimpleTest', 'failures', 0);
107 | $this->assertTestSuiteResult('success', 'SimpleTest', 'errors', 0);
108 | $this->assertTestPosition('success', 'SimpleTest::testFailure', 1);
109 | $this->assertTestPosition('success', 'SimpleTest::testError', 2);
110 | $this->assertTestPosition('success', 'SimpleTest::testSuccess', 3);
111 |
112 | $this->assertTestSuitePosition('retry', 'SimpleTest', 1);
113 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'tests', 3);
114 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'failures', 0);
115 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'errors', 0);
116 | $this->assertTestPosition('retry', 'SimpleTest::testFailure', 1);
117 | $this->assertTestPosition('retry', 'SimpleTest::testError', 2);
118 | $this->assertTestPosition('retry', 'SimpleTest::testSuccess', 3);
119 | }
120 |
121 | public function testSimpleCaseGrouped_FailuresOnly()
122 | {
123 | $this->runTests('SimpleTest', 'failure', 'failure', false, 'grp');
124 | $this->runTests('SimpleTest', 'success', 'success', true, 'grp');
125 | $this->runTests('SimpleTest', 'success', 'retry', true, 'grp');
126 |
127 | $this->assertTestSuitePosition('failure', 'SimpleTest', array(5, 1));
128 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'tests', 3);
129 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'failures', 1);
130 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'errors', 0);
131 | $this->assertTestPosition('failure', 'SimpleTest::testSuccess', 1);
132 | $this->assertTestPosition('failure', 'SimpleTest::testFailure', 2);
133 | $this->assertTestPosition('failure', 'SimpleTest::testError', 3);
134 |
135 | $this->assertTestSuitePosition('success', 'SimpleTest', 1);
136 | $this->assertTestSuiteResult('success', 'SimpleTest', 'tests', 3);
137 | $this->assertTestSuiteResult('success', 'SimpleTest', 'failures', 0);
138 | $this->assertTestSuiteResult('success', 'SimpleTest', 'errors', 0);
139 | $this->assertTestPosition('success', 'SimpleTest::testFailure', 1);
140 | $this->assertTestPosition('success', 'SimpleTest::testSuccess', 2);
141 | $this->assertTestPosition('success', 'SimpleTest::testError', 3);
142 |
143 | $this->assertTestSuitePosition('retry', 'SimpleTest', 1);
144 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'tests', 3);
145 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'failures', 0);
146 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'errors', 0);
147 | $this->assertTestPosition('retry', 'SimpleTest::testFailure', 1);
148 | $this->assertTestPosition('retry', 'SimpleTest::testSuccess', 2);
149 | $this->assertTestPosition('retry', 'SimpleTest::testError', 3);
150 | }
151 |
152 | public function testSimpleCaseGrouped_ErrorsOnly()
153 | {
154 | $this->runTests('SimpleTest', 'error', 'failure', false, 'grp');
155 | $this->runTests('SimpleTest', 'success', 'success', true, 'grp');
156 | $this->runTests('SimpleTest', 'success', 'retry', true, 'grp');
157 |
158 | $this->assertTestSuitePosition('failure', 'SimpleTest', array(5, 1));
159 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'tests', 3);
160 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'failures', 0);
161 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'errors', 1);
162 | $this->assertTestPosition('failure', 'SimpleTest::testSuccess', 1);
163 | $this->assertTestPosition('failure', 'SimpleTest::testFailure', 2);
164 | $this->assertTestPosition('failure', 'SimpleTest::testError', 3);
165 |
166 | $this->assertTestSuitePosition('success', 'SimpleTest', 1);
167 | $this->assertTestSuiteResult('success', 'SimpleTest', 'tests', 3);
168 | $this->assertTestSuiteResult('success', 'SimpleTest', 'failures', 0);
169 | $this->assertTestSuiteResult('success', 'SimpleTest', 'errors', 0);
170 | $this->assertTestPosition('success', 'SimpleTest::testError', 1);
171 | $this->assertTestPosition('success', 'SimpleTest::testSuccess', 2);
172 | $this->assertTestPosition('success', 'SimpleTest::testFailure', 3);
173 |
174 | $this->assertTestSuitePosition('retry', 'SimpleTest', 1);
175 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'tests', 3);
176 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'failures', 0);
177 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'errors', 0);
178 | $this->assertTestPosition('retry', 'SimpleTest::testError', 1);
179 | $this->assertTestPosition('retry', 'SimpleTest::testSuccess', 2);
180 | $this->assertTestPosition('retry', 'SimpleTest::testFailure', 3);
181 | }
182 |
183 | public function testSimpleCaseGrouped_ErrorsAndFailures()
184 | {
185 | $this->runTests('SimpleTest', 'error-failure', 'failure', false, 'grp');
186 | $this->runTests('SimpleTest', 'success', 'success', true, 'grp');
187 | $this->runTests('SimpleTest', 'success', 'retry', true, 'grp');
188 |
189 | $this->assertTestSuitePosition('failure', 'SimpleTest', array(5, 1));
190 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'tests', 3);
191 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'failures', 1);
192 | $this->assertTestSuiteResult('failure', 'SimpleTest', 'errors', 1);
193 | $this->assertTestPosition('failure', 'SimpleTest::testSuccess', 1);
194 | $this->assertTestPosition('failure', 'SimpleTest::testFailure', 2);
195 | $this->assertTestPosition('failure', 'SimpleTest::testError', 3);
196 |
197 | $this->assertTestSuitePosition('success', 'SimpleTest', 1);
198 | $this->assertTestSuiteResult('success', 'SimpleTest', 'tests', 3);
199 | $this->assertTestSuiteResult('success', 'SimpleTest', 'failures', 0);
200 | $this->assertTestSuiteResult('success', 'SimpleTest', 'errors', 0);
201 | $this->assertTestPosition('success', 'SimpleTest::testFailure', 1);
202 | $this->assertTestPosition('success', 'SimpleTest::testError', 2);
203 | $this->assertTestPosition('success', 'SimpleTest::testSuccess', 3);
204 |
205 | $this->assertTestSuitePosition('retry', 'SimpleTest', 1);
206 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'tests', 3);
207 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'failures', 0);
208 | $this->assertTestSuiteResult('retry', 'SimpleTest', 'errors', 0);
209 | $this->assertTestPosition('retry', 'SimpleTest::testFailure', 1);
210 | $this->assertTestPosition('retry', 'SimpleTest::testError', 2);
211 | $this->assertTestPosition('retry', 'SimpleTest::testSuccess', 3);
212 | }
213 |
214 | public function testDataProviderTestCase()
215 | {
216 | $this->runTests('DataTest', 'error', 'failure', false, 'grp');
217 | $this->runTests('DataTest', 'success', 'success', true, 'grp');
218 | $this->runTests('DataTest', 'success', 'retry', true, 'grp');
219 |
220 | $this->assertTestSuitePosition('failure', 'DataTest', 1);
221 | $this->assertTestSuiteResult('failure', 'DataTest', 'tests', 3);
222 | $this->assertTestSuiteResult('failure', 'DataTest', 'failures', 0);
223 | $this->assertTestSuiteResult('failure', 'DataTest', 'errors', 1);
224 | $this->assertTestPosition('failure', 'DataTest::testData with data set #0', 1);
225 | $this->assertTestPosition('failure', 'DataTest::testData with data set #1', 2);
226 | $this->assertTestPosition('failure', 'DataTest::testData with data set #2', 3);
227 |
228 | $this->assertTestSuitePosition('success', 'DataTest', 1);
229 | $this->assertTestSuiteResult('success', 'DataTest', 'tests', 3);
230 | $this->assertTestSuiteResult('success', 'DataTest', 'failures', 0);
231 | $this->assertTestSuiteResult('success', 'DataTest', 'errors', 0);
232 | $this->assertTestPosition('success', 'DataTest::testData with data set #1', 1);
233 | $this->assertTestPosition('success', 'DataTest::testData with data set #0', 2);
234 | $this->assertTestPosition('success', 'DataTest::testData with data set #2', 3);
235 |
236 | $this->assertTestSuitePosition('retry', 'DataTest', 1);
237 | $this->assertTestSuiteResult('retry', 'DataTest', 'tests', 3);
238 | $this->assertTestSuiteResult('retry', 'DataTest', 'failures', 0);
239 | $this->assertTestSuiteResult('retry', 'DataTest', 'errors', 0);
240 | $this->assertTestPosition('retry', 'DataTest::testData with data set #1', 1);
241 | $this->assertTestPosition('retry', 'DataTest::testData with data set #0', 2);
242 | $this->assertTestPosition('retry', 'DataTest::testData with data set #2', 3);
243 | }
244 |
245 | public function testDependentTest()
246 | {
247 | $this->runTests('DependentTest', 'failure', 'failure', false, 'grp');
248 | $this->runTests('DependentTest', 'success', 'success', true, 'grp');
249 | $this->runTests('DependentTest', 'success', 'retry', true, 'grp');
250 |
251 | $this->assertTestSuitePosition('failure', 'DependentTest', 1);
252 | $this->assertTestSuiteResult('failure', 'DependentTest', 'tests', 2);
253 | $this->assertTestSuiteResult('failure', 'DependentTest', 'failures', 1);
254 | $this->assertTestSuiteResult('failure', 'DependentTest', 'errors', 0);
255 | $this->assertTestPosition('failure', 'DependentTest::testSuccess', 1);
256 | $this->assertTestPosition('failure', 'DependentTest::testFailure', 2);
257 |
258 | $this->assertTestSuitePosition('success', 'DependentTest', 1);
259 | $this->assertTestSuiteResult('success', 'DependentTest', 'tests', 3);
260 | $this->assertTestSuiteResult('success', 'DependentTest', 'failures', 0);
261 | $this->assertTestSuiteResult('success', 'DependentTest', 'errors', 0);
262 | $this->assertTestPosition('success', 'DependentTest::testSuccess', 1);
263 | $this->assertTestPosition('success', 'DependentTest::testFailure', 2);
264 | $this->assertTestPosition('success', 'DependentTest::testError', 3);
265 |
266 | $this->assertTestSuitePosition('retry', 'DependentTest', 1);
267 | $this->assertTestSuiteResult('retry', 'DependentTest', 'tests', 3);
268 | $this->assertTestSuiteResult('retry', 'DependentTest', 'failures', 0);
269 | $this->assertTestSuiteResult('retry', 'DependentTest', 'errors', 0);
270 | $this->assertTestPosition('retry', 'DependentTest::testSuccess', 1);
271 | $this->assertTestPosition('retry', 'DependentTest::testFailure', 2);
272 | $this->assertTestPosition('retry', 'DependentTest::testError', 3);
273 | }
274 |
275 | public function testFatalError()
276 | {
277 | $this->runTests('FatalErrorTest', 'fatal', 'fatal', false, 'grp');
278 | $this->runTests('FatalErrorTest', 'success', 'success', true, 'grp');
279 | $this->runTests('FatalErrorTest', 'success', 'retry', true, 'grp');
280 |
281 | $this->assertTestSuitePosition('success', 'FatalErrorTest', 1);
282 | $this->assertTestSuiteResult('success', 'FatalErrorTest', 'tests', 3);
283 | $this->assertTestSuiteResult('success', 'FatalErrorTest', 'failures', 0);
284 | $this->assertTestSuiteResult('success', 'FatalErrorTest', 'errors', 0);
285 | $this->assertTestPosition('success', 'FatalErrorTest::testFatal', 1);
286 | $this->assertTestPosition('success', 'FatalErrorTest::testSuccess2', 2);
287 | $this->assertTestPosition('success', 'FatalErrorTest::testSuccess1', 3);
288 |
289 | $this->assertTestSuitePosition('retry', 'FatalErrorTest', 1);
290 | $this->assertTestSuiteResult('retry', 'FatalErrorTest', 'tests', 3);
291 | $this->assertTestSuiteResult('retry', 'FatalErrorTest', 'failures', 0);
292 | $this->assertTestSuiteResult('retry', 'FatalErrorTest', 'errors', 0);
293 | $this->assertTestPosition('retry', 'FatalErrorTest::testFatal', 1);
294 | $this->assertTestPosition('retry', 'FatalErrorTest::testSuccess1', 2);
295 | $this->assertTestPosition('retry', 'FatalErrorTest::testSuccess2', 3);
296 | }
297 |
298 | public function testSkippedAndIncompleteTests()
299 | {
300 | $this->runTests('SkipTest', 'skip', 'skip', true, 'grp');
301 | $this->runTests('SkipTest', 'success', 'success', true, 'grp');
302 | $this->runTests('SkipTest', 'success', 'retry', true, 'grp');
303 |
304 | $this->assertTestSuitePosition('skip', 'SkipTest', array(1, 6));
305 | $this->assertTestSuiteResult('skip', 'SkipTest', 'tests', 2);
306 | $this->assertTestSuiteResult('skip', 'SkipTest', 'failures', 0);
307 | $this->assertTestSuiteResult('skip', 'SkipTest', 'errors', 0);
308 | $this->assertTestPosition('skip', 'SkipTest::testSuccess1', 1);
309 | $this->assertTestPosition('skip', 'SkipTest::testSuccess2', 2);
310 |
311 | $this->assertTestSuitePosition('success', 'SkipTest', 1);
312 | $this->assertTestSuiteResult('success', 'SkipTest', 'tests', 4);
313 | $this->assertTestSuiteResult('success', 'SkipTest', 'failures', 0);
314 | $this->assertTestSuiteResult('success', 'SkipTest', 'errors', 0);
315 | $this->assertTestPosition('success', 'SkipTest::testSkipped', 1);
316 | $this->assertTestPosition('success', 'SkipTest::testIncomplete', 2);
317 | $this->assertTestPosition('success', 'SkipTest::testSuccess1', 3);
318 | $this->assertTestPosition('success', 'SkipTest::testSuccess2', 4);
319 |
320 | $this->assertTestSuitePosition('retry', 'SkipTest', 1);
321 | $this->assertTestSuiteResult('retry', 'SkipTest', 'tests', 4);
322 | $this->assertTestSuiteResult('retry', 'SkipTest', 'failures', 0);
323 | $this->assertTestSuiteResult('retry', 'SkipTest', 'errors', 0);
324 | $this->assertTestPosition('retry', 'SkipTest::testSkipped', 1);
325 | $this->assertTestPosition('retry', 'SkipTest::testIncomplete', 2);
326 | $this->assertTestPosition('retry', 'SkipTest::testSuccess1', 3);
327 | $this->assertTestPosition('retry', 'SkipTest::testSuccess2', 4);
328 | }
329 |
330 | private function runTests($testFile, $state, $runName, $expectedResult, $group = null)
331 | {
332 | $phpunit = realpath(__DIR__ . '/../../../../../../../vendor/bin/phpunit');
333 |
334 | $commandString = defined('PHP_BINARY') ? PHP_BINARY : 'php';
335 | if (strpos($commandString, 'hhvm') === false) {
336 | $commandString .= ' -d error_log=/tmp/dev.log';
337 | }
338 |
339 | $commandString .= ' ' . $phpunit
340 | . ' --configuration ' . __DIR__ . '/../phpunit-%s.xml'
341 | . ' --log-junit ' . __DIR__ . '/../result-' . $runName . '.xml'
342 | . ' --filter ' . $testFile;
343 |
344 | if ($group) {
345 | $commandString .= ' --group ' . $group;
346 | }
347 |
348 | $process = new Process(sprintf($commandString, $state));
349 | $process->setWorkingDirectory(__DIR__ . '/../');
350 | $process->run();
351 |
352 | $this->assertTrue(
353 | $expectedResult ? $process->isSuccessful() : !$process->isSuccessful(),
354 | $process->getOutput() . "\n\n\n" . $process->getErrorOutput()
355 | );
356 | }
357 |
358 | private static function assertTestPosition($runName, $testName, $expectedPosition)
359 | {
360 | $resultFilePath = static::getResultFilePath($runName);
361 | list($class, $method) = explode('::', $testName);
362 | $expression = sprintf(
363 | '//testsuite[contains(@name, "%s")]/testcase[%d][@name="%s"]',
364 | $class,
365 | $expectedPosition,
366 | $method
367 | );
368 |
369 | $xml = file_get_contents($resultFilePath);
370 | static::assertXpathNotEmpty(
371 | $xml,
372 | $expression,
373 | sprintf('Could not find XPath expression "%s" in "%s" (%s)', $expression, $resultFilePath, $xml)
374 | );
375 | }
376 |
377 | private static function assertTestSuitePosition($runName, $suite, $expectedPositions)
378 | {
379 | $resultFilePath = static::getResultFilePath($runName);
380 |
381 | $expressions = array();
382 | foreach ((array) $expectedPositions as $expectedPosition) {
383 | $expressions[] = sprintf(
384 | '//testsuite/testsuite[%d][contains(@name, "%s")]',
385 | $expectedPosition,
386 | $suite
387 | );
388 | }
389 |
390 | $expression = implode(' | ', $expressions);
391 |
392 | $xml = file_get_contents($resultFilePath);
393 | static::assertXpathNotEmpty(
394 | $xml,
395 | $expression,
396 | sprintf('Could not find XPath expression "%s" in "%s" (%s)', $expression, $resultFilePath, $xml)
397 | );
398 | }
399 |
400 | private static function assertTestSuiteResult($runName, $class, $attribute, $expectedValue)
401 | {
402 | $resultFilePath = static::getResultFilePath($runName);
403 | $expression = sprintf('//testsuite[contains(@name, "%s")]', $class);
404 |
405 | $xml = file_get_contents($resultFilePath);
406 | static::assertXpathEquals($xml, $expression, $expectedValue, $attribute);
407 | }
408 |
409 | private static function assertXpathNotEmpty($xml, $xpath, $comment = null)
410 | {
411 | $xml = new SimpleXMLElement($xml);
412 |
413 | static::assertNotEmpty(
414 | (array) $xml->xpath($xpath),
415 | $comment ?: sprintf('Could not find "%s" in "%s"', $xpath, $xml)
416 | );
417 | }
418 |
419 | private static function assertXpathEquals($xml, $xpath, $expectedValue, $attribute = null, $comment = null)
420 | {
421 | static::assertXpathNotEmpty($xml, $xpath);
422 | $xml = new SimpleXMLElement($xml);
423 | $element = current($xml->xpath($xpath));
424 | if ($attribute) {
425 | $element = $element[$attribute];
426 | }
427 | static::assertEquals($expectedValue, (string) $element);
428 | }
429 |
430 | private static function getResultFilePath($runName)
431 | {
432 | return __DIR__ . '/../result-' . $runName . '.xml';
433 | }
434 | }
435 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Unit/PrioritySorterTest.php:
--------------------------------------------------------------------------------
1 | addTest(new Test('test1'));
19 | $suite->addTest(new Test('test2'));
20 | $suite->addTest(new Test('test3'));
21 | $suite->addTest(new Test('test4'));
22 |
23 | $tests = $suite->tests();
24 | $this->assertSame('test1', $tests[0]->getName());
25 | $this->assertSame('test2', $tests[1]->getName());
26 | $this->assertSame('test3', $tests[2]->getName());
27 | $this->assertSame('test4', $tests[3]->getName());
28 |
29 | $sorter = new PrioritySorter(
30 | array(array('class' => 'PHPUnit\Runner\CleverAndSmart\Unit\Test', 'test' => 'test2'))
31 | );
32 | $sorter->sort($suite);
33 | $tests = $suite->tests();
34 |
35 | $this->assertSame('test2', $tests[0]->getName());
36 | $this->assertSame('test1', $tests[1]->getName());
37 | $this->assertSame('test3', $tests[2]->getName());
38 | $this->assertSame('test4', $tests[3]->getName());
39 | }
40 |
41 | public function testSimpleSortingBothMarkedAsErroneous()
42 | {
43 | $suite = new TestSuite('suite1', 'suite1');
44 | $suite->addTest(new Test('test1'));
45 | $suite->addTest(new Test('test2'));
46 | $suite->addTest(new Test('test3'));
47 | $suite->addTest(new Test('test4'));
48 |
49 | $tests = $suite->tests();
50 | $this->assertSame('test1', $tests[0]->getName());
51 | $this->assertSame('test2', $tests[1]->getName());
52 | $this->assertSame('test3', $tests[2]->getName());
53 | $this->assertSame('test4', $tests[3]->getName());
54 |
55 | $sorter = new PrioritySorter(
56 | array(
57 | array('class' => 'PHPUnit\Runner\CleverAndSmart\Unit\Test', 'test' => 'test2'),
58 | array('class' => 'PHPUnit\Runner\CleverAndSmart\Unit\Test', 'test' => 'test1'),
59 | )
60 | );
61 | $sorter->sort($suite);
62 | $tests = $suite->tests();
63 |
64 | $this->assertSame('test1', $tests[0]->getName());
65 | $this->assertSame('test2', $tests[1]->getName());
66 | $this->assertSame('test3', $tests[2]->getName());
67 | $this->assertSame('test4', $tests[3]->getName());
68 | }
69 |
70 | public function testSimpleSortingNoErrors()
71 | {
72 | $suite = new TestSuite('suite1', 'suite1');
73 | $suite->addTest(new Test('test1'));
74 | $suite->addTest(new Test('test2'));
75 | $suite->addTest(new Test('test3'));
76 | $suite->addTest(new Test('test4'));
77 |
78 | $tests = $suite->tests();
79 | $this->assertSame('test1', $tests[0]->getName());
80 | $this->assertSame('test2', $tests[1]->getName());
81 | $this->assertSame('test3', $tests[2]->getName());
82 | $this->assertSame('test4', $tests[3]->getName());
83 |
84 | $sorter = new PrioritySorter(array());
85 | $sorter->sort($suite);
86 | $tests = $suite->tests();
87 |
88 | $this->assertSame('test1', $tests[0]->getName());
89 | $this->assertSame('test2', $tests[1]->getName());
90 | $this->assertSame('test3', $tests[2]->getName());
91 | $this->assertSame('test4', $tests[3]->getName());
92 | }
93 |
94 | public function testNestedSorting()
95 | {
96 | $suite1 = new TestSuite('suite1', 'suite1');
97 | $suite2 = new TestSuite('suite2', 'suite2');
98 | $suite2->addTest(new Test('test3'));
99 | $suite1->addTestSuite($suite2);
100 | $suite1->addTest(new Test('test1'));
101 | $suite1->addTest(new Test('test2'));
102 | $suite1->addTest(new Test('test3'));
103 | $suite1->addTest(new Test('test4'));
104 |
105 | $tests = $suite1->tests();
106 | $this->assertSame('suite2', $tests[0]->getName());
107 | $this->assertSame('test1', $tests[1]->getName());
108 | $this->assertSame('test2', $tests[2]->getName());
109 | $this->assertSame('test3', $tests[3]->getName());
110 | $this->assertSame('test4', $tests[4]->getName());
111 |
112 | $sorter = new PrioritySorter(
113 | array(array('class' => 'PHPUnit\Runner\CleverAndSmart\Unit\Test', 'test' => 'test2'))
114 | );
115 | $sorter->sort($suite1);
116 | $tests = $suite1->tests();
117 |
118 | $this->assertSame('test2', $tests[0]->getName());
119 | $this->assertSame('suite2', $tests[1]->getName());
120 | $this->assertSame('test1', $tests[2]->getName());
121 | $this->assertSame('test3', $tests[3]->getName());
122 | $this->assertSame('test4', $tests[4]->getName());
123 | }
124 |
125 | public function testNestedSortingWithTimings()
126 | {
127 | $suite1 = new TestSuite('suite1', 'suite1');
128 | $suite2 = new TestSuite('suite2', 'suite2');
129 | $suite2->addTest(new Test('test2.1'));
130 | $suite2->addTest(new Test('test2.2'));
131 | $suite1->addTestSuite($suite2);
132 | $suite1->addTest(new Test('test1'));
133 | $suite1->addTest(new Test('test2'));
134 | $suite1->addTest(new Test('test3'));
135 | $suite1->addTest(new Test('test4'));
136 |
137 | $tests = $suite1->tests();
138 | $this->assertSame('suite2', $tests[0]->getName());
139 | $this->assertSame('test1', $tests[1]->getName());
140 | $this->assertSame('test2', $tests[2]->getName());
141 | $this->assertSame('test3', $tests[3]->getName());
142 | $this->assertSame('test4', $tests[4]->getName());
143 |
144 | $sorter = new PrioritySorter(
145 | array(array('class' => 'PHPUnit\Runner\CleverAndSmart\Unit\Test', 'test' => 'test2')),
146 | array(
147 | array('class' => 'PHPUnit\Runner\CleverAndSmart\Unit\Test', 'test' => 'test1', 'time' => 100),
148 | array('class' => 'PHPUnit\Runner\CleverAndSmart\Unit\Test', 'test' => 'test4', 'time' => 200),
149 | array('class' => 'PHPUnit\Runner\CleverAndSmart\Unit\Test', 'test' => 'test2.1', 'time' => 100),
150 | )
151 | );
152 | $sorter->sort($suite1);
153 | $tests = $suite1->tests();
154 | $tests2 = $tests[2]->tests();
155 |
156 | $this->assertSame('test2', $tests[0]->getName());
157 | $this->assertSame('test3', $tests[1]->getName());
158 | $this->assertSame('suite2', $tests[2]->getName());
159 | $this->assertSame('test2.2', $tests2[0]->getName());
160 | $this->assertSame('test2.1', $tests2[1]->getName());
161 | $this->assertSame('test1', $tests[3]->getName());
162 | $this->assertSame('test4', $tests[4]->getName());
163 | }
164 |
165 | public function testNestedSortingNoErrors()
166 | {
167 | $suite1 = new TestSuite('suite1', 'suite1');
168 | $suite2 = new TestSuite('suite2', 'suite2');
169 | $suite2->addTest(new Test('test3'));
170 | $suite1->addTestSuite($suite2);
171 | $suite1->addTest(new Test('test1'));
172 | $suite1->addTest(new Test('test2'));
173 | $suite1->addTest(new Test('test3'));
174 | $suite1->addTest(new Test('test4'));
175 |
176 | $tests = $suite1->tests();
177 | $tests0 = $tests[0]->tests();
178 |
179 | $this->assertSame('suite2', $tests[0]->getName());
180 | $this->assertSame('test3', $tests0[0]->getName());
181 | $this->assertSame('test1', $tests[1]->getName());
182 | $this->assertSame('test2', $tests[2]->getName());
183 | $this->assertSame('test3', $tests[3]->getName());
184 | $this->assertSame('test4', $tests[4]->getName());
185 |
186 | $sorter = new PrioritySorter(array());
187 | $sorter->sort($suite1);
188 | $tests = $suite1->tests();
189 | $tests0 = $tests[0]->tests();
190 |
191 | $this->assertSame('suite2', $tests[0]->getName());
192 | $this->assertSame('test3', $tests0[0]->getName());
193 | $this->assertSame('test1', $tests[1]->getName());
194 | $this->assertSame('test2', $tests[2]->getName());
195 | $this->assertSame('test3', $tests[3]->getName());
196 | $this->assertSame('test4', $tests[4]->getName());
197 | }
198 |
199 | public function testSimpleSortingGroups()
200 | {
201 | $suite = new TestSuite('suite1', 'suite1');
202 | $suite->addTest(new Test('test1'), array('g1'));
203 | $suite->addTest(new Test('test2'), array('g1'));
204 | $suite->addTest(new Test('test3'), array('g1'));
205 | $suite->addTest(new Test('test4'), array('g1'));
206 |
207 | $tests = $suite->tests();
208 | $this->assertSame('test1', $tests[0]->getName());
209 | $this->assertSame('test2', $tests[1]->getName());
210 | $this->assertSame('test3', $tests[2]->getName());
211 | $this->assertSame('test4', $tests[3]->getName());
212 |
213 | $groupDetails = Util::getInvisibleProperty($suite, 'groups', 'getGroupDetails');
214 | $tests = $groupDetails['g1'];
215 | $this->assertSame('test1', $tests[0]->getName());
216 | $this->assertSame('test2', $tests[1]->getName());
217 | $this->assertSame('test3', $tests[2]->getName());
218 | $this->assertSame('test4', $tests[3]->getName());
219 |
220 | $sorter = new PrioritySorter(
221 | array(array('class' => 'PHPUnit\Runner\CleverAndSmart\Unit\Test', 'test' => 'test2'))
222 | );
223 | $sorter->sort($suite);
224 | $tests = $suite->tests();
225 |
226 | $this->assertSame('test2', $tests[0]->getName());
227 | $this->assertSame('test1', $tests[1]->getName());
228 | $this->assertSame('test3', $tests[2]->getName());
229 | $this->assertSame('test4', $tests[3]->getName());
230 |
231 | $groupDetails = Util::getInvisibleProperty($suite, 'groups', 'getGroupDetails');
232 | $tests = $groupDetails['g1'];
233 | $this->assertSame('test2', $tests[0]->getName());
234 | $this->assertSame('test1', $tests[1]->getName());
235 | $this->assertSame('test3', $tests[2]->getName());
236 | $this->assertSame('test4', $tests[3]->getName());
237 | }
238 |
239 | public function testNestedSortingGroups()
240 | {
241 | $suite1 = new TestSuite('suite1', 'suite1');
242 | $suite2 = new TestSuite('suite2', 'suite2');
243 | $suite2->addTest(new Test('test3'), array('g1'));
244 | $suite1->addTestSuite($suite2);
245 | $suite1->addTest(new Test('test1'), array('g1'));
246 | $suite1->addTest(new Test('test2'), array('g1'));
247 | $suite1->addTest(new Test('test4'), array('g1'));
248 | $suite1->addTest(new Test('test5'), array('g1'));
249 |
250 | $tests = $suite1->tests();
251 | $tests0 = $tests[0]->tests();
252 |
253 | $this->assertSame('suite2', $tests[0]->getName());
254 | $this->assertSame('test3', $tests0[0]->getName());
255 | $this->assertSame('test1', $tests[1]->getName());
256 | $this->assertSame('test2', $tests[2]->getName());
257 | $this->assertSame('test4', $tests[3]->getName());
258 | $this->assertSame('test5', $tests[4]->getName());
259 |
260 | $groupDetails = Util::getInvisibleProperty($suite1, 'groups', 'getGroupDetails');
261 | $tests = $groupDetails['g1'];
262 | $tests0 = $tests[0]->tests();
263 |
264 | $this->assertSame('suite2', $tests[0]->getName());
265 | $this->assertSame('test3', $tests0[0]->getName());
266 | $this->assertSame('test1', $tests[1]->getName());
267 | $this->assertSame('test2', $tests[2]->getName());
268 | $this->assertSame('test4', $tests[3]->getName());
269 | $this->assertSame('test5', $tests[4]->getName());
270 |
271 | $sorter = new PrioritySorter(
272 | array(array('class' => 'PHPUnit\Runner\CleverAndSmart\Unit\Test', 'test' => 'test2'))
273 | );
274 | $sorter->sort($suite1);
275 |
276 | $tests = $suite1->tests();
277 | $tests1 = $tests[1]->tests();
278 |
279 | $this->assertSame('test2', $tests[0]->getName());
280 | $this->assertSame('suite2', $tests[1]->getName());
281 | $this->assertSame('test3', $tests1[0]->getName());
282 | $this->assertSame('test1', $tests[2]->getName());
283 | $this->assertSame('test4', $tests[3]->getName());
284 | $this->assertSame('test5', $tests[4]->getName());
285 |
286 | $groupDetails = Util::getInvisibleProperty($suite1, 'groups', 'getGroupDetails');
287 | $tests = $groupDetails['g1'];
288 | $tests1 = $tests[1]->tests();
289 |
290 | $this->assertSame('test2', $tests[0]->getName());
291 | $this->assertSame('suite2', $tests[1]->getName());
292 | $this->assertSame('test3', $tests1[0]->getName());
293 | $this->assertSame('test1', $tests[2]->getName());
294 | $this->assertSame('test4', $tests[3]->getName());
295 | $this->assertSame('test5', $tests[4]->getName());
296 | }
297 | }
298 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Unit/SegmentedQueueTest.php:
--------------------------------------------------------------------------------
1 | queue = new SegmentedQueue();
15 | }
16 |
17 | public function testPushToUnknownQueue()
18 | {
19 | $this->queue->unknown->push('test1');
20 | $this->queue->unknown->push('test2');
21 |
22 | $this->assertSame(array('test1', 'test2'), iterator_to_array($this->queue));
23 | }
24 |
25 | public function testPushWithPriority()
26 | {
27 | $this->queue->unknown->push('test1');
28 | $this->queue->timed->insert('test4', 0.1);
29 | $this->queue->timed->insert('test5', 0.2);
30 | $this->queue->timed->insert('test3', 0.05);
31 | $this->queue->unknown->push('test2');
32 |
33 | $this->assertSame(array('test1', 'test2', 'test3', 'test4', 'test5'), iterator_to_array($this->queue));
34 | }
35 |
36 | public function testResetWithNull()
37 | {
38 | $this->queue->unknown->push('test1');
39 | $this->queue->unknown->push('test2');
40 | $this->queue->unknown[0] = null;
41 |
42 | $this->assertSame(array('test2'), iterator_to_array($this->queue));
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Unit/Storage/Sqlite3StorageTest.php:
--------------------------------------------------------------------------------
1 | file = __DIR__ . '/.phpunit-cas-test.db';
37 | $this->reset();
38 |
39 | $this->storage = new Sqlite3Storage($this->file);
40 | $this->test1 = new Test();
41 | $this->test1->setName('testMethod1');
42 | $this->test2 = new Test();
43 | $this->test2->setName('testMethod2');
44 | $this->run1 = new Run();
45 | $this->run2 = new Run();
46 | }
47 |
48 | public function tearDown()
49 | {
50 | $this->reset();
51 | }
52 |
53 | private function reset()
54 | {
55 | if (file_exists($this->file)) {
56 | unlink($this->file);
57 | }
58 | }
59 |
60 | public static function getTypes()
61 | {
62 | $class = new ReflectionClass('PHPUnit\Runner\CleverAndSmart\Storage\StorageInterface');
63 |
64 | $types = array();
65 | foreach ($class->getConstants() as $name => $value) {
66 | $types[] = array($value, $name);
67 | }
68 |
69 | return $types;
70 | }
71 |
72 | public static function getErrorTypes()
73 | {
74 | return array(
75 | array(StorageInterface::STATUS_FAILURE, 'STATUS_FAILURE'),
76 | array(StorageInterface::STATUS_ERROR, 'STATUS_ERROR'),
77 | array(StorageInterface::STATUS_FATAL_ERROR, 'STATUS_FATAL_ERROR'),
78 | array(StorageInterface::STATUS_CANCEL, 'STATUS_CANCEL'),
79 | );
80 | }
81 |
82 | /** @dataProvider getTypes */
83 | public function testNormalRecording($type)
84 | {
85 | $this->assertEmpty($this->storage->getRecordings(array($type)));
86 | $this->storage->record($this->run1, $this->test1, 1000, $type);
87 | $this->storage->record($this->run1, $this->test1, 2000, $type);
88 | $recordings = $this->storage->getRecordings(array($type));
89 | $this->assertNotEmpty($recordings);
90 |
91 | $this->assertCount(3, $recordings[0]);
92 | $this->assertArrayHasKey('class', $recordings[0]);
93 | $this->assertArrayHasKey('test', $recordings[0]);
94 | $this->assertArrayHasKey('time', $recordings[0]);
95 | $this->assertSame(1500.0, $recordings[0]['time']);
96 |
97 | $recordings = $this->storage->getRecordings(array($type), false);
98 | $this->assertCount(2, $recordings[0]);
99 | $this->assertArrayHasKey('class', $recordings[0]);
100 | $this->assertArrayHasKey('test', $recordings[0]);
101 | }
102 |
103 | /** @dataProvider getTypes */
104 | public function testRecordingsAreSortedByFrequency($type)
105 | {
106 | $this->assertEmpty($this->storage->getRecordings(array($type)));
107 | $this->storage->record($this->run1, $this->test1, 0, $type);
108 | $this->storage->record($this->run1, $this->test2, 0, $type);
109 | $this->storage->record($this->run1, $this->test1, 0, $type);
110 | $this->storage->record($this->run1, $this->test2, 0, $type);
111 | $this->storage->record($this->run2, $this->test2, 0, $type);
112 |
113 | $this->assertSame(
114 | array(
115 | array('class' => 'PHPUnit\Runner\CleverAndSmart\Unit\Storage\Test', 'test' => 'testMethod2'),
116 | array('class' => 'PHPUnit\Runner\CleverAndSmart\Unit\Storage\Test', 'test' => 'testMethod1'),
117 | ),
118 | $this->storage->getRecordings(array($type), false)
119 | );
120 | }
121 |
122 | /** @dataProvider getErrorTypes */
123 | public function testRecordedErrorsAreRemovedAfterFiveTimes($type)
124 | {
125 | $this->assertEmpty($this->storage->getRecordings(array($type)));
126 | $this->storage->record($this->run1, $this->test1, 1, $type);
127 | $this->assertNotEmpty($this->storage->getRecordings(array($type)));
128 |
129 | $this->storage->record($this->run1, $this->test1, 1, StorageInterface::STATUS_PASSED);
130 | $this->assertNotEmpty($this->storage->getRecordings(array($type)));
131 | $this->storage->record($this->run1, $this->test1, 2, StorageInterface::STATUS_PASSED);
132 | $this->assertNotEmpty($this->storage->getRecordings(array($type)));
133 | $this->storage->record($this->run1, $this->test1, 3, StorageInterface::STATUS_PASSED);
134 | $this->assertNotEmpty($this->storage->getRecordings(array($type)));
135 | $this->storage->record($this->run1, $this->test1, 4, StorageInterface::STATUS_PASSED);
136 | $this->assertEmpty($this->storage->getRecordings(array($type)));
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/tests/PHPUnit/Tests/Runner/CleverAndSmart/Unit/UtilTest.php:
--------------------------------------------------------------------------------
1 | privateProperty;
16 | }
17 |
18 | public function setPrivateProperty($value)
19 | {
20 | $this->privateProperty = $value;
21 | }
22 |
23 | public function getPublicProperty()
24 | {
25 | return $this->publicProperty;
26 | }
27 |
28 | public function setPublicProperty($value)
29 | {
30 | $this->publicProperty = $value;
31 | }
32 | }
33 |
34 | class Child extends Mother
35 | {
36 | protected $protectedProperty = 'protected';
37 |
38 | public function getProtectedProperty()
39 | {
40 | return $this->protectedProperty;
41 | }
42 |
43 | public function setProtectedProperty($value)
44 | {
45 | $this->protectedProperty = $value;
46 | }
47 | }
48 |
49 | class UtilTest extends TestCase
50 | {
51 | public function testCreateRunId()
52 | {
53 | $idOne = Util::createRunId();
54 | $idTwo = Util::createRunId();
55 |
56 | $this->assertSame(128, strlen($idOne));
57 | $this->assertSame(128, strlen($idTwo));
58 | $this->assertNotSame($idOne, $idTwo);
59 | }
60 |
61 | public function testGetInvisiblePropertyByMethod()
62 | {
63 | $mother = new Mother();
64 | $child = new Child();
65 |
66 | $this->assertSame('private', Util::getInvisibleProperty($mother, 'invalidProperty', 'getPrivateProperty'));
67 | $this->assertSame('private', Util::getInvisibleProperty($child, 'invalidProperty', 'getPrivateProperty'));
68 | $this->assertSame('protected', Util::getInvisibleProperty($child, 'invalidProperty', 'getProtectedProperty'));
69 | $this->assertSame('public', Util::getInvisibleProperty($mother, 'invalidProperty', 'getPublicProperty'));
70 | $this->assertSame('public', Util::getInvisibleProperty($child, 'invalidProperty', 'getPublicProperty'));
71 | }
72 |
73 | public function testGetInvisiblePropertyByProperty()
74 | {
75 | $mother = new Mother();
76 | $child = new Child();
77 |
78 | $this->assertSame('private', Util::getInvisibleProperty($mother, 'privateProperty'));
79 | $this->assertSame('private', Util::getInvisibleProperty($mother, 'privateProperty', 'invalidMethod'));
80 | $this->assertSame('private', Util::getInvisibleProperty($child, 'privateProperty'));
81 | $this->assertSame('private', Util::getInvisibleProperty($child, 'privateProperty', 'invalidMethod'));
82 | $this->assertSame('protected', Util::getInvisibleProperty($child, 'protectedProperty'));
83 | $this->assertSame('protected', Util::getInvisibleProperty($child, 'protectedProperty', 'invalidMethod'));
84 | $this->assertSame('public', Util::getInvisibleProperty($mother, 'publicProperty'));
85 | $this->assertSame('public', Util::getInvisibleProperty($mother, 'publicProperty', 'invalidMethod'));
86 | $this->assertSame('public', Util::getInvisibleProperty($child, 'publicProperty'));
87 | $this->assertSame('public', Util::getInvisibleProperty($child, 'publicProperty', 'invalidMethod'));
88 | }
89 |
90 | public function testSetInvisiblePropertyByProperty()
91 | {
92 | $mother = new Mother();
93 | $child = new Child();
94 |
95 | Util::setInvisibleProperty($mother, 'privateProperty', 'private2');
96 | $this->assertSame('private2', Util::getInvisibleProperty($mother, 'invalidProperty', 'getPrivateProperty'));
97 |
98 | Util::setInvisibleProperty($mother, 'privateProperty', 'private3', 'invalidMethod');
99 | $this->assertSame('private3', Util::getInvisibleProperty($mother, 'invalidProperty', 'getPrivateProperty'));
100 |
101 | Util::setInvisibleProperty($child, 'privateProperty', 'private2');
102 | $this->assertSame('private2', Util::getInvisibleProperty($child, 'invalidProperty', 'getPrivateProperty'));
103 |
104 | Util::setInvisibleProperty($child, 'privateProperty', 'private3', 'invalidMethod');
105 | $this->assertSame('private3', Util::getInvisibleProperty($child, 'invalidProperty', 'getPrivateProperty'));
106 |
107 | Util::setInvisibleProperty($child, 'protectedProperty', 'protected2');
108 | $this->assertSame('protected2', Util::getInvisibleProperty($child, 'invalidProperty', 'getProtectedProperty'));
109 |
110 | Util::setInvisibleProperty($child, 'protectedProperty', 'protected3', 'invalidMethod');
111 | $this->assertSame('protected3', Util::getInvisibleProperty($child, 'invalidProperty', 'getProtectedProperty'));
112 |
113 | Util::setInvisibleProperty($mother, 'publicProperty', 'public2');
114 | $this->assertSame('public2', Util::getInvisibleProperty($mother, 'invalidProperty', 'getPublicProperty'));
115 |
116 | Util::setInvisibleProperty($mother, 'publicProperty', 'public3', 'methodName');
117 | $this->assertSame('public3', Util::getInvisibleProperty($mother, 'invalidProperty', 'getPublicProperty'));
118 |
119 | Util::setInvisibleProperty($child, 'publicProperty', 'public2');
120 | $this->assertSame('public2', Util::getInvisibleProperty($child, 'invalidProperty', 'getPublicProperty'));
121 |
122 | Util::setInvisibleProperty($child, 'publicProperty', 'public3', 'methodName');
123 | $this->assertSame('public3', Util::getInvisibleProperty($child, 'invalidProperty', 'getPublicProperty'));
124 | }
125 |
126 | public function testSetInvisiblePropertyByMethod()
127 | {
128 | $mother = new Mother();
129 | $child = new Child();
130 |
131 | Util::setInvisibleProperty($mother, 'invalidProperty', 'private2', 'setPrivateProperty');
132 | $this->assertSame('private2', Util::getInvisibleProperty($mother, 'invalidProperty', 'getPrivateProperty'));
133 |
134 | Util::setInvisibleProperty($child, 'invalidProperty', 'private2', 'setPrivateProperty');
135 | $this->assertSame('private2', Util::getInvisibleProperty($child, 'invalidProperty', 'getPrivateProperty'));
136 |
137 | Util::setInvisibleProperty($child, 'invalidProperty', 'protected2', 'setProtectedProperty');
138 | $this->assertSame('protected2', Util::getInvisibleProperty($child, 'invalidProperty', 'getProtectedProperty'));
139 |
140 | Util::setInvisibleProperty($mother, 'invalidProperty', 'public2', 'setPublicProperty');
141 | $this->assertSame('public2', Util::getInvisibleProperty($mother, 'invalidProperty', 'getPublicProperty'));
142 |
143 | Util::setInvisibleProperty($child, 'invalidProperty', 'public2', 'setPublicProperty');
144 | $this->assertSame('public2', Util::getInvisibleProperty($child, 'invalidProperty', 'getPublicProperty'));
145 | }
146 |
147 | public function testGetInvalidProperty()
148 | {
149 | $this->setExpectedException(
150 | 'PHPUnit\Runner\CleverAndSmart\Exception\PropertyReflectionException',
151 | 'Property "invalidProperty" does not exist in hierarchy PHPUnit\Runner\CleverAndSmart\Unit\Child < PHPUnit\Runner\CleverAndSmart\Unit\Mother'
152 | );
153 | Util::getInvisibleProperty(new Child(), 'invalidProperty');
154 | }
155 |
156 | public function testSetInvalidProperty()
157 | {
158 | $this->setExpectedException(
159 | 'PHPUnit\Runner\CleverAndSmart\Exception\PropertyReflectionException',
160 | 'Property "invalidProperty" does not exist in hierarchy PHPUnit\Runner\CleverAndSmart\Unit\Child < PHPUnit\Runner\CleverAndSmart\Unit\Mother'
161 | );
162 | Util::setInvisibleProperty(new Child(), 'invalidProperty', 'value');
163 | }
164 | }
165 |
--------------------------------------------------------------------------------