0) { ob_end_clean(); } }); afterEach(function () { while (ob_get_level() > 0) { ob_end_clean(); } }); describe('clean()', function () { it('cleans buffer and returns content', function () { $handle = OutputBuffer::start(); echo "Test content"; $content = $handle->clean(); expect($content)->toBe("Test content"); expect(ob_get_level())->toBe(0); }); it('throws exception if buffer level mismatch', function () { $handle = OutputBuffer::start(); ob_start(); // Create additional buffer expect(fn() => $handle->clean()) ->toThrow(OutputBufferException::class); ob_end_clean(); $handle->end(); }); }); describe('end()', function () { it('ends buffer without returning content', function () { $handle = OutputBuffer::start(); echo "Test content"; $handle->end(); expect(ob_get_level())->toBe(0); }); it('validates buffer level before ending', function () { $handle = OutputBuffer::start(); $handle->end(); expect(fn() => $handle->end()) ->toThrow(OutputBufferException::class); }); }); describe('flush()', function () { it('flushes buffer contents', function () { $handle = OutputBuffer::start(); echo "Test"; // Flush should work (though output goes nowhere in tests) expect(fn() => $handle->flush())->not->toThrow(Exception::class); $handle->end(); }); }); describe('getContents()', function () { it('gets contents without clearing buffer', function () { $handle = OutputBuffer::start(); echo "Test"; $content = $handle->getContents(); expect($content)->toBe("Test"); expect($handle->isActive())->toBeTrue(); $handle->end(); }); it('can be called multiple times', function () { $handle = OutputBuffer::start(); echo "Test"; $content1 = $handle->getContents(); echo " More"; $content2 = $handle->getContents(); expect($content1)->toBe("Test"); expect($content2)->toBe("Test More"); $handle->end(); }); }); describe('getLength()', function () { it('returns buffer content length', function () { $handle = OutputBuffer::start(); expect($handle->getLength())->toBe(0); echo "Test"; expect($handle->getLength())->toBe(4); echo "ing"; expect($handle->getLength())->toBe(7); $handle->end(); }); }); describe('isActive()', function () { it('returns true when buffer is active', function () { $handle = OutputBuffer::start(); expect($handle->isActive())->toBeTrue(); $handle->end(); }); it('returns false after buffer is cleaned', function () { $handle = OutputBuffer::start(); $handle->end(); expect($handle->isActive())->toBeFalse(); }); }); describe('level validation', function () { it('validates buffer level for all operations', function () { $handle = OutputBuffer::start(); $handle->end(); // All operations should fail after buffer is ended expect(fn() => $handle->clean())->toThrow(OutputBufferException::class); expect(fn() => $handle->getContents())->toThrow(OutputBufferException::class); expect(fn() => $handle->flush())->toThrow(OutputBufferException::class); }); it('detects level mismatch', function () { $handle1 = OutputBuffer::start(); $handle2 = OutputBuffer::start(); // Try to clean handle1 while handle2 is active expect(fn() => $handle1->clean()) ->toThrow(OutputBufferException::class); $handle2->end(); $handle1->end(); }); }); });