@@ -25,13 +25,22 @@ class TestHandler
2525 /** @var Runner */
2626 private $ runner ;
2727
28+ /** @var string|null */
29+ private $ tempDir ;
30+
2831
2932 public function __construct (Runner $ runner )
3033 {
3134 $ this ->runner = $ runner ;
3235 }
3336
3437
38+ public function setTempDirectory (?string $ path ): void
39+ {
40+ $ this ->tempDir = $ path ;
41+ }
42+
43+
3544 public function initiate (string $ file ): void
3645 {
3746 [$ annotations , $ title ] = $ this ->getAnnotations ($ file );
@@ -157,28 +166,59 @@ private function initiateMultiple(Test $test, $count): array
157166
158167 private function initiateTestCase (Test $ test , $ foo , PhpInterpreter $ interpreter )
159168 {
160- $ job = new Job ($ test ->withArguments (['method ' => TestCase::LIST_METHODS ]), $ interpreter , $ this ->runner ->getEnvironmentVariables ());
161- $ job ->run ();
162-
163- if (in_array ($ job ->getExitCode (), [Job::CODE_ERROR , Job::CODE_FAIL , Job::CODE_SKIP ], true )) {
164- return $ test ->withResult ($ job ->getExitCode () === Job::CODE_SKIP ? Test::SKIPPED : Test::FAILED , $ job ->getTest ()->stdout );
169+ $ methods = null ;
170+
171+ if ($ this ->tempDir ) {
172+ $ cacheFile = $ this ->tempDir . DIRECTORY_SEPARATOR . 'TestHandler.testCase. ' . substr (md5 ($ test ->getSignature ()), 0 , 5 ) . '.list ' ;
173+ if (is_file ($ cacheFile )) {
174+ $ cache = unserialize (file_get_contents ($ cacheFile ));
175+
176+ $ valid = true ;
177+ foreach ($ cache ['files ' ] as $ path => $ mTime ) {
178+ if (!is_file ($ path ) || filemtime ($ path ) !== $ mTime ) {
179+ $ valid = false ;
180+ break ;
181+ }
182+ }
183+ if ($ valid ) {
184+ $ methods = $ cache ['methods ' ];
185+ }
186+ }
165187 }
166188
167- $ stdout = $ job ->getTest ()->stdout ;
189+ if ($ methods === null ) {
190+ $ job = new Job ($ test ->withArguments (['method ' => TestCase::LIST_METHODS ]), $ interpreter , $ this ->runner ->getEnvironmentVariables ());
191+ $ job ->run ();
168192
169- if (!preg_match ('#^TestCase:([^\n]+)$#m ' , $ stdout , $ m )) {
170- return $ test ->withResult (Test::FAILED , "Cannot list TestCase methods in file ' {$ test ->getFile ()}'. Do you call TestCase::run() in it? " );
171- }
172- $ testCaseClass = $ m [1 ];
193+ if (in_array ($ job ->getExitCode (), [Job::CODE_ERROR , Job::CODE_FAIL , Job::CODE_SKIP ], true )) {
194+ return $ test ->withResult ($ job ->getExitCode () === Job::CODE_SKIP ? Test::SKIPPED : Test::FAILED , $ job ->getTest ()->stdout );
195+ }
196+
197+ $ stdout = $ job ->getTest ()->stdout ;
173198
174- preg_match_all ('#^Method:([^\n]+)$#m ' , $ stdout , $ m );
175- if (count ($ m [1 ]) < 1 ) {
176- return $ test ->withResult (Test::SKIPPED , "Class $ testCaseClass in file ' {$ test ->getFile ()}' does not contain test methods. " );
199+ if (!preg_match ('#^TestCase:([^\n]+)$#m ' , $ stdout , $ m )) {
200+ return $ test ->withResult (Test::FAILED , "Cannot list TestCase methods in file ' {$ test ->getFile ()}'. Do you call TestCase::run() in it? " );
201+ }
202+ $ testCaseClass = $ m [1 ];
203+
204+ preg_match_all ('#^Method:([^\n]+)$#m ' , $ stdout , $ m );
205+ if (count ($ m [1 ]) < 1 ) {
206+ return $ test ->withResult (Test::SKIPPED , "Class $ testCaseClass in file ' {$ test ->getFile ()}' does not contain test methods. " );
207+ }
208+ $ methods = $ m [1 ];
209+
210+ if ($ this ->tempDir ) {
211+ preg_match_all ('#^Dependency:([^\n]+)$#m ' , $ stdout , $ m );
212+ file_put_contents ($ cacheFile , serialize ([
213+ 'methods ' => $ methods ,
214+ 'files ' => array_combine ($ m [1 ], array_map ('filemtime ' , $ m [1 ])),
215+ ]));
216+ }
177217 }
178218
179219 return array_map (function (string $ method ) use ($ test ): Test {
180220 return $ test ->withArguments (['method ' => $ method ]);
181- }, $ m [ 1 ] );
221+ }, $ methods );
182222 }
183223
184224
0 commit comments