4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 * http://www.gnu.org/copyleft/gpl.html
25 * @author Bryan Davis <bd808@wikimedia.org>
26 * @copyright © 2014 Bryan Davis and Wikimedia Foundation.
29 class XhprofTest
extends PHPUnit_Framework_TestCase
{
31 public function setUp() {
32 if ( !function_exists( 'xhprof_enable' ) ) {
33 $this->markTestSkipped( 'No xhprof support detected.' );
38 * @covers Xhprof::splitKey
39 * @dataProvider provideSplitKey
41 public function testSplitKey( $key, $expect ) {
42 $this->assertSame( $expect, Xhprof
::splitKey( $key ) );
45 public function provideSplitKey() {
47 array( 'main()', array( null, 'main()' ) ),
48 array( 'foo==>bar', array( 'foo', 'bar' ) ),
49 array( 'bar@1==>bar@2', array( 'bar@1', 'bar@2' ) ),
50 array( 'foo==>bar==>baz', array( 'foo', 'bar==>baz' ) ),
51 array( '==>bar', array( '', 'bar' ) ),
52 array( '', array( null, '' ) ),
57 * @covers Xhprof::__construct
58 * @covers Xhprof::stop
59 * @covers Xhprof::getRawData
60 * @dataProvider provideRawData
62 public function testRawData( $flags, $keys ) {
63 $xhprof = new Xhprof( array( 'flags' => $flags ) );
64 $raw = $xhprof->getRawData();
65 $this->assertArrayHasKey( 'main()', $raw );
66 foreach ( $keys as $key ) {
67 $this->assertArrayHasKey( $key, $raw['main()'] );
71 public function provideRawData() {
73 array( 0, array( 'ct', 'wt' ) ),
74 array( XHPROF_FLAGS_MEMORY
, array( 'ct', 'wt', 'mu', 'pmu' ) ),
75 array( XHPROF_FLAGS_CPU
, array( 'ct', 'wt', 'cpu' ) ),
76 array( XHPROF_FLAGS_MEMORY | XHPROF_FLAGS_CPU
, array(
77 'ct', 'wt', 'mu', 'pmu', 'cpu',
83 * @covers Xhprof::pruneData
85 public function testInclude() {
86 $xhprof = $this->getXhprofFixture( array(
87 'include' => array( 'main()' ),
89 $raw = $xhprof->getRawData();
90 $this->assertArrayHasKey( 'main()', $raw );
91 $this->assertArrayHasKey( 'main()==>foo', $raw );
92 $this->assertArrayHasKey( 'main()==>xhprof_disable', $raw );
93 $this->assertSame( 3, count( $raw ) );
97 * Validate the structure of data returned by
98 * Xhprof::getInclusiveMetrics(). This acts as a guard against unexpected
99 * structural changes to the returned data in lieu of using a more heavy
100 * weight typed response object.
102 * @covers Xhprof::getInclusiveMetrics
104 public function testInclusiveMetricsStructure() {
105 $metricStruct = array(
113 'total' => 'numeric',
117 'variance' => 'numeric',
118 'percent' => 'numeric',
121 $xhprof = $this->getXhprofFixture();
122 $metrics = $xhprof->getInclusiveMetrics();
124 foreach ( $metrics as $name => $metric ) {
125 $this->assertArrayStructure( $metricStruct, $metric );
127 foreach ( $metricStruct as $key => $type ) {
128 if ( $type === 'array' ) {
129 $this->assertArrayStructure( $statStruct, $metric[$key] );
130 if ( $name === 'main()' ) {
131 $this->assertEquals( 100, $metric[$key]['percent'] );
139 * Validate the structure of data returned by
140 * Xhprof::getCompleteMetrics(). This acts as a guard against unexpected
141 * structural changes to the returned data in lieu of using a more heavy
142 * weight typed response object.
144 * @covers Xhprof::getCompleteMetrics
146 public function testCompleteMetricsStructure() {
147 $metricStruct = array(
154 'subcalls' => 'array',
156 $statsMetrics = array( 'wt', 'cpu', 'mu', 'pmu' );
158 'total' => 'numeric',
162 'variance' => 'numeric',
163 'percent' => 'numeric',
164 'exclusive' => 'numeric',
167 $xhprof = $this->getXhprofFixture();
168 $metrics = $xhprof->getCompleteMetrics();
170 foreach ( $metrics as $name => $metric ) {
171 $this->assertArrayStructure( $metricStruct, $metric, $name );
173 foreach ( $metricStruct as $key => $type ) {
174 if ( in_array( $key, $statsMetrics ) ) {
175 $this->assertArrayStructure(
176 $statStruct, $metric[$key], $key
178 $this->assertLessThanOrEqual(
179 $metric[$key]['total'], $metric[$key]['exclusive']
187 * @covers Xhprof::getCallers
188 * @covers Xhprof::getCallees
191 public function testEdges() {
192 $xhprof = $this->getXhprofFixture();
193 $this->assertSame( array(), $xhprof->getCallers( 'main()' ) );
194 $this->assertSame( array( 'foo', 'xhprof_disable' ),
195 $xhprof->getCallees( 'main()' )
197 $this->assertSame( array( 'main()' ),
198 $xhprof->getCallers( 'foo' )
200 $this->assertSame( array(), $xhprof->getCallees( 'strlen' ) );
204 * @covers Xhprof::getCriticalPath
207 public function testCriticalPath() {
208 $xhprof = $this->getXhprofFixture();
209 $path = $xhprof->getCriticalPath();
212 foreach ( $path as $key => $value ) {
213 list( $func, $call ) = Xhprof
::splitKey( $key );
214 $this->assertSame( $last, $func );
217 $this->assertSame( $last, 'bar@1' );
221 * Get an Xhprof instance that has been primed with a set of known testing
222 * data. Tests for the Xhprof class should laregly be concerned with
223 * evaluating the manipulations of the data collected by xhprof rather
224 * than the data collection process itself.
226 * The returned Xhprof instance primed will be with a data set created by
227 * running this trivial program using the PECL xhprof implementation:
229 * function bar( $x ) {
235 * for ( $idx = 0; $idx < 2; $idx++ ) {
237 * $x = strlen( 'abc' );
240 * xhprof_enable( XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY );
242 * $x = xhprof_disable();
248 protected function getXhprofFixture( array $opts = array() ) {
249 $xhprof = new Xhprof( $opts );
250 $xhprof->loadRawData( array (
251 'foo==>bar' => array (
258 'foo==>strlen' => array (
265 'bar==>bar@1' => array (
272 'main()==>foo' => array (
279 'main()==>xhprof_disable' => array (
298 * Assert that the given array has the described structure.
300 * @param array $struct Array of key => type mappings
301 * @param array $actual Array to check
302 * @param string $label
304 protected function assertArrayStructure( $struct, $actual, $label = null ) {
305 $this->assertInternalType( 'array', $actual, $label );
306 $this->assertCount( count($struct), $actual, $label );
307 foreach ( $struct as $key => $type ) {
308 $this->assertArrayHasKey( $key, $actual );
309 $this->assertInternalType( $type, $actual[$key] );