public $functionHooks = [];
public $transparentHooks = [];
- // Fuzz test
- public $maxFuzzTestLength = 300;
- public $fuzzSeed = 0;
- public $memoryLimit = 50;
-
/**
* @var DjVuSupport
*/
if ( $this->regex != '' && !preg_match( '/' . $this->regex . '/', $desc ) ) {
$this->assertTrue( true ); // XXX: don't flood output with "test made no assertions"
// $this->markTestSkipped( 'Filtered out by the user' );
+ $this->teardownGlobals();
return;
}
// parser tests frequently assume that the main namespace contains wikitext.
// @todo When setting up pages, force the content model. Only skip if
// $wgtContentModelUseDB is false.
+ $this->teardownGlobals();
$this->markTestSkipped( "Main namespace does not support wikitext,"
. "skipping parser test: $desc" );
}
global $wgTexvc;
if ( !isset( $wgTexvc ) ) {
+ $this->teardownGlobals();
$this->markTestSkipped( "SKIPPED: \$wgTexvc is not set" );
} elseif ( !is_executable( $wgTexvc ) ) {
+ $this->teardownGlobals();
$this->markTestSkipped( "SKIPPED: texvc binary does not exist"
. " or is not executable.\n"
. "Current configuration is:\n\$wgTexvc = '$wgTexvc'" );
if ( isset( $opts['djvu'] ) ) {
if ( !$this->djVuSupport->isEnabled() ) {
+ $this->teardownGlobals();
$this->markTestSkipped( "SKIPPED: djvu binaries do not exist or are not executable.\n" );
}
}
if ( isset( $opts['tidy'] ) ) {
if ( !$this->tidySupport->isEnabled() ) {
+ $this->teardownGlobals();
$this->markTestSkipped( "SKIPPED: tidy extension is not installed.\n" );
} else {
$options->setTidy( true );
$this->assertEquals( $result, $out, $desc );
}
- /**
- * Run a fuzz test series
- * Draw input from a set of test files
- *
- * @todo fixme Needs some work to not eat memory until the world explodes
- *
- * @group ParserFuzz
- */
- public function testFuzzTests() {
- global $wgParserTestFiles;
-
- $files = $wgParserTestFiles;
-
- if ( $this->getCliArg( 'file' ) ) {
- $files = [ $this->getCliArg( 'file' ) ];
- }
-
- $dict = $this->getFuzzInput( $files );
- $dictSize = strlen( $dict );
- $logMaxLength = log( $this->maxFuzzTestLength );
-
- ini_set( 'memory_limit', $this->memoryLimit * 1048576 );
-
- $user = new User;
- $opts = ParserOptions::newFromUser( $user );
- $title = Title::makeTitle( NS_MAIN, 'Parser_test' );
-
- $id = 1;
-
- while ( true ) {
-
- // Generate test input
- mt_srand( ++$this->fuzzSeed );
- $totalLength = mt_rand( 1, $this->maxFuzzTestLength );
- $input = '';
-
- while ( strlen( $input ) < $totalLength ) {
- $logHairLength = mt_rand( 0, 1000000 ) / 1000000 * $logMaxLength;
- $hairLength = min( intval( exp( $logHairLength ) ), $dictSize );
- $offset = mt_rand( 0, $dictSize - $hairLength );
- $input .= substr( $dict, $offset, $hairLength );
- }
-
- $this->setupGlobals();
- $parser = $this->getParser();
-
- // Run the test
- try {
- $parser->parse( $input, $title, $opts );
- $this->assertTrue( true, "Test $id, fuzz seed {$this->fuzzSeed}" );
- } catch ( Exception $exception ) {
- $input_dump = sprintf( "string(%d) \"%s\"\n", strlen( $input ), $input );
-
- $this->assertTrue( false, "Test $id, fuzz seed {$this->fuzzSeed}. \n\n" .
- "Input: $input_dump\n\nError: {$exception->getMessage()}\n\n" .
- "Backtrace: {$exception->getTraceAsString()}" );
- }
-
- $this->teardownGlobals();
- $parser->__destruct();
-
- if ( $id % 100 == 0 ) {
- $usage = intval( memory_get_usage( true ) / $this->memoryLimit / 1048576 * 100 );
- // echo "{$this->fuzzSeed}: $numSuccess/$numTotal (mem: $usage%)\n";
- if ( $usage > 90 ) {
- $ret = "Out of memory:\n";
- $memStats = $this->getMemoryBreakdown();
-
- foreach ( $memStats as $name => $usage ) {
- $ret .= "$name: $usage\n";
- }
-
- throw new MWException( $ret );
- }
- }
-
- $id++;
- }
- }
-
- // Various getter functions
-
- /**
- * Get an input dictionary from a set of parser test files
- * @param array $filenames
- * @return string
- */
- function getFuzzInput( $filenames ) {
- $dict = '';
-
- foreach ( $filenames as $filename ) {
- $contents = file_get_contents( $filename );
- preg_match_all( '/!!\s*input\n(.*?)\n!!\s*result/s', $contents, $matches );
-
- foreach ( $matches[1] as $match ) {
- $dict .= $match . "\n";
- }
- }
-
- return $dict;
- }
-
- /**
- * Get a memory usage breakdown
- * @return array
- */
- function getMemoryBreakdown() {
- $memStats = [];
-
- foreach ( $GLOBALS as $name => $value ) {
- $memStats['$' . $name] = strlen( serialize( $value ) );
- }
-
- $classes = get_declared_classes();
-
- foreach ( $classes as $class ) {
- $rc = new ReflectionClass( $class );
- $props = $rc->getStaticProperties();
- $memStats[$class] = strlen( serialize( $props ) );
- $methods = $rc->getMethods();
-
- foreach ( $methods as $method ) {
- $memStats[$class] += strlen( serialize( $method->getStaticVariables() ) );
- }
- }
-
- $functions = get_defined_functions();
-
- foreach ( $functions['user'] as $function ) {
- $rf = new ReflectionFunction( $function );
- $memStats["$function()"] = strlen( serialize( $rf->getStaticVariables() ) );
- }
-
- asort( $memStats );
-
- return $memStats;
- }
-
/**
* Get a Parser object
* @param Preprocessor $preprocessor