Files
michaelschiemer/tests/Unit/Framework/OutputBuffer/OutputBufferTest.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

272 lines
8.2 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\OutputBuffer\OutputBuffer;
use App\Framework\OutputBuffer\OutputBufferConfig;
use App\Framework\OutputBuffer\OutputBufferException;
use App\Framework\OutputBuffer\OutputBufferFlag;
use App\Framework\OutputBuffer\OutputBufferFlags;
use App\Framework\OutputBuffer\CapturedOutput;
describe('OutputBuffer', function () {
beforeEach(function () {
// Ensure clean state
while (ob_get_level() > 0) {
ob_end_clean();
}
});
afterEach(function () {
// Cleanup after tests
while (ob_get_level() > 0) {
ob_end_clean();
}
});
describe('capture()', function () {
it('captures output from callback', function () {
$captured = OutputBuffer::capture(function () {
echo "Hello World";
return 42;
});
expect($captured)->toBeInstanceOf(CapturedOutput::class);
expect($captured->content)->toBe("Hello World");
expect($captured->result)->toBe(42);
});
it('captures empty output', function () {
$captured = OutputBuffer::capture(function () {
return "result";
});
expect($captured->content)->toBe("");
expect($captured->result)->toBe("result");
expect($captured->isEmpty())->toBeTrue();
});
it('captures multiline output', function () {
$captured = OutputBuffer::capture(function () {
echo "Line 1\n";
echo "Line 2\n";
echo "Line 3";
});
expect($captured->content)->toBe("Line 1\nLine 2\nLine 3");
expect($captured->lineCount())->toBe(3);
expect($captured->lines())->toBe(['Line 1', 'Line 2', 'Line 3']);
});
it('cleans up buffer on success', function () {
$levelBefore = ob_get_level();
OutputBuffer::capture(function () {
echo "test";
});
expect(ob_get_level())->toBe($levelBefore);
});
it('cleans up buffer on exception', function () {
$levelBefore = ob_get_level();
try {
OutputBuffer::capture(function () {
echo "test";
throw new RuntimeException('Test exception');
});
} catch (RuntimeException $e) {
// Expected exception
}
expect(ob_get_level())->toBe($levelBefore);
});
it('supports custom configuration', function () {
$callbackExecuted = false;
$config = OutputBufferConfig::withCallback(function (string $buffer) use (&$callbackExecuted) {
$callbackExecuted = true;
return strtoupper($buffer);
});
$captured = OutputBuffer::capture(function () {
echo "hello";
}, $config);
expect($callbackExecuted)->toBeTrue();
expect($captured->content)->toBe("HELLO");
});
it('handles nested captures', function () {
$captured1 = OutputBuffer::capture(function () {
echo "Outer Start\n";
$captured2 = OutputBuffer::capture(function () {
echo "Inner";
return "inner-result";
});
echo $captured2->content . " processed\n";
echo "Outer End";
return "outer-result";
});
expect($captured1->content)->toBe("Outer Start\nInner processed\nOuter End");
expect($captured1->result)->toBe("outer-result");
});
});
describe('start()', function () {
it('starts new buffer and returns handle', function () {
$levelBefore = ob_get_level();
$handle = OutputBuffer::start();
expect(ob_get_level())->toBe($levelBefore + 1);
expect($handle->level)->toBe($levelBefore + 1);
expect($handle->isActive())->toBeTrue();
$handle->end();
});
it('allows manual buffer management', function () {
$handle = OutputBuffer::start();
echo "Test output";
$content = $handle->clean();
expect($content)->toBe("Test output");
expect(ob_get_level())->toBe(0);
});
it('supports custom configuration', function () {
$config = OutputBufferConfig::forCapture();
$handle = OutputBuffer::start($config);
expect($handle->config)->toBe($config);
$handle->end();
});
});
describe('getCurrentLevel()', function () {
it('returns current buffer level', function () {
expect(OutputBuffer::getCurrentLevel())->toBe(0);
ob_start();
expect(OutputBuffer::getCurrentLevel())->toBe(1);
ob_start();
expect(OutputBuffer::getCurrentLevel())->toBe(2);
ob_end_clean();
ob_end_clean();
});
});
describe('isActive()', function () {
it('returns false when no buffers active', function () {
expect(OutputBuffer::isActive())->toBeFalse();
});
it('returns true when buffer is active', function () {
ob_start();
expect(OutputBuffer::isActive())->toBeTrue();
ob_end_clean();
});
});
describe('cleanAll()', function () {
it('cleans all active buffers', function () {
ob_start();
ob_start();
ob_start();
expect(ob_get_level())->toBe(3);
$count = OutputBuffer::cleanAll();
expect($count)->toBe(3);
expect(ob_get_level())->toBe(0);
});
it('returns 0 when no buffers active', function () {
$count = OutputBuffer::cleanAll();
expect($count)->toBe(0);
});
});
describe('getStatus()', function () {
it('returns status of all buffers', function () {
$status = OutputBuffer::getStatus();
expect($status)->toBeArray();
});
it('shows buffer information when active', function () {
ob_start();
$status = OutputBuffer::getStatus();
expect($status)->toBeArray();
expect($status)->toHaveCount(1);
ob_end_clean();
});
});
describe('withoutBuffering()', function () {
it('executes callback without buffering', function () {
$executedWithoutBuffer = false;
OutputBuffer::capture(function () use (&$executedWithoutBuffer) {
OutputBuffer::withoutBuffering(function () use (&$executedWithoutBuffer) {
$executedWithoutBuffer = ob_get_level() === 0;
});
});
expect($executedWithoutBuffer)->toBeTrue();
});
it('restores buffers after callback', function () {
$captured = OutputBuffer::capture(function () {
echo "Before";
OutputBuffer::withoutBuffering(function () {
// This output should not be captured
echo "During";
});
echo "After";
});
expect($captured->content)->toBe("BeforeAfter");
});
it('returns callback result', function () {
$result = OutputBuffer::withoutBuffering(function () {
return 42;
});
expect($result)->toBe(42);
});
});
describe('exception handling', function () {
it('throws exception when capture fails', function () {
// This is hard to test as ob_start rarely fails
// but we test the exception exists
expect(OutputBufferException::failedToCapture())
->toBeInstanceOf(OutputBufferException::class);
});
it('propagates callback exceptions', function () {
expect(function () {
OutputBuffer::capture(function () {
throw new RuntimeException('Test');
});
})->toThrow(RuntimeException::class);
});
});
});