mageekguy\atoum\reports\asynchronous\xunit: lines coverage

84% of 922

OPs

99% of 138

Lines

64% of 89

Branches

0% of 4109

Paths
Method OPs OPs % Lines Line % Branches Branches % Paths Path %
mageekguy\atoum\reports\asynchronous\xunit::__construct() 35 97% 6 100% 4 50% 2 100%
mageekguy\atoum\reports\asynchronous\xunit::handleEvent() 82 100% 16 100% 10 100% 6 50%
mageekguy\atoum\reports\asynchronous\xunit::getTestedClasses() 95 100% 33 100% 1 100% 1 100%
mageekguy\atoum\reports\asynchronous\xunit::build() 594 77% 66 100% 66 59% 4096 0%
mageekguy\atoum\reports\asynchronous\xunit::getTestCase() 75 100% 11 100% 4 75% 2 50%
mageekguy\atoum\reports\asynchronous\xunit::findTestCase() 41 80% 6 83% 4 50% 2 50%
#
1
<?php
2

                    
3
namespace mageekguy\atoum\reports\asynchronous;
4

                    
5
use
6
	mageekguy\atoum,
7
	mageekguy\atoum\exceptions,
8
	mageekguy\atoum\report\fields
9
;
10

                    
11
class xunit extends atoum\reports\asynchronous
12
{
13
	const defaultTitle = 'atoum testsuite';
14

                    
15
	protected $score = null;
16
	protected $assertions = array();
17

                    
18
	public function __construct(atoum\adapter $adapter = null)100%
19
	{
20
		parent::__construct();
21

                    
22
		$this->setAdapter($adapter);
23

                    
24
		if ($this->adapter->extension_loaded('libxml') === false)
25
		{
26
			throw new exceptions\runtime('libxml PHP extension is mandatory for xunit report');
27
		}
28
	}
29

                    
30
	public function handleEvent($event, atoum\observable $observable)100%
31
	{
32
		$this->score = null;
33

                    
34
		if ($event === atoum\test::afterTestMethod)
35
		{
36
			$classname = $this->adapter->get_class($observable);
37
			$method = $observable->getCurrentMethod();
38

                    
39
			if (isset($this->assertions[$classname]) === false)
40
			{
41
				$this->assertions[$classname] = array();
42
			}
43

                    
44
			$this->assertions[$classname][$method] = $observable->getScore()->getAssertionNumber() - array_sum($this->assertions[$classname]);
45
		}
46

                    
47
		if ($event === atoum\runner::runStop)
48
		{
49
			$this->score = $observable->getScore();
50
		}
51

                    
52
		return parent::handleEvent($event, $observable);
53
	}
54

                    
55
	protected function getTestedClasses()100%
56
	{
57
		$durations = $this->score->getDurations();
58
		$errors = $this->score->getErrors();
59
		$excepts = $this->score->getExceptions();
60
		$fails = $this->score->getFailAssertions();
61
		$uncomplete = $this->score->getUncompletedMethods();
62
		$skipped = $this->score->getSkippedMethods();
63
		$assertions = $this->assertions;
64

                    
65
		$filterClass = function($element) use (& $clname) { return ($element['class'] == $clname); };
66
		$extractClasses = function($list) use (& $clname, & $classes, & $assertions, $durations, $errors, $excepts, $fails, $uncomplete, $skipped, $filterClass) {
67
			foreach ($list as $entry)
68
			{
69
				$clname = ltrim($entry['class'], '\\');
70

                    
71
				if (isset($classes[$clname]) === false)
72
				{
73
					$classes[$clname] = array(
74
						'errors' => array_filter($errors, $filterClass),
75
						'excepts' => array_filter($excepts, $filterClass),
76
						'fails' => array_filter($fails, $filterClass),
77
						'durations' => array_filter($durations, $filterClass),
78
						'uncomplete' => array_filter($uncomplete, $filterClass),
79
						'skipped' => array_filter($skipped, $filterClass),
80
						'assertions' => isset($assertions[$clname]) ? $assertions[$clname] : array()
81
					);
82
				}
83
			}
84
		};
85

                    
86
		$classes = array();
87
		$extractClasses($durations);
88
		$extractClasses($errors);
89
		$extractClasses($excepts);
90
		$extractClasses($fails);
91
		$extractClasses($uncomplete);
92
		$extractClasses($skipped);
93

                    
94
		return $classes;
95
	}
96

                    
97
	public function build($event)100%
98
	{
99
		$this->string = '';
100

                    
101
		if ($event === atoum\runner::runStop)
102
		{
103
			$this->title = $this->title ?: self::defaultTitle;
104

                    
105
			$document = new \DOMDocument('1.0', 'UTF-8');
106
			$document->formatOutput = true;
107
			$document->appendChild($root = $document->createElement('testsuites'));
108
			$root->setAttribute('name', $this->title);
109
			$classes = $this->getTestedClasses();
110

                    
111
			foreach ($classes as $name => $class)
112
			{
113
				$clname = $package = $name;
114
				$antiSlashOffset = strrpos($clname, '\\');
115
				if ($antiSlashOffset !== false)
116
				{
117
					$clname = substr($clname, $antiSlashOffset + 1);
118
					$package = substr($name, 0, $antiSlashOffset);
119
				}
120

                    
121
				$root->appendChild($testSuite = $document->createElement('testsuite'));
122

                    
123
				$testSuite->setAttribute('name', $clname);
124
				$testSuite->setAttribute('package', $package);
125
				$testSuite->setAttribute('tests', sizeof($class['durations']) + ($fails = sizeof($class['fails'])) + ($errors = sizeof($class['excepts']) + sizeof($class['errors']) + sizeof($class['uncomplete'])) + sizeof($class['skipped']));
126
				$testSuite->setAttribute('failures', $fails);
127
				$testSuite->setAttribute('errors', $errors);
128
				$testSuite->setAttribute('skipped', sizeof($class['skipped']));
129

                    
130
				$time = 0;
131
				foreach ($class['durations'] as $duration)
132
				{
133
					$time += $duration['value'];
134

                    
135
					self::getTestCase($document, $testSuite, $name, $duration['method'], $duration['value'], $duration['path'], isset($class['assertions'][$duration['method']]) ? $class['assertions'][$duration['method']] : 0);
136
				}
137

                    
138
				$testSuite->setAttribute('time', $time);
139

                    
140
				foreach ($class['errors'] as $error)
141
				{
142
					$testCase = self::getTestCase($document, $testSuite, $name, $error['method'], 0, $error['file'], isset($class['assertions'][$error['method']]) ? $class['assertions'][$error['method']] : 0);
143
					$testCase->appendChild($xError = $document->createElement('error'));
144

                    
145
					$xError->setAttribute('type', $error['type']);
146
					$xError->appendChild($document->createCDATASection($error['message']));
147
				}
148

                    
149
				foreach ($class['uncomplete'] as $uncomplete)
150
				{
151
					$testCase = self::getTestCase($document, $testSuite, $name, $uncomplete['method'], 0, null, isset($class['assertions'][$uncomplete['method']]) ? $class['assertions'][$uncomplete['method']] : 0);
152
					$testCase->appendChild($xFail = $document->createElement('error'));
153

                    
154
					$xFail->setAttribute('type', $uncomplete['exitCode']);
155
					$xFail->appendChild($document->createCDATASection($uncomplete['output']));
156
				}
157

                    
158
				foreach ($class['fails'] as $fail)
159
				{
160
					$testCase = self::getTestCase($document, $testSuite, $name, $fail['method'], 0, $fail['file'], isset($class['assertions'][$fail['method']]) ? $class['assertions'][$fail['method']] : 0);
161
					$testCase->appendChild($xFail = $document->createElement('failure'));
162

                    
163
					$xFail->setAttribute('type', 'Failure');
164
					$xFail->setAttribute('message', $fail['asserter']);
165

                    
166
					$xFail->appendChild($document->createCDATASection($fail['fail']));
167
				}
168

                    
169
				foreach ($class['excepts'] as $exc)
170
				{
171
					$testCase = self::getTestCase($document, $testSuite, $name, $exc['method'], 0, $exc['file'], isset($class['assertions'][$exc['method']]) ? $class['assertions'][$exc['method']] : 0);
172
					$testCase->appendChild($xError = $document->createElement('error'));
173

                    
174
					$xError->setAttribute('type', 'Exception');
175
					$xError->appendChild($document->createCDATASection($exc['value']));
176
				}
177

                    
178
				foreach ($class['skipped'] as $skipped)
179
				{
180
					$testCase = self::getTestCase($document, $testSuite, $name, $skipped['method'], 0, null, isset($class['assertions'][$skipped['method']]) ? $class['assertions'][$skipped['method']] : 0);
181
					$testCase->appendChild($xFail = $document->createElement('skipped'));
182

                    
183
					$xFail->setAttribute('type', 'Skipped');
184

                    
185
					$xFail->appendChild($document->createCDATASection($skipped['message']));
186
				}
187
			}
188

                    
189
			$this->string = $document->saveXML();
190
		}
191

                    
192
		return $this;
193
	}
194

                    
195
	private static function getTestCase(\DOMDocument $document, \DOMElement $testSuite, $class, $method, $time, $path, $assertions)100%
196
	{
197
		if (($testCase = self::findTestCase($document, $class, $method)) === null)
198
		{
199
			$testCase = $document->createElement('testcase');
200
			$testCase->setAttribute('name', $method);
201
			$testCase->setIdAttribute('name', true);
202
			$testCase->setAttribute('time', $time);
203
			$testCase->setAttribute('classname', $class);
204
			$testCase->setAttribute('assertions', $assertions);
205

                    
206
			$testSuite->appendChild($testCase);
207
		}
208

                    
209
		return $testCase;
210
	}
211

                    
212
	private static function findTestCase(\DOMDocument $document, $class, $method)83%
213
	{
214
		$xpath = new \DOMXPath($document);
215
		$query = $xpath->query("//testcase[@classname='$class' and @name='$method']");
216

                    
217
		if ($query->length > 0)
218
		{
219
			return $query->item(0);
220
		}
221

                    
222
		return null;
223
	}
224
}