Files
framework/tests/PipelineTest.php
2026-01-06 12:44:28 +08:00

352 lines
9.7 KiB
PHP

<?php
namespace think\tests;
use Closure;
use Exception;
use PHPUnit\Framework\TestCase;
use think\Pipeline;
class PipelineTest extends TestCase
{
protected $pipeline;
protected function setUp(): void
{
$this->pipeline = new Pipeline();
}
public function testSend()
{
$data = 'test data';
$result = $this->pipeline->send($data);
$this->assertSame($this->pipeline, $result);
}
public function testThroughWithArray()
{
$pipes = [
function ($passable, $next) {
return $next($passable . ' pipe1');
},
function ($passable, $next) {
return $next($passable . ' pipe2');
}
];
$result = $this->pipeline->through($pipes);
$this->assertSame($this->pipeline, $result);
}
public function testThroughWithArguments()
{
$pipe1 = function ($passable, $next) {
return $next($passable . ' pipe1');
};
$pipe2 = function ($passable, $next) {
return $next($passable . ' pipe2');
};
$result = $this->pipeline->through($pipe1, $pipe2);
$this->assertSame($this->pipeline, $result);
}
public function testThenExecutesPipeline()
{
$pipes = [
function ($passable, $next) {
return $next($passable . ' pipe1');
},
function ($passable, $next) {
return $next($passable . ' pipe2');
}
];
$destination = function ($passable) {
return $passable . ' destination';
};
$result = $this->pipeline
->send('start')
->through($pipes)
->then($destination);
$this->assertEquals('start pipe1 pipe2 destination', $result);
}
public function testPipelineExecutesInCorrectOrder()
{
$order = [];
$pipes = [
function ($passable, $next) use (&$order) {
$order[] = 'pipe1_before';
$result = $next($passable);
$order[] = 'pipe1_after';
return $result;
},
function ($passable, $next) use (&$order) {
$order[] = 'pipe2_before';
$result = $next($passable);
$order[] = 'pipe2_after';
return $result;
}
];
$destination = function ($passable) use (&$order) {
$order[] = 'destination';
return $passable;
};
$this->pipeline
->send('test')
->through($pipes)
->then($destination);
$expected = ['pipe1_before', 'pipe2_before', 'destination', 'pipe2_after', 'pipe1_after'];
$this->assertEquals($expected, $order);
}
public function testEmptyPipelineExecutesDestination()
{
$destination = function ($passable) {
return $passable . ' processed';
};
$result = $this->pipeline
->send('test')
->through([])
->then($destination);
$this->assertEquals('test processed', $result);
}
public function testPipelineCanModifyData()
{
$pipes = [
function ($passable, $next) {
$passable['pipe1'] = true;
return $next($passable);
},
function ($passable, $next) {
$passable['pipe2'] = true;
return $next($passable);
}
];
$destination = function ($passable) {
$passable['destination'] = true;
return $passable;
};
$result = $this->pipeline
->send([])
->through($pipes)
->then($destination);
$expected = [
'pipe1' => true,
'pipe2' => true,
'destination' => true
];
$this->assertEquals($expected, $result);
}
public function testPipelineCanShortCircuit()
{
$pipes = [
function ($passable, $next) {
if ($passable === 'stop') {
return 'stopped';
}
return $next($passable);
},
function ($passable, $next) {
return $next($passable . ' pipe2');
}
];
$destination = function ($passable) {
return $passable . ' destination';
};
$result = $this->pipeline
->send('stop')
->through($pipes)
->then($destination);
$this->assertEquals('stopped', $result);
}
public function testExceptionInDestinationIsHandled()
{
$pipes = [
function ($passable, $next) {
return $next($passable);
}
];
$destination = function ($passable) {
throw new Exception('Destination error');
};
$this->expectException(Exception::class);
$this->expectExceptionMessage('Destination error');
$this->pipeline
->send('test')
->through($pipes)
->then($destination);
}
public function testExceptionInPipeIsHandled()
{
$pipes = [
function ($passable, $next) {
throw new Exception('Pipe error');
}
];
$destination = function ($passable) {
return $passable;
};
$this->expectException(Exception::class);
$this->expectExceptionMessage('Pipe error');
$this->pipeline
->send('test')
->through($pipes)
->then($destination);
}
public function testWhenExceptionSetsHandler()
{
$result = $this->pipeline->whenException(function ($passable, $e) {
return 'handled';
});
$this->assertSame($this->pipeline, $result);
}
public function testExceptionHandlerIsCalledOnException()
{
$pipes = [
function ($passable, $next) {
throw new Exception('Test exception');
}
];
$destination = function ($passable) {
return $passable;
};
$result = $this->pipeline
->send('test')
->through($pipes)
->whenException(function ($passable, $e) {
return 'handled: ' . $e->getMessage();
})
->then($destination);
$this->assertEquals('handled: Test exception', $result);
}
public function testExceptionHandlerReceivesCorrectParameters()
{
$pipes = [
function ($passable, $next) {
throw new Exception('Test exception');
}
];
$destination = function ($passable) {
return $passable;
};
$handlerCalled = false;
$receivedPassable = null;
$receivedException = null;
$this->pipeline
->send('original data')
->through($pipes)
->whenException(function ($passable, $e) use (&$handlerCalled, &$receivedPassable, &$receivedException) {
$handlerCalled = true;
$receivedPassable = $passable;
$receivedException = $e;
return 'handled';
})
->then($destination);
$this->assertTrue($handlerCalled);
$this->assertEquals('original data', $receivedPassable);
$this->assertInstanceOf(Exception::class, $receivedException);
$this->assertEquals('Test exception', $receivedException->getMessage());
}
public function testExceptionInDestinationWithHandler()
{
$destination = function ($passable) {
throw new Exception('Destination exception');
};
$result = $this->pipeline
->send('test')
->through([])
->whenException(function ($passable, $e) {
return 'destination handled: ' . $e->getMessage();
})
->then($destination);
$this->assertEquals('destination handled: Destination exception', $result);
}
public function testComplexPipelineWithExceptions()
{
$pipes = [
function ($passable, $next) {
$passable[] = 'pipe1';
return $next($passable);
},
function ($passable, $next) {
if (in_array('error', $passable)) {
throw new Exception('Pipe2 error');
}
$passable[] = 'pipe2';
return $next($passable);
},
function ($passable, $next) {
$passable[] = 'pipe3';
return $next($passable);
}
];
$destination = function ($passable) {
$passable[] = 'destination';
return $passable;
};
// Normal execution
$result1 = $this->pipeline
->send(['start'])
->through($pipes)
->then($destination);
$this->assertEquals(['start', 'pipe1', 'pipe2', 'pipe3', 'destination'], $result1);
// With exception handling
$result2 = $this->pipeline
->send(['start', 'error'])
->through($pipes)
->whenException(function ($passable, $e) {
return ['error_handled', $e->getMessage()];
})
->then($destination);
$this->assertEquals(['error_handled', 'Pipe2 error'], $result2);
}
}