Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * $Id: PHPUnitTask.php 427 2008-10-28 19:34:15Z mrook $
4
 *
5
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
 *
17
 * This software consists of voluntary contributions made by many individuals
18
 * and is licensed under the LGPL. For more information please see
19
 * <http://phing.info>.
20
 */
21
 
22
require_once 'phing/Task.php';
23
require_once 'phing/system/io/PhingFile.php';
24
require_once 'phing/system/io/Writer.php';
25
require_once 'phing/util/LogWriter.php';
26
 
27
/**
28
 * Runs PHPUnit2/3 tests.
29
 *
30
 * @author Michiel Rook <michiel.rook@gmail.com>
31
 * @version $Id: PHPUnitTask.php 427 2008-10-28 19:34:15Z mrook $
32
 * @package phing.tasks.ext.phpunit
33
 * @see BatchTest
34
 * @since 2.1.0
35
 */
36
class PHPUnitTask extends Task
37
{
38
	private $batchtests = array();
39
	private $formatters = array();
40
	private $haltonerror = false;
41
	private $haltonfailure = false;
42
	private $haltonincomplete = false;
43
	private $haltonskipped = false;
44
	private $errorproperty;
45
	private $failureproperty;
46
	private $incompleteproperty;
47
	private $skippedproperty;
48
	private $printsummary = false;
49
	private $testfailed = false;
50
	private $codecoverage = false;
51
	private $groups = array();
52
	private $excludeGroups = array();
53
 
54
	/**
55
	 * Initialize Task.
56
 	 * This method includes any necessary PHPUnit2 libraries and triggers
57
	 * appropriate error if they cannot be found.  This is not done in header
58
	 * because we may want this class to be loaded w/o triggering an error.
59
	 */
60
	function init() {
61
		if (version_compare(PHP_VERSION, '5.0.3') < 0) {
62
		    throw new BuildException("PHPUnit2Task requires PHP version >= 5.0.3.", $this->getLocation());
63
		}
64
 
65
		/**
66
		 * Determine PHPUnit version number
67
		 */
68
		@include_once 'PHPUnit/Runner/Version.php';
69
		@include_once 'PHPUnit2/Runner/Version.php';
70
 
71
		if (class_exists('PHPUnit_Runner_Version'))
72
		{
73
			$version = PHPUnit_Runner_Version::id();
74
		}
75
		elseif (class_exists('PHPUnit2_Runner_Version'))
76
		{
77
			$version = PHPUnit2_Runner_Version::id();
78
		}
79
		else
80
		{
81
			throw new BuildException("PHPUnit task depends on PHPUnit 2 or 3 package being installed.", $this->getLocation());
82
		}
83
 
84
		if (version_compare($version, "3.0.0") >= 0)
85
		{
86
			PHPUnitUtil::$installedVersion = 3;
87
			if (version_compare($version, "3.2.0") >= 0)
88
			{
89
				PHPUnitUtil::$installedMinorVersion = 2;
90
			}
91
		}
92
		else
93
		{
94
			PHPUnitUtil::$installedVersion = 2;
95
		}
96
 
97
		/**
98
		 * Other dependencies that should only be loaded when class is actually used.
99
		 */
100
		require_once 'phing/tasks/ext/phpunit/PHPUnitTestRunner.php';
101
		require_once 'phing/tasks/ext/phpunit/BatchTest.php';
102
		require_once 'phing/tasks/ext/phpunit/FormatterElement.php';
103
 
104
		/**
105
		 * Add some defaults to the PHPUnit filter
106
		 */
107
		$pwd = dirname(__FILE__);
108
 
109
		if (PHPUnitUtil::$installedVersion == 3)
110
		{
111
			require_once 'PHPUnit/Framework.php';
112
			require_once 'PHPUnit/Util/Filter.php';
113
 
114
			// point PHPUnit_MAIN_METHOD define to non-existing method
115
			if (!defined('PHPUnit_MAIN_METHOD')) {
116
				define('PHPUnit_MAIN_METHOD', 'PHPUnitTask::undefined');
117
			}
118
 
119
			PHPUnit_Util_Filter::addFileToFilter($pwd . '/PHPUnitTask.php', 'PHING');
120
			PHPUnit_Util_Filter::addFileToFilter($pwd . '/PHPUnitTestRunner.php', 'PHING');
121
			PHPUnit_Util_Filter::addFileToFilter($pwd . '/../../../Task.php', 'PHING');
122
			PHPUnit_Util_Filter::addFileToFilter($pwd . '/../../../Target.php', 'PHING');
123
			PHPUnit_Util_Filter::addFileToFilter($pwd . '/../../../Project.php', 'PHING');
124
			PHPUnit_Util_Filter::addFileToFilter($pwd . '/../../../Phing.php', 'PHING');
125
		}
126
		else
127
		{
128
			require_once 'PHPUnit2/Framework.php';
129
			require_once 'PHPUnit2/Util/Filter.php';
130
 
131
			PHPUnit2_Util_Filter::addFileToFilter($pwd . '/PHPUnitTask.php');
132
			PHPUnit2_Util_Filter::addFileToFilter($pwd . '/PHPUnitTestRunner.php');
133
			PHPUnit2_Util_Filter::addFileToFilter($pwd . '/../../../Task.php');
134
			PHPUnit2_Util_Filter::addFileToFilter($pwd . '/../../../Target.php');
135
			PHPUnit2_Util_Filter::addFileToFilter($pwd . '/../../../Project.php');
136
			PHPUnit2_Util_Filter::addFileToFilter($pwd . '/../../../Phing.php');
137
		}
138
	}
139
 
140
	function setErrorproperty($value)
141
	{
142
		$this->errorproperty = $value;
143
	}
144
 
145
	function setFailureproperty($value)
146
	{
147
		$this->failureproperty = $value;
148
	}
149
 
150
	function setIncompleteproperty($value)
151
	{
152
		$this->incompleteproperty = $value;
153
	}
154
 
155
	function setSkippedproperty($value)
156
	{
157
		$this->skippedproperty = $value;
158
	}
159
 
160
	function setHaltonerror($value)
161
	{
162
		$this->haltonerror = $value;
163
	}
164
 
165
	function setHaltonfailure($value)
166
	{
167
		$this->haltonfailure = $value;
168
	}
169
 
170
	function setHaltonincomplete($value)
171
	{
172
		$this->haltonincomplete = $value;
173
	}
174
 
175
	function setHaltonskipped($value)
176
	{
177
		$this->haltonskipped = $value;
178
	}
179
 
180
	function setPrintsummary($printsummary)
181
	{
182
		$this->printsummary = $printsummary;
183
	}
184
 
185
	function setCodecoverage($codecoverage)
186
	{
187
		$this->codecoverage = $codecoverage;
188
	}
189
 
190
	function setGroups($groups)
191
	{
192
		if (PHPUnitUtil::$installedVersion < 3 || (PHPUnitUtil::$installedVersion == 3 && PHPUnitUtil::$installedMinorVersion < 2))
193
		{
194
			$this->log("The 'groups' attribute is only available with PHPUnit 3.2.0 or newer", Project::MSG_WARN);
195
		}
196
		$token = ' ,;';
197
		$this->groups = array();
198
		$tok = strtok($groups, $token);
199
		while ($tok !== false) {
200
			$this->groups[] = $tok;
201
			$tok = strtok($token);
202
		}
203
	}
204
 
205
	function setExcludeGroups($excludeGroups)
206
	{
207
		if (PHPUnitUtil::$installedVersion < 3 || (PHPUnitUtil::$installedVersion == 3 && PHPUnitUtil::$installedMinorVersion < 2))
208
		{
209
			$this->log("The 'excludeGroups' attribute is only available with PHPUnit 3.2.0 or newer", Project::MSG_WARN);
210
		}
211
		$token = ' ,;';
212
		$this->excludeGroups = array();
213
		$tok = strtok($groups, $token);
214
		while ($tok !== false) {
215
			$this->excludeGroups[] = $tok;
216
			$tok = strtok($token);
217
		}
218
	}
219
 
220
	/**
221
	 * Add a new formatter to all tests of this task.
222
	 *
223
	 * @param FormatterElement formatter element
224
	 */
225
	function addFormatter(FormatterElement $fe)
226
	{
227
		$this->formatters[] = $fe;
228
	}
229
 
230
	/**
231
	 * The main entry point
232
	 *
233
	 * @throws BuildException
234
	 */
235
	function main()
236
	{
237
		$tests = array();
238
 
239
		if ($this->printsummary)
240
		{
241
			$fe = new FormatterElement();
242
			$fe->setType("summary");
243
			$fe->setUseFile(false);
244
			$this->formatters[] = $fe;
245
		}
246
 
247
		foreach ($this->batchtests as $batchtest)
248
		{
249
			$tests = array_merge($tests, $batchtest->elements());
250
		}
251
 
252
		foreach ($this->formatters as $fe)
253
		{
254
			$formatter = $fe->getFormatter();
255
			$formatter->setProject($this->getProject());
256
 
257
			if ($fe->getUseFile())
258
			{
259
				$destFile = new PhingFile($fe->getToDir(), $fe->getOutfile());
260
 
261
				$writer = new FileWriter($destFile->getAbsolutePath());
262
 
263
				$formatter->setOutput($writer);
264
			}
265
			else
266
			{
267
				$formatter->setOutput($this->getDefaultOutput());
268
			}
269
 
270
			$formatter->startTestRun();
271
		}
272
 
273
		foreach ($tests as $test)
274
		{
275
			$suite = NULL;
276
 
277
			if ((PHPUnitUtil::$installedVersion == 3 && is_subclass_of($test, 'PHPUnit_Framework_TestSuite')) || (PHPUnitUtil::$installedVersion == 2 && is_subclass_of($test, 'PHPUnit2_Framework_TestSuite')))
278
			{
279
				if (is_object($test))
280
				{
281
					$suite = $test;
282
				}
283
				else
284
				{
285
					$suite = new $test();
286
				}
287
			}
288
			else
289
			{
290
				if (PHPUnitUtil::$installedVersion == 3)
291
				{
292
					require_once 'PHPUnit/Framework/TestSuite.php';
293
					$suite = new PHPUnit_Framework_TestSuite(new ReflectionClass($test));
294
				}
295
				else
296
				{
297
					require_once 'PHPUnit2/Framework/TestSuite.php';
298
					$suite = new PHPUnit2_Framework_TestSuite(new ReflectionClass($test));
299
				}
300
			}
301
 
302
			$this->execute($suite);
303
		}
304
 
305
		foreach ($this->formatters as $fe)
306
		{
307
			$formatter = $fe->getFormatter();
308
			$formatter->endTestRun();
309
		}
310
 
311
		if ($this->testfailed)
312
		{
313
			throw new BuildException("One or more tests failed");
314
		}
315
	}
316
 
317
	/**
318
	 * @throws BuildException
319
	 */
320
	private function execute($suite)
321
	{
322
		$runner = new PHPUnitTestRunner($suite, $this->project, $this->groups, $this->excludeGroups);
323
 
324
		$runner->setCodecoverage($this->codecoverage);
325
 
326
		foreach ($this->formatters as $fe)
327
		{
328
			$formatter = $fe->getFormatter();
329
 
330
			$runner->addFormatter($formatter);
331
		}
332
 
333
		$runner->run();
334
 
335
		$retcode = $runner->getRetCode();
336
 
337
		if ($retcode == PHPUnitTestRunner::ERRORS) {
338
		    if ($this->errorproperty) {
339
				$this->project->setNewProperty($this->errorproperty, true);
340
			}
341
			if ($this->haltonerror) {
342
			    $this->testfailed = true;
343
			}
344
		} elseif ($retcode == PHPUnitTestRunner::FAILURES) {
345
			if ($this->failureproperty) {
346
				$this->project->setNewProperty($this->failureproperty, true);
347
			}
348
 
349
			if ($this->haltonfailure) {
350
				$this->testfailed = true;
351
			}
352
		} elseif ($retcode == PHPUnitTestRunner::INCOMPLETES) {
353
			if ($this->incompleteproperty) {
354
				$this->project->setNewProperty($this->incompleteproperty, true);
355
			}
356
 
357
			if ($this->haltonincomplete) {
358
				$this->testfailed = true;
359
			}
360
		} elseif ($retcode == PHPUnitTestRunner::SKIPPED) {
361
			if ($this->skippedproperty) {
362
				$this->project->setNewProperty($this->skippedproperty, true);
363
			}
364
 
365
			if ($this->haltonskipped) {
366
				$this->testfailed = true;
367
			}
368
		}
369
	}
370
 
371
	private function getDefaultOutput()
372
	{
373
		return new LogWriter($this);
374
	}
375
 
376
	/**
377
	 * Adds a set of tests based on pattern matching.
378
	 *
379
	 * @return BatchTest a new instance of a batch test.
380
	 */
381
	function createBatchTest()
382
	{
383
		$batchtest = new BatchTest($this->getProject());
384
 
385
		$this->batchtests[] = $batchtest;
386
 
387
		return $batchtest;
388
	}
389
}
390