1<?php
2/*
3 * This file is part of PHPUnit.
4 *
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11class PHPUnit_Util_TestDox_ResultPrinter_XML extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener
12{
13    /**
14     * @var DOMDocument
15     */
16    private $document;
17
18    /**
19     * @var DOMElement
20     */
21    private $root;
22
23    /**
24     * @var PHPUnit_Util_TestDox_NamePrettifier
25     */
26    private $prettifier;
27
28    /**
29     * @var Exception
30     */
31    private $exception;
32
33    /**
34     * @param string|resource $out
35     */
36    public function __construct($out = null)
37    {
38        $this->document               = new DOMDocument('1.0', 'UTF-8');
39        $this->document->formatOutput = true;
40
41        $this->root = $this->document->createElement('tests');
42        $this->document->appendChild($this->root);
43
44        $this->prettifier = new PHPUnit_Util_TestDox_NamePrettifier;
45
46        parent::__construct($out);
47    }
48
49    /**
50     * Flush buffer and close output.
51     */
52    public function flush()
53    {
54        $this->write($this->document->saveXML());
55
56        parent::flush();
57    }
58
59    /**
60     * An error occurred.
61     *
62     * @param PHPUnit_Framework_Test $test
63     * @param Exception              $e
64     * @param float                  $time
65     */
66    public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
67    {
68        $this->exception = $e;
69    }
70
71    /**
72     * A warning occurred.
73     *
74     * @param PHPUnit_Framework_Test    $test
75     * @param PHPUnit_Framework_Warning $e
76     * @param float                     $time
77     */
78    public function addWarning(PHPUnit_Framework_Test $test, PHPUnit_Framework_Warning $e, $time)
79    {
80    }
81
82    /**
83     * A failure occurred.
84     *
85     * @param PHPUnit_Framework_Test                 $test
86     * @param PHPUnit_Framework_AssertionFailedError $e
87     * @param float                                  $time
88     */
89    public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
90    {
91        $this->exception = $e;
92    }
93
94    /**
95     * Incomplete test.
96     *
97     * @param PHPUnit_Framework_Test $test
98     * @param Exception              $e
99     * @param float                  $time
100     */
101    public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
102    {
103    }
104
105    /**
106     * Risky test.
107     *
108     * @param PHPUnit_Framework_Test $test
109     * @param Exception              $e
110     * @param float                  $time
111     */
112    public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time)
113    {
114    }
115
116    /**
117     * Skipped test.
118     *
119     * @param PHPUnit_Framework_Test $test
120     * @param Exception              $e
121     * @param float                  $time
122     */
123    public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
124    {
125    }
126
127    /**
128     * A test suite started.
129     *
130     * @param PHPUnit_Framework_TestSuite $suite
131     */
132    public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
133    {
134    }
135
136    /**
137     * A test suite ended.
138     *
139     * @param PHPUnit_Framework_TestSuite $suite
140     */
141    public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
142    {
143    }
144
145    /**
146     * A test started.
147     *
148     * @param PHPUnit_Framework_Test $test
149     */
150    public function startTest(PHPUnit_Framework_Test $test)
151    {
152        $this->exception = null;
153    }
154
155    /**
156     * A test ended.
157     *
158     * @param PHPUnit_Framework_Test $test
159     * @param float                  $time
160     */
161    public function endTest(PHPUnit_Framework_Test $test, $time)
162    {
163        if (!$test instanceof PHPUnit_Framework_TestCase) {
164            return;
165        }
166
167        /* @var PHPUnit_Framework_TestCase $test */
168
169        $groups = array_filter(
170            $test->getGroups(),
171            function ($group) {
172                if ($group == 'small' || $group == 'medium' || $group == 'large') {
173                    return false;
174                }
175
176                return true;
177            }
178        );
179
180        $node = $this->document->createElement('test');
181
182        $node->setAttribute('className', get_class($test));
183        $node->setAttribute('methodName', $test->getName());
184        $node->setAttribute('prettifiedClassName', $this->prettifier->prettifyTestClass(get_class($test)));
185        $node->setAttribute('prettifiedMethodName', $this->prettifier->prettifyTestMethod($test->getName()));
186        $node->setAttribute('status', $test->getStatus());
187        $node->setAttribute('time', $time);
188        $node->setAttribute('size', $test->getSize());
189        $node->setAttribute('groups', implode(',', $groups));
190
191        $inlineAnnotations = PHPUnit_Util_Test::getInlineAnnotations(get_class($test), $test->getName());
192
193        if (isset($inlineAnnotations['given']) && isset($inlineAnnotations['when']) && isset($inlineAnnotations['then'])) {
194            $node->setAttribute('given', $inlineAnnotations['given']['value']);
195            $node->setAttribute('givenStartLine', $inlineAnnotations['given']['line']);
196            $node->setAttribute('when', $inlineAnnotations['when']['value']);
197            $node->setAttribute('whenStartLine', $inlineAnnotations['when']['line']);
198            $node->setAttribute('then', $inlineAnnotations['then']['value']);
199            $node->setAttribute('thenStartLine', $inlineAnnotations['then']['line']);
200        }
201
202        if ($this->exception !== null) {
203            if ($this->exception instanceof PHPUnit_Framework_Exception) {
204                $steps = $this->exception->getSerializableTrace();
205            } else {
206                $steps = $this->exception->getTrace();
207            }
208
209            $class = new ReflectionClass($test);
210            $file  = $class->getFileName();
211
212            foreach ($steps as $step) {
213                if (isset($step['file']) && $step['file'] == $file) {
214                    $node->setAttribute('exceptionLine', $step['line']);
215
216                    break;
217                }
218            }
219
220            $node->setAttribute('exceptionMessage', $this->exception->getMessage());
221        }
222
223        $this->root->appendChild($node);
224    }
225}
226