1 : <?php
2 : /**
3 : * Dictionaries of Old French and Latin
4 : *
5 : * PHP version 5
6 : *
7 : * @category DicFro
8 : * @package Tests
9 : * @author Michel Corne <mcorne@yahoo.com>
10 : * @copyright 2010 Michel Corne
11 : * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
12 : * @version SVN: $Id$
13 : */
14 :
15 : /**
16 : * Tests filter
17 : *
18 : * @category DicFro
19 : * @package Tests
20 : * @author Michel Corne <mcorne@yahoo.com>
21 : * @copyright 2010 Michel Corne
22 : * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
23 : */
24 :
25 : class Filter
26 : {
27 : /**
28 : * The name of the file updated each time the test is run
29 : */
30 : const LAST_TEST_RUN = 'last-test-run.php';
31 :
32 : /**
33 : * The name of the file containing the class list and their dependencies
34 : */
35 : const DEPENDENCIES = 'Dependencies.php';
36 :
37 : /**
38 : * The class list and their dependencies
39 : * @var array
40 : */
41 : protected $dependencies = array();
42 :
43 : /**
44 : * The name of the application directory
45 : * @var string
46 : */
47 : protected $applicationDir;
48 :
49 : /**
50 : * The name of the application test directory
51 : * @var string
52 : */
53 : protected $applicationTestDir;
54 :
55 : /**
56 : * The full name of the file updated each time the test is run
57 : * @var string
58 : */
59 : protected $lastTestRunFile;
60 :
61 : /**
62 : * Constructor
63 : *
64 : * @param string $applicationDir the name of the application directory
65 : * @param string $applicationTestDir the name of the application test directory
66 : * @return void
67 : */
68 : public function __construct($applicationDir, $applicationTestDir)
69 : {
70 0 : $this->applicationDir = $applicationDir;
71 0 : $this->applicationTestDir = $applicationTestDir;
72 :
73 0 : $this->dependencies = include dirname(__FILE__) . '/' . self::DEPENDENCIES;
74 0 : $this->lastTestRunFile = dirname(__FILE__) . '/' . self::LAST_TEST_RUN;
75 0 : }
76 :
77 : /**
78 : * Determines the last update time of a file or its dependencies
79 : *
80 : * @param string $file the file name
81 : * @return array the last update time
82 : */
83 : public function getFileTime($file)
84 : {
85 0 : static $times = array();
86 :
87 0 : if (!isset($times[$file])) {
88 0 : $times[$file] = filemtime($this->applicationDir . $file);
89 0 : $dependencyTime = 0;
90 :
91 0 : foreach($this->dependencies[$file] as $dependency) {
92 0 : $dependencyTime = $this->getFileTime($dependency);
93 0 : }
94 :
95 0 : $times[$file] = max($dependencyTime, $times[$file]);
96 : }
97 :
98 0 : return $times[$file];
99 : }
100 :
101 : /**
102 : * Completes the list of dependencies
103 : *
104 : * @return void
105 : */
106 : public function completeDependencies()
107 : {
108 0 : foreach($this->dependencies as $details) {
109 0 : foreach($details as $dependency) {
110 0 : isset($this->dependencies[$dependency]) or $this->dependencies[$dependency] = array();
111 0 : }
112 0 : }
113 0 : }
114 :
115 : /**
116 : * Removes a file from the list of dependencies
117 : *
118 : * @param string $file the file name
119 : * @param array $dependencies the list of dependencies
120 : * @return array the updated list of dependencies
121 : */
122 : public function removeDependencies($file, $dependencies)
123 : {
124 : // removes the file from all dependent files
125 0 : foreach($dependencies as &$dependency) {
126 0 : unset($dependency[$file]);
127 0 : }
128 :
129 : // removes the file from the dependency list
130 0 : unset($dependencies[$file]);
131 :
132 0 : return $dependencies;
133 : }
134 :
135 : /**
136 : * Finds the tests to run
137 : *
138 : * A test is run if the test file, or the class file, or one of its dependencies
139 : * was updated since the last run.
140 : *
141 : * @param bool $runAllTests all tests are run if true, or run as needed if false
142 : * @return array the list of tests to run
143 : */
144 : public function findTests($runAllTests)
145 : {
146 0 : $this->completeDependencies();
147 :
148 0 : $dependencies = array_map('array_flip', $this->dependencies);
149 :
150 0 : $lastRunTime = file_exists($this->lastTestRunFile)?
151 0 : filemtime($this->lastTestRunFile) : time();
152 :
153 0 : $tests = array();
154 0 : $recentFiles = array();
155 :
156 0 : while(count($dependencies)) {
157 0 : $count = array_map('count', $dependencies);
158 0 : asort($count);
159 :
160 0 : $file = key($count);
161 0 : $dependencies = $this->removeDependencies($file, $dependencies);
162 :
163 0 : ($runAllTests or $this->getFileTime($file) > $lastRunTime or
164 0 : array_intersect($this->dependencies[$file], $recentFiles)) and
165 0 : $recentFiles[] = $file;
166 :
167 0 : if (pathinfo($file, PATHINFO_EXTENSION) == 'php') {
168 0 : $testFile = $this->applicationTestDir . str_replace('.php', 'Test.php', $file);
169 0 : file_exists($testFile) and
170 0 : (filemtime($testFile) > $lastRunTime or in_array($file, $recentFiles)) and
171 0 : $tests[] = $testFile;
172 : }
173 0 : }
174 :
175 : // stores the list of tests to run
176 0 : $content = var_export($tests, true);
177 0 : file_put_contents($this->lastTestRunFile, "<?php return $content;");
178 :
179 0 : return $tests;
180 : }
181 :
182 : /**
183 : * Finds the tests to run
184 : *
185 : * @param string $applicationDir the name of the application directory
186 : * @param string $applicationTestDir the name of the application test directory
187 : */
188 : public static function listTestFiles($applicationDir, $applicationTestDir)
189 : {
190 0 : $filter = new Filter($applicationDir, $applicationTestDir);
191 :
192 0 : $runAllTests = getenv('RUN_ALL_TESTS');
193 0 : if ($runAllTests === false) {
194 : // the directive is not set, returns the last test set
195 0 : $tests = file_exists($filter->lastTestRunFile)? include $filter->lastTestRunFile : array();
196 : } else {
197 : // the directive is set, finds the test to run
198 0 : $tests = $filter->findTests($runAllTests);
199 : }
200 :
201 0 : return $tests;
202 : }
203 : }
|