Merge "DateTimeInputWidget: Only show calendar when focusing date components, not...
[lhc/web/wiklou.git] / tests / phpunit / includes / libs / XhprofDataTest.php
1 <?php
2 /**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20
21 /**
22 * @uses XhprofData
23 * @uses AutoLoader
24 * @author Bryan Davis <bd808@wikimedia.org>
25 * @copyright © 2014 Bryan Davis and Wikimedia Foundation.
26 * @since 1.25
27 */
28 class XhprofDataTest extends PHPUnit_Framework_TestCase {
29
30 /**
31 * @covers XhprofData::splitKey
32 * @dataProvider provideSplitKey
33 */
34 public function testSplitKey( $key, $expect ) {
35 $this->assertSame( $expect, XhprofData::splitKey( $key ) );
36 }
37
38 public function provideSplitKey() {
39 return [
40 [ 'main()', [ null, 'main()' ] ],
41 [ 'foo==>bar', [ 'foo', 'bar' ] ],
42 [ 'bar@1==>bar@2', [ 'bar@1', 'bar@2' ] ],
43 [ 'foo==>bar==>baz', [ 'foo', 'bar==>baz' ] ],
44 [ '==>bar', [ '', 'bar' ] ],
45 [ '', [ null, '' ] ],
46 ];
47 }
48
49 /**
50 * @covers XhprofData::pruneData
51 */
52 public function testInclude() {
53 $xhprofData = $this->getXhprofDataFixture( [
54 'include' => [ 'main()' ],
55 ] );
56 $raw = $xhprofData->getRawData();
57 $this->assertArrayHasKey( 'main()', $raw );
58 $this->assertArrayHasKey( 'main()==>foo', $raw );
59 $this->assertArrayHasKey( 'main()==>xhprof_disable', $raw );
60 $this->assertSame( 3, count( $raw ) );
61 }
62
63 /**
64 * Validate the structure of data returned by
65 * Xhprof::getInclusiveMetrics(). This acts as a guard against unexpected
66 * structural changes to the returned data in lieu of using a more heavy
67 * weight typed response object.
68 *
69 * @covers XhprofData::getInclusiveMetrics
70 */
71 public function testInclusiveMetricsStructure() {
72 $metricStruct = [
73 'ct' => 'int',
74 'wt' => 'array',
75 'cpu' => 'array',
76 'mu' => 'array',
77 'pmu' => 'array',
78 ];
79 $statStruct = [
80 'total' => 'numeric',
81 'min' => 'numeric',
82 'mean' => 'numeric',
83 'max' => 'numeric',
84 'variance' => 'numeric',
85 'percent' => 'numeric',
86 ];
87
88 $xhprofData = $this->getXhprofDataFixture();
89 $metrics = $xhprofData->getInclusiveMetrics();
90
91 foreach ( $metrics as $name => $metric ) {
92 $this->assertArrayStructure( $metricStruct, $metric );
93
94 foreach ( $metricStruct as $key => $type ) {
95 if ( $type === 'array' ) {
96 $this->assertArrayStructure( $statStruct, $metric[$key] );
97 if ( $name === 'main()' ) {
98 $this->assertEquals( 100, $metric[$key]['percent'] );
99 }
100 }
101 }
102 }
103 }
104
105 /**
106 * Validate the structure of data returned by
107 * Xhprof::getCompleteMetrics(). This acts as a guard against unexpected
108 * structural changes to the returned data in lieu of using a more heavy
109 * weight typed response object.
110 *
111 * @covers XhprofData::getCompleteMetrics
112 */
113 public function testCompleteMetricsStructure() {
114 $metricStruct = [
115 'ct' => 'int',
116 'wt' => 'array',
117 'cpu' => 'array',
118 'mu' => 'array',
119 'pmu' => 'array',
120 'calls' => 'array',
121 'subcalls' => 'array',
122 ];
123 $statsMetrics = [ 'wt', 'cpu', 'mu', 'pmu' ];
124 $statStruct = [
125 'total' => 'numeric',
126 'min' => 'numeric',
127 'mean' => 'numeric',
128 'max' => 'numeric',
129 'variance' => 'numeric',
130 'percent' => 'numeric',
131 'exclusive' => 'numeric',
132 ];
133
134 $xhprofData = $this->getXhprofDataFixture();
135 $metrics = $xhprofData->getCompleteMetrics();
136
137 foreach ( $metrics as $name => $metric ) {
138 $this->assertArrayStructure( $metricStruct, $metric, $name );
139
140 foreach ( $metricStruct as $key => $type ) {
141 if ( in_array( $key, $statsMetrics ) ) {
142 $this->assertArrayStructure(
143 $statStruct, $metric[$key], $key
144 );
145 $this->assertLessThanOrEqual(
146 $metric[$key]['total'], $metric[$key]['exclusive']
147 );
148 }
149 }
150 }
151 }
152
153 /**
154 * @covers XhprofData::getCallers
155 * @covers XhprofData::getCallees
156 * @uses XhprofData
157 */
158 public function testEdges() {
159 $xhprofData = $this->getXhprofDataFixture();
160 $this->assertSame( [], $xhprofData->getCallers( 'main()' ) );
161 $this->assertSame( [ 'foo', 'xhprof_disable' ],
162 $xhprofData->getCallees( 'main()' )
163 );
164 $this->assertSame( [ 'main()' ],
165 $xhprofData->getCallers( 'foo' )
166 );
167 $this->assertSame( [], $xhprofData->getCallees( 'strlen' ) );
168 }
169
170 /**
171 * @covers XhprofData::getCriticalPath
172 * @uses XhprofData
173 */
174 public function testCriticalPath() {
175 $xhprofData = $this->getXhprofDataFixture();
176 $path = $xhprofData->getCriticalPath();
177
178 $last = null;
179 foreach ( $path as $key => $value ) {
180 list( $func, $call ) = XhprofData::splitKey( $key );
181 $this->assertSame( $last, $func );
182 $last = $call;
183 }
184 $this->assertSame( $last, 'bar@1' );
185 }
186
187 /**
188 * Get an Xhprof instance that has been primed with a set of known testing
189 * data. Tests for the Xhprof class should laregly be concerned with
190 * evaluating the manipulations of the data collected by xhprof rather
191 * than the data collection process itself.
192 *
193 * The returned Xhprof instance primed will be with a data set created by
194 * running this trivial program using the PECL xhprof implementation:
195 * @code
196 * function bar( $x ) {
197 * if ( $x > 0 ) {
198 * bar($x - 1);
199 * }
200 * }
201 * function foo() {
202 * for ( $idx = 0; $idx < 2; $idx++ ) {
203 * bar( $idx );
204 * $x = strlen( 'abc' );
205 * }
206 * }
207 * xhprof_enable( XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY );
208 * foo();
209 * $x = xhprof_disable();
210 * var_export( $x );
211 * @endcode
212 *
213 * @return Xhprof
214 */
215 protected function getXhprofDataFixture( array $opts = [] ) {
216 return new XhprofData( [
217 'foo==>bar' => [
218 'ct' => 2,
219 'wt' => 57,
220 'cpu' => 92,
221 'mu' => 1896,
222 'pmu' => 0,
223 ],
224 'foo==>strlen' => [
225 'ct' => 2,
226 'wt' => 21,
227 'cpu' => 141,
228 'mu' => 752,
229 'pmu' => 0,
230 ],
231 'bar==>bar@1' => [
232 'ct' => 1,
233 'wt' => 18,
234 'cpu' => 19,
235 'mu' => 752,
236 'pmu' => 0,
237 ],
238 'main()==>foo' => [
239 'ct' => 1,
240 'wt' => 304,
241 'cpu' => 307,
242 'mu' => 4008,
243 'pmu' => 0,
244 ],
245 'main()==>xhprof_disable' => [
246 'ct' => 1,
247 'wt' => 8,
248 'cpu' => 10,
249 'mu' => 768,
250 'pmu' => 392,
251 ],
252 'main()' => [
253 'ct' => 1,
254 'wt' => 353,
255 'cpu' => 351,
256 'mu' => 6112,
257 'pmu' => 1424,
258 ],
259 ], $opts );
260 }
261
262 /**
263 * Assert that the given array has the described structure.
264 *
265 * @param array $struct Array of key => type mappings
266 * @param array $actual Array to check
267 * @param string $label
268 */
269 protected function assertArrayStructure( $struct, $actual, $label = null ) {
270 $this->assertInternalType( 'array', $actual, $label );
271 $this->assertCount( count( $struct ), $actual, $label );
272 foreach ( $struct as $key => $type ) {
273 $this->assertArrayHasKey( $key, $actual );
274 $this->assertInternalType( $type, $actual[$key] );
275 }
276 }
277 }