/**
  * @param string      $owner
  * @param string      $repository
  * @param string      $startReference
  * @param string|null $endReference
  *
  * @return Resource\Range
  */
 public function items($owner, $repository, $startReference, $endReference = null)
 {
     $range = $this->commitRepository->items($owner, $repository, $startReference, $endReference);
     $commits = $range->commits();
     array_walk($commits, function (Resource\CommitInterface $commit) use(&$range, $owner, $repository) {
         if (0 === preg_match('/^Merge pull request #(?P<id>\\d+)/', $commit->message(), $matches)) {
             return;
         }
         $id = $matches['id'];
         $pullRequest = $this->show($owner, $repository, $id);
         if (null === $pullRequest) {
             return;
         }
         $range = $range->withPullRequest($pullRequest);
     });
     return $range;
 }
 public function testItemsFetchesMoreCommitsIfEndIsNotContainedInFirstBatch()
 {
     $faker = $this->getFaker();
     $owner = $faker->userName;
     $repository = $faker->slug();
     $startReference = $faker->sha1;
     $endReference = $faker->sha1;
     $commitApi = $this->getCommitApiMock();
     $startCommit = $this->commitItem();
     $startCommit->sha = $faker->sha1;
     $commitApi->expects($this->at(0))->method('show')->with($this->equalTo($owner), $this->equalTo($repository), $this->equalTo($startReference))->willReturn($this->response($startCommit));
     $endCommit = $this->commitItem();
     $endCommit->sha = $faker->sha1;
     $commitApi->expects($this->at(1))->method('show')->with($this->equalTo($owner), $this->equalTo($repository), $this->equalTo($endReference))->willReturn($this->response($endCommit));
     $countBetweenFirstSegment = 4;
     $countBetweenSecondSegment = 5;
     $countBefore = 2;
     $firstSegment = array_merge($this->commitItems($countBetweenFirstSegment), [$endCommit]);
     $firstCommitFromFirstSegment = reset($firstSegment);
     $secondSegment = array_merge($this->commitItems($countBefore), [$startCommit], $this->commitItems($countBetweenSecondSegment), [$firstCommitFromFirstSegment]);
     $expectedItems = array_merge(array_slice($secondSegment, $countBefore + 1, $countBetweenSecondSegment), $firstSegment);
     $commitApi->expects($this->at(2))->method('all')->with($this->equalTo($owner), $this->equalTo($repository), $this->arrayHasKeyAndValue('sha', $endCommit->sha))->willReturn($this->responseFromItems($firstSegment));
     $commitApi->expects($this->at(3))->method('all')->with($this->equalTo($owner), $this->equalTo($repository), $this->arrayHasKeyAndValue('sha', $firstCommitFromFirstSegment->sha))->willReturn($this->responseFromItems($secondSegment));
     $commitRepository = new Repository\CommitRepository($commitApi);
     $range = $commitRepository->items($owner, $repository, $startReference, $endReference);
     $this->assertInstanceOf(Resource\RangeInterface::class, $range);
     $commits = $range->commits();
     $this->assertCount(count($expectedItems), $commits);
     array_walk($commits, function ($commit) use(&$expectedItems) {
         /*
          * API returns items in reverse order
          */
         $expectedItem = array_pop($expectedItems);
         $this->assertInstanceOf(Resource\CommitInterface::class, $commit);
         /* @var Resource\CommitInterface $commit */
         $this->assertSame($expectedItem->sha, $commit->sha());
         $this->assertSame($expectedItem->message, $commit->message());
     });
 }