assertSame([], LoopDetector::findLoopingWorkflows([])); } public function testSameSourceAndTargetIsALoop(): void { $this->assertSame([1], LoopDetector::findLoopingWorkflows([1 => [10, 10]])); } public function testTwoWorkflowsBackAndForthAreALoop(): void { $this->assertSame([1, 2], LoopDetector::findLoopingWorkflows([ 1 => [10, 20], 2 => [20, 10], ])); } public function testLongerCircleIsALoop(): void { $this->assertSame([1, 2, 3], LoopDetector::findLoopingWorkflows([ 1 => [10, 20], 2 => [20, 30], 3 => [30, 10], ])); } public function testChainIsNoLoop(): void { $this->assertSame([], LoopDetector::findLoopingWorkflows([ 1 => [10, 20], 2 => [20, 30], ])); } public function testOnlyWorkflowsOnTheCircleAreReported(): void { // 1 feeds into the circle 2 → 3 → 2 and 4 leads out of it; neither // lies on it. $this->assertSame([2, 3], LoopDetector::findLoopingWorkflows([ 1 => [10, 20], 2 => [20, 30], 3 => [30, 20], 4 => [30, 40], ])); } public function testTwoWorkflowsFromTheSameSourceAreNoLoop(): void { $this->assertSame([], LoopDetector::findLoopingWorkflows([ 1 => [10, 20], 2 => [10, 30], ])); } public function testFindPathListsTheWorkflowsInOrder(): void { $edges = [ 7 => [30, 10], 5 => [10, 20], 6 => [20, 30], ]; $this->assertSame([5, 6], LoopDetector::findPath($edges, 10, 30)); $this->assertSame([6, 7], LoopDetector::findPath($edges, 20, 10)); } public function testFindPathWithoutConnectionIsNull(): void { $this->assertNull(LoopDetector::findPath([1 => [10, 20]], 20, 10)); } public function testFindPathToItselfIsEmpty(): void { $this->assertSame([], LoopDetector::findPath([], 10, 10)); } }