1]); $GLOBALS['post'] = $previousPost; $GLOBALS['id'] = 1; $GLOBALS['authordata'] = 'previous-author'; $GLOBALS['pages'] = ['previous']; $GLOBALS['page'] = 1; $GLOBALS['more'] = 1; $GLOBALS['numpages'] = 1; $GLOBALS['multipage'] = 0; $post = new WP_Post(['ID' => 7, 'post_content' => '']); $setup = []; Functions\when('setup_postdata')->alias(static function (WP_Post $p) use (&$setup): bool { $setup[] = $p->ID; $GLOBALS['id'] = $p->ID; $GLOBALS['authordata'] = 'author-of-' . $p->ID; $GLOBALS['pages'] = ['page-of-' . $p->ID]; $GLOBALS['page'] = 2; $GLOBALS['more'] = 0; $GLOBALS['numpages'] = 3; $GLOBALS['multipage'] = 1; return true; }); Filters\expectApplied('the_content')->once()->with('')->andReturnUsing( static function () use ($post): string { echo '
echoed
'; return $GLOBALS['post'] === $post ? '' : 'wrong post'; } ); $html = (new PageRenderer())->render($post); self::assertSame('echoed
', $html); self::assertSame([7], $setup); self::assertSame($previousPost, $GLOBALS['post']); self::assertSame(1, $GLOBALS['id']); self::assertSame('previous-author', $GLOBALS['authordata']); self::assertSame(['previous'], $GLOBALS['pages']); self::assertSame(1, $GLOBALS['page']); self::assertSame(1, $GLOBALS['more']); self::assertSame(1, $GLOBALS['numpages']); self::assertSame(0, $GLOBALS['multipage']); } public function testRestoresEvenWhenRenderingThrows(): void { Functions\when('setup_postdata')->justReturn(true); Filters\expectApplied('the_content')->once()->andReturnUsing(static function (): string { throw new RuntimeException('module crashed'); }); try { (new PageRenderer())->render(new WP_Post(['ID' => 7])); self::fail('exception expected'); } catch (RuntimeException) { self::assertArrayHasKey('post', $GLOBALS); self::assertNull($GLOBALS['post']); foreach (self::POSTDATA_GLOBALS as $name) { self::assertArrayHasKey($name, $GLOBALS); self::assertNull($GLOBALS[$name]); } } } public function testDrainsAnExtraOutputBufferAShortcodeLeavesOpen(): void { Functions\when('setup_postdata')->justReturn(true); Filters\expectApplied('the_content')->once()->andReturnUsing(static function (): string { echo 'before-'; ob_start(); // a buggy shortcode opens a buffer and never closes it echo 'leaked'; return 'html'; }); $levelBefore = ob_get_level(); $html = (new PageRenderer())->render(new WP_Post(['ID' => 7])); self::assertSame('before-leakedhtml', $html); self::assertSame($levelBefore, ob_get_level()); } public function testToleratesAShortcodeThatClosesOneOutputBufferTooMany(): void { Functions\when('setup_postdata')->justReturn(true); Filters\expectApplied('the_content')->once()->andReturnUsing(static function (): string { ob_start(); // shortcode's own nested buffer echo 'own'; ob_end_clean(); // correct: closes its own buffer ob_end_clean(); // bug: also closes PageRenderer's buffer return 'html'; }); $levelBefore = ob_get_level(); $html = (new PageRenderer())->render(new WP_Post(['ID' => 7])); self::assertSame('html', $html); self::assertSame($levelBefore, ob_get_level()); } }