ÿØÿà JFIF    ÿÛ „  ( %"1!%)+...383,7(-.+  -+++--++++---+-+-----+---------------+---+-++7-----ÿÀ  ß â" ÿÄ     ÿÄ H    !1AQaq"‘¡2B±ÁÑð#R“Ò Tbr‚²á3csƒ’ÂñDS¢³$CÿÄ   ÿÄ %  !1AQa"23‘ÿÚ   ? ôÿ ¨pŸªáÿ —åYõõ\?àÒü©ŠÄï¨pŸªáÿ —åYõõ\?àÓü©ŠÄá 0Ÿªáÿ Ÿå[úƒ ú®ði~TÁbqÐ8OÕpÿ ƒOò¤Oè`–RÂáœá™êi€ßÉ< FtŸI“öÌ8úDf´°å}“¾œ6  öFá°y¥jñÇh†ˆ¢ã/ÃÐ:ªcÈ "Y¡ðÑl>ÿ ”ÏËte:qž\oäŠe÷󲍷˜HT4&ÿ ÓÐü6ö®¿øþßèô Ÿ•7Ñi’•j|“ñì>b…þS?*Óôÿ ÓÐü*h¥£ír¶ü UãS炟[AÐaè[ûª•õ&õj?†Éö+EzP—WeÒírJFt ‘BŒ†Ï‡%#tE Øz ¥OÛ«!1›üä±Í™%ºÍãö]°î(–:@<‹ŒÊö×òÆt¦ãº+‡¦%ÌÁ²h´OƒJŒtMÜ>ÀÜÊw3Y´•牋4ǍýʏTì>œú=Íwhyë,¾Ôò×õ¿ßÊa»«þˆѪQ|%6ž™A õ%:øj<>É—ÿ Å_ˆCbõ¥š±ý¯Ýƒï…¶|RëócÍf溪“t.СøTÿ *Ä¿-{†çàczůŽ_–^XþŒ±miB[X±d 1,é”zEù»& î9gœf™9Ð'.;—™i}!ôšåîqêÛ٤ёý£½ÆA–àôe"A$˝Úsäÿ ÷Û #°xŸëí(l »ý3—¥5m! rt`†0~'j2(]S¦¦kv,ÚÇ l¦øJA£Šƒ J3E8ÙiŽ:cÉžúeZ°€¯\®kÖ(79«Ž:¯X”¾³Š&¡* ….‰Ž(ÜíŸ2¥ª‡×Hi²TF¤ò[¨íÈRëÉ䢍mgÑ.Ÿ<öäS0í„ǹÁU´f#Vß;Õ–…P@3ío<ä-±»Ž.L|kªÀê›fÂ6@»eu‚|ÓaÞÆŸ…¨ááå>åŠ?cKü6ùTÍÆ”†sĤÚ;H2RÚ†õ\Ö·Ÿn'¾ ñ#ºI¤Å´%çÁ­‚â7›‹qT3Iï¨ÖÚ5I7Ë!ÅOóŸ¶øÝñØôת¦$Tcö‘[«Ö³šÒ';Aþ ¸èíg A2Z"i¸vdÄ÷.iõ®§)¿]¤À†–‡É&ä{V¶iŽ”.Ó×Õÿ û?h¬Mt–íª[ÿ Ñÿ ÌV(í}=ibÔ¡›¥¢±b Lô¥‡piη_Z<‡z§èŒ)iÖwiÇ 2hÙ3·=’d÷8éŽ1¦¸c¤µ€7›7Ø ð\á)} ¹fËí›pAÃL%âc2 í§æQz¿;T8sæ°qø)QFMð‰XŒÂ±N¢aF¨…8¯!U  Z©RÊ ÖPVÄÀÍin™Ì-GˆªÅËŠ›•zË}º±ŽÍFò¹}Uw×#ä5B¤{î}Ð<ÙD é©¤&‡ïDbàÁôMÁ.. namespace core; /** * Unit tests for the xhprof class. * * @package core * @category test * @copyright 2019 Brendan Heywood * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class xhprof_test extends \advanced_testcase { public static function setUpBeforeClass(): void { global $CFG; require_once($CFG->libdir . '/xhprof/xhprof_moodle.php'); } /** * Data provider for string matches * * @return array */ public static function profiling_string_matches_provider(): array { return [ ['/index.php', '/index.php', true], ['/some/dir/index.php', '/index.php', false], ['/course/view.php', '/course/view.php', true], ['/view.php', '/course/view.php', false], ['/mod/forum', '/mod/forum/*', false], ['/mod/forum/', '/mod/forum/*', true], ['/mod/forum/index.php', '/mod/forum/*', true], ['/mod/forum/foo.php', '/mod/forum/*', true], ['/mod/forum/view.php', '/mod/*/view.php', true], ['/mod/one/two/view.php', '/mod/*/view.php', true], ['/view.php', '*/view.php', true], ['/mod/one/two/view.php', '*/view.php', true], ['/foo.php', '/foo.php,/bar.php', true], ['/bar.php', '/foo.php,/bar.php', true], ['/foo/bar.php', "/foo.php,/bar.php", false], ['/foo/bar.php', "/foo.php,*/bar.php", true], ['/foo/bar.php', "/foo*.php,/bar.php", true], ['/foo.php', "/foo.php\n/bar.php", true], ['/bar.php', "/foo.php\n/bar.php", true], ['/foo/bar.php', "/foo.php\n/bar.php", false], ['/foo/bar.php', "/foo.php\n*/bar.php", true], ['/foo/bar.php', "/foo*.php\n/bar.php", true], ]; } /** * Test the matching syntax * * @covers ::profiling_string_matches * @dataProvider profiling_string_matches_provider * @param string $string * @param string $patterns * @param bool $expected */ public function test_profiling_string_matches($string, $patterns, $expected) { $result = profiling_string_matches($string, $patterns); $this->assertSame($result, $expected); } /** * Data provider for both the topological sort and the data reduction tests. * * @return array */ public static function run_data_provider(): array { // This data corresponds to the runs used as example @ MDL-79285. return [ 'sorted_case' => [ 'rundata' => array_flip([ 'A', 'A==>B', 'A==>C', 'A==>__Mustache4', 'B==>__Mustache1', '__Mustache1==>__Mustache2', '__Mustache4==>__Mustache2', '__Mustache4==>E', 'E==>F', 'C==>F', '__Mustache2==>F', '__Mustache2==>D', 'D==>__Mustache3', '__Mustache3==>F', ]), 'expectations' => [ 'topofirst' => 'A', 'topolast' => '__Mustache3==>F', 'topocount' => 14, 'topoorder' => [ // Before and after pairs to verify they are ordered. ['before' => 'A==>C', 'after' => 'C==>F'], ['before' => 'D==>__Mustache3', 'after' => '__Mustache3==>F'], ], 'reducecount' => 8, 'reduceremoved' => [ // Elements that will be removed by the reduction. '__Mustache1==>__Mustache2', '__Mustache4==>__Mustache2', '__Mustache2==>F', '__Mustache2==>D', '__Mustache2==>D', '__Mustache3==>F', ], ], ], 'unsorted_case' => [ 'rundata' => array_flip([ 'A==>__Mustache4', '__Mustache3==>F', 'A==>B', 'A==>C', 'B==>__Mustache1', '__Mustache1==>__Mustache2', '__Mustache4==>__Mustache2', '__Mustache4==>E', 'E==>F', 'C==>F', '__Mustache2==>F', '__Mustache2==>D', 'D==>__Mustache3', 'A', ]), 'expectations' => [ 'topofirst' => 'A', 'topolast' => '__Mustache3==>F', 'topocount' => 14, 'topoorder' => [ // Before and after pairs to verify they are ordered. ['before' => 'A==>C', 'after' => 'C==>F'], ['before' => 'D==>__Mustache3', 'after' => '__Mustache3==>F'], ], 'reducecount' => 8, 'reduceremoved' => [ // Elements that will be removed by the reduction. '__Mustache1==>__Mustache2', '__Mustache4==>__Mustache2', '__Mustache2==>F', '__Mustache2==>D', '__Mustache2==>D', '__Mustache3==>F', ], ], ], ]; } /** * Test that topologically sorting the run data works as expected * * @covers \moodle_xhprofrun::xhprof_topo_sort * @dataProvider run_data_provider * * @param array $rundata The run data to be sorted. * @param array $expectations The expected results. */ public function test_xhprof_topo_sort(array $rundata, array $expectations) { // Make sure all the examples in the provider are the same size. $this->assertSame($expectations['topocount'], count($rundata)); // Make moodle_xhprofrun::xhprof_topo_sort() accessible. $reflection = new \ReflectionClass('\moodle_xhprofrun'); $method = $reflection->getMethod('xhprof_topo_sort'); $method->setAccessible(true); // Sort the data. $result = $method->invokeArgs(new \moodle_xhprofrun(), [$rundata]); $this->assertIsArray($result); $this->assertSame($expectations['topocount'], count($result)); // Convert the array to a list of keys, so we can assert values by position. $resultkeys = array_keys($result); // This is the elements that should be first. $this->assertSame($expectations['topofirst'], $resultkeys[0]); // This is the element that should be last. $this->assertSame($expectations['topolast'], $resultkeys[$expectations['topocount'] - 1]); // This relative ordering should be respected. foreach ($expectations['topoorder'] as $order) { // All the elements in the expectations should be present. $this->assertArrayHasKey($order['before'], $result); $this->assertArrayHasKey($order['after'], $result); // And they should be in the correct relative order. $this->assertGreaterThan( array_search($order['before'], $resultkeys), array_search($order['after'], $resultkeys) ); } // Final check, if we sort it again, nothing changes (it's already topologically sorted). $result2 = $method->invokeArgs(new \moodle_xhprofrun(), [$result]); $this->assertSame($result, $result2); } /** * Test that reducing the data complexity works as expected * * @covers \moodle_xhprofrun::reduce_run_data * @dataProvider run_data_provider * * @param array $rundata The run data to be reduced. * @param array $expectations The expected results. */ public function test_reduce_run_data(array $rundata, array $expectations) { // Make sure that the expected keys that will be removed are present. foreach ($expectations['reduceremoved'] as $key) { $this->assertArrayHasKey($key, $rundata); } // Make moodle_xhprofrun::reduce_run_data() accessible. $reflection = new \ReflectionClass('\moodle_xhprofrun'); $method = $reflection->getMethod('reduce_run_data'); $method->setAccessible(true); // Reduce the data. $result = $method->invokeArgs(new \moodle_xhprofrun(), [$rundata]); $this->assertIsArray($result); $this->assertSame($expectations['reducecount'], count($result)); // These have been the removed elements. foreach ($expectations['reduceremoved'] as $key) { $this->assertArrayNotHasKey($key, $result); } // Final check, if we reduce it again, nothing changes (it's already reduced). $result2 = $method->invokeArgs(new \moodle_xhprofrun(), [$result]); $this->assertSame($result, $result2); } }