diff --git a/src/Events/Dispatcher.php b/src/Events/Dispatcher.php index a993bad..95c09a1 100644 --- a/src/Events/Dispatcher.php +++ b/src/Events/Dispatcher.php @@ -354,10 +354,6 @@ protected function createClassCallable($listener) $method = '__invoke'; } - if ($this->handlerShouldBeQueued($class)) { - return $this->createQueuedHandlerCallable($class, $method); - } - $listener = new $class(); return [$listener, $method]; diff --git a/src/Pagination/AbstractPaginator.php b/src/Pagination/AbstractPaginator.php index 4d18dd2..1760379 100644 --- a/src/Pagination/AbstractPaginator.php +++ b/src/Pagination/AbstractPaginator.php @@ -378,6 +378,16 @@ public function onFirstPage() return $this->currentPage() <= 1; } + /** + * Determine if the paginator is on the last page. + * + * @return bool + */ + public function onLastPage() + { + return ! $this->hasMorePages(); + } + /** * Get the current page. * diff --git a/tests/Events/EventsDispatcherTest.php b/tests/Events/EventsDispatcherTest.php new file mode 100644 index 0000000..5fb3dbe --- /dev/null +++ b/tests/Events/EventsDispatcherTest.php @@ -0,0 +1,463 @@ +listen('foo', function ($foo) { + $_SERVER['__event.test'] = $foo; + }); + $response = $d->dispatch('foo', ['bar']); + + $this->assertEquals([null], $response); + $this->assertSame('bar', $_SERVER['__event.test']); + + // we can still add listeners after the event has fired + $d->listen('foo', function ($foo) { + $_SERVER['__event.test'] .= $foo; + }); + + $d->dispatch('foo', ['bar']); + $this->assertSame('barbar', $_SERVER['__event.test']); + } + + public function testHaltingEventExecution() + { + unset($_SERVER['__event.test']); + $d = new Dispatcher; + $d->listen('foo', function ($foo) { + $this->assertTrue(true); + + return 'here'; + }); + $d->listen('foo', function ($foo) { + throw new Exception('should not be called'); + }); + + $response = $d->dispatch('foo', ['bar'], true); + $this->assertSame('here', $response); + + $response = $d->until('foo', ['bar']); + $this->assertSame('here', $response); + } + + public function testResponseWhenNoListenersAreSet() + { + $d = new Dispatcher; + $response = $d->dispatch('foo'); + + $this->assertEquals([], $response); + + $response = $d->dispatch('foo', [], true); + $this->assertNull($response); + } + + public function testReturningFalseStopsPropagation() + { + unset($_SERVER['__event.test']); + $d = new Dispatcher; + $d->listen('foo', function ($foo) { + return $foo; + }); + + $d->listen('foo', function ($foo) { + $_SERVER['__event.test'] = $foo; + + return false; + }); + + $d->listen('foo', function ($foo) { + throw new Exception('should not be called'); + }); + + $response = $d->dispatch('foo', ['bar']); + + $this->assertSame('bar', $_SERVER['__event.test']); + $this->assertEquals(['bar'], $response); + } + + public function testReturningFalsyValuesContinuesPropagation() + { + unset($_SERVER['__event.test']); + $d = new Dispatcher; + $d->listen('foo', function () { + return 0; + }); + $d->listen('foo', function () { + return []; + }); + $d->listen('foo', function () { + return ''; + }); + $d->listen('foo', function () { + }); + + $response = $d->dispatch('foo', ['bar']); + + $this->assertEquals([0, [], '', null], $response); + } + + // public function testContainerResolutionOfEventHandlers() + // { + // $d = new Dispatcher($container = m::mock(Container::class)); + // $container->shouldReceive('make')->once()->with(TestEventListener::class)->andReturn(new TestEventListener); + // $d->listen('foo', TestEventListener::class.'@onFooEvent'); + // $response = $d->dispatch('foo', ['foo', 'bar']); + + // $this->assertEquals(['baz'], $response); + // } + + public function testContainerResolutionOfEventHandlersWithDefaultMethods() + { + $d = new Dispatcher(); + $d->listen('foo', TestEventListener::class); + $response = $d->dispatch('foo', ['foo', 'bar']); + $this->assertEquals(['baz'], $response); + } + + public function testQueuedEventsAreFired() + { + unset($_SERVER['__event.test']); + $d = new Dispatcher; + $d->listen('update', function ($name) { + $_SERVER['__event.test'] = $name; + }); + $d->push('update', ['name' => 'taylor']); + $d->listen('update', function ($name) { + $_SERVER['__event.test'] .= '_'.$name; + }); + + $this->assertFalse(isset($_SERVER['__event.test'])); + $d->flush('update'); + $d->listen('update', function ($name) { + $_SERVER['__event.test'] .= $name; + }); + $this->assertSame('taylor_taylor', $_SERVER['__event.test']); + } + + public function testQueuedEventsCanBeForgotten() + { + $_SERVER['__event.test'] = 'unset'; + $d = new Dispatcher; + $d->push('update', ['name' => 'taylor']); + $d->listen('update', function ($name) { + $_SERVER['__event.test'] = $name; + }); + + $d->forgetPushed(); + $d->flush('update'); + $this->assertSame('unset', $_SERVER['__event.test']); + } + + public function testMultiplePushedEventsWillGetFlushed() + { + $_SERVER['__event.test'] = ''; + $d = new Dispatcher; + $d->push('update', ['name' => 'taylor ']); + $d->push('update', ['name' => 'otwell']); + $d->listen('update', function ($name) { + $_SERVER['__event.test'] .= $name; + }); + + $d->flush('update'); + $this->assertSame('taylor otwell', $_SERVER['__event.test']); + } + + public function testWildcardListeners() + { + unset($_SERVER['__event.test']); + $d = new Dispatcher; + $d->listen('foo.bar', function () { + $_SERVER['__event.test'] = 'regular'; + }); + $d->listen('foo.*', function () { + $_SERVER['__event.test'] = 'wildcard'; + }); + $d->listen('bar.*', function () { + $_SERVER['__event.test'] = 'nope'; + }); + + $response = $d->dispatch('foo.bar'); + + $this->assertEquals([null, null], $response); + $this->assertSame('wildcard', $_SERVER['__event.test']); + } + + public function testWildcardListenersWithResponses() + { + unset($_SERVER['__event.test']); + $d = new Dispatcher; + $d->listen('foo.bar', function () { + return 'regular'; + }); + $d->listen('foo.*', function () { + return 'wildcard'; + }); + $d->listen('bar.*', function () { + return 'nope'; + }); + + $response = $d->dispatch('foo.bar'); + + $this->assertEquals(['regular', 'wildcard'], $response); + } + + public function testWildcardListenersCacheFlushing() + { + unset($_SERVER['__event.test']); + $d = new Dispatcher; + $d->listen('foo.*', function () { + $_SERVER['__event.test'] = 'cached_wildcard'; + }); + $d->dispatch('foo.bar'); + $this->assertSame('cached_wildcard', $_SERVER['__event.test']); + + $d->listen('foo.*', function () { + $_SERVER['__event.test'] = 'new_wildcard'; + }); + $d->dispatch('foo.bar'); + $this->assertSame('new_wildcard', $_SERVER['__event.test']); + } + + public function testListenersCanBeRemoved() + { + unset($_SERVER['__event.test']); + $d = new Dispatcher; + $d->listen('foo', function () { + $_SERVER['__event.test'] = 'foo'; + }); + $d->forget('foo'); + $d->dispatch('foo'); + + $this->assertFalse(isset($_SERVER['__event.test'])); + } + + public function testWildcardListenersCanBeRemoved() + { + unset($_SERVER['__event.test']); + $d = new Dispatcher; + $d->listen('foo.*', function () { + $_SERVER['__event.test'] = 'foo'; + }); + $d->forget('foo.*'); + $d->dispatch('foo.bar'); + + $this->assertFalse(isset($_SERVER['__event.test'])); + } + + public function testWildcardCacheIsClearedWhenListenersAreRemoved() + { + unset($_SERVER['__event.test']); + + $d = new Dispatcher; + $d->listen('foo*', function () { + $_SERVER['__event.test'] = 'foo'; + }); + $d->dispatch('foo'); + + $this->assertSame('foo', $_SERVER['__event.test']); + + unset($_SERVER['__event.test']); + + $d->forget('foo*'); + $d->dispatch('foo'); + + $this->assertFalse(isset($_SERVER['__event.test'])); + } + + public function testListenersCanBeFound() + { + $d = new Dispatcher; + $this->assertFalse($d->hasListeners('foo')); + + $d->listen('foo', function () { + // + }); + $this->assertTrue($d->hasListeners('foo')); + } + + public function testWildcardListenersCanBeFound() + { + $d = new Dispatcher; + $this->assertFalse($d->hasListeners('foo.*')); + + $d->listen('foo.*', function () { + // + }); + $this->assertTrue($d->hasListeners('foo.*')); + $this->assertTrue($d->hasListeners('foo.bar')); + } + + public function testEventPassedFirstToWildcards() + { + $d = new Dispatcher; + $d->listen('foo.*', function ($event, $data) { + $this->assertSame('foo.bar', $event); + $this->assertEquals(['first', 'second'], $data); + }); + $d->dispatch('foo.bar', ['first', 'second']); + + $d = new Dispatcher; + $d->listen('foo.bar', function ($first, $second) { + $this->assertSame('first', $first); + $this->assertSame('second', $second); + }); + $d->dispatch('foo.bar', ['first', 'second']); + } + + public function testClassesWork() + { + unset($_SERVER['__event.test']); + $d = new Dispatcher; + $d->listen(ExampleEvent::class, function () { + $_SERVER['__event.test'] = 'baz'; + }); + $d->dispatch(new ExampleEvent); + + $this->assertSame('baz', $_SERVER['__event.test']); + } + + public function testClassesWorkWithAnonymousListeners() + { + unset($_SERVER['__event.test']); + $d = new Dispatcher; + $d->listen(function (ExampleEvent $event) { + $_SERVER['__event.test'] = 'qux'; + }); + $d->dispatch(new ExampleEvent); + + $this->assertSame('qux', $_SERVER['__event.test']); + } + + public function testEventClassesArePayload() + { + unset($_SERVER['__event.test']); + $d = new Dispatcher; + $d->listen(ExampleEvent::class, function ($payload) { + $_SERVER['__event.test'] = $payload; + }); + $d->dispatch($e = new ExampleEvent, ['foo']); + + $this->assertSame($e, $_SERVER['__event.test']); + } + + public function testInterfacesWork() + { + unset($_SERVER['__event.test']); + $d = new Dispatcher; + $d->listen(SomeEventInterface::class, function () { + $_SERVER['__event.test'] = 'bar'; + }); + $d->dispatch(new AnotherEvent); + + $this->assertSame('bar', $_SERVER['__event.test']); + } + + public function testBothClassesAndInterfacesWork() + { + unset($_SERVER['__event.test']); + $_SERVER['__event.test'] = []; + $d = new Dispatcher; + $d->listen(AnotherEvent::class, function ($p) { + $_SERVER['__event.test'][] = $p; + $_SERVER['__event.test1'] = 'fooo'; + }); + $d->listen(SomeEventInterface::class, function ($p) { + $_SERVER['__event.test'][] = $p; + $_SERVER['__event.test2'] = 'baar'; + }); + $d->dispatch($e = new AnotherEvent, ['foo']); + + $this->assertSame($e, $_SERVER['__event.test'][0]); + $this->assertSame($e, $_SERVER['__event.test'][1]); + $this->assertSame('fooo', $_SERVER['__event.test1']); + $this->assertSame('baar', $_SERVER['__event.test2']); + + unset($_SERVER['__event.test1'], $_SERVER['__event.test2']); + } + + public function testNestedEvent() + { + $_SERVER['__event.test'] = []; + $d = new Dispatcher; + + $d->listen('event', function () use ($d) { + $d->listen('event', function () { + $_SERVER['__event.test'][] = 'fired 1'; + }); + $d->listen('event', function () { + $_SERVER['__event.test'][] = 'fired 2'; + }); + }); + + $d->dispatch('event'); + $this->assertSame([], $_SERVER['__event.test']); + $d->dispatch('event'); + $this->assertEquals(['fired 1', 'fired 2'], $_SERVER['__event.test']); + } + + public function testDuplicateListenersWillFire() + { + $d = new Dispatcher; + $d->listen('event', TestListener::class); + $d->listen('event', TestListener::class); + $d->listen('event', TestListener::class.'@handle'); + $d->listen('event', TestListener::class.'@handle'); + $d->dispatch('event'); + + $this->assertEquals(4, TestListener::$counter); + TestListener::$counter = 0; + } +} + +class ExampleEvent +{ + // +} + +interface SomeEventInterface +{ + // +} + +class AnotherEvent implements SomeEventInterface +{ + // +} + +class TestEventListener +{ + public function handle($foo, $bar) + { + return 'baz'; + } + + public function onFooEvent($foo, $bar) + { + return 'baz'; + } +} + +class TestListener +{ + public static $counter = 0; + + public function handle() + { + self::$counter++; + } +} \ No newline at end of file diff --git a/tests/Events/EventsSubscriberTest.php b/tests/Events/EventsSubscriberTest.php new file mode 100644 index 0000000..3e4cd2c --- /dev/null +++ b/tests/Events/EventsSubscriberTest.php @@ -0,0 +1,91 @@ +expectNotToPerformAssertions(); + + $d = new Dispatcher(); + $subs = m::mock(ExampleSubscriber::class); + $subs->shouldReceive('subscribe')->once()->with($d); + + $d->subscribe($subs); + } + + public function testEventSubscribeCanAcceptObject() + { + $this->expectNotToPerformAssertions(); + + $d = new Dispatcher; + $subs = m::mock(ExampleSubscriber::class); + $subs->shouldReceive('subscribe')->once()->with($d); + + $d->subscribe($subs); + } + + public function testEventSubscribeCanReturnMappings() + { + $d = new Dispatcher; + $d->subscribe(DeclarativeSubscriber::class); + + $d->dispatch('myEvent1'); + $this->assertSame('L1_L2_', DeclarativeSubscriber::$string); + + $d->dispatch('myEvent2'); + $this->assertSame('L1_L2_L3', DeclarativeSubscriber::$string); + } +} + +class ExampleSubscriber +{ + public function subscribe($e) + { + // There would be no error if a non-array is returned. + return '(O_o)'; + } +} + +class DeclarativeSubscriber +{ + public static $string = ''; + + public function subscribe() + { + return [ + 'myEvent1' => [ + self::class.'@listener1', + self::class.'@listener2', + ], + 'myEvent2' => [ + self::class.'@listener3', + ], + ]; + } + + public function listener1() + { + self::$string .= 'L1_'; + } + + public function listener2() + { + self::$string .= 'L2_'; + } + + public function listener3() + { + self::$string .= 'L3'; + } +} \ No newline at end of file diff --git a/tests/Pagination/CursorPaginatorLoadMorphCountTest.php b/tests/Pagination/CursorPaginatorLoadMorphCountTest.php new file mode 100644 index 0000000..ed9ec9a --- /dev/null +++ b/tests/Pagination/CursorPaginatorLoadMorphCountTest.php @@ -0,0 +1,29 @@ + 'photos', + 'App\\Company' => ['employees', 'calendars'], + ]; + + $items = m::mock(Collection::class); + $items->shouldReceive('loadMorphCount')->once()->with('parentable', $relations); + + $p = (new class extends AbstractCursorPaginator + { + // + })->setCollection($items); + + $this->assertSame($p, $p->loadMorphCount('parentable', $relations)); + } +} \ No newline at end of file diff --git a/tests/Pagination/CursorPaginatorLoadMorphTest.php b/tests/Pagination/CursorPaginatorLoadMorphTest.php new file mode 100644 index 0000000..3b60708 --- /dev/null +++ b/tests/Pagination/CursorPaginatorLoadMorphTest.php @@ -0,0 +1,29 @@ + 'photos', + 'App\\Company' => ['employees', 'calendars'], + ]; + + $items = m::mock(Collection::class); + $items->shouldReceive('loadMorph')->once()->with('parentable', $relations); + + $p = (new class extends AbstractCursorPaginator + { + // + })->setCollection($items); + + $this->assertSame($p, $p->loadMorph('parentable', $relations)); + } +} \ No newline at end of file diff --git a/tests/Pagination/CursorPaginatorTest.php b/tests/Pagination/CursorPaginatorTest.php new file mode 100644 index 0000000..727a89f --- /dev/null +++ b/tests/Pagination/CursorPaginatorTest.php @@ -0,0 +1,83 @@ + 1], ['id' => 2], ['id' => 3]], 2, null, [ + 'parameters' => ['id'], + ]); + + $this->assertTrue($p->hasPages()); + $this->assertTrue($p->hasMorePages()); + $this->assertEquals([['id' => 1], ['id' => 2]], $p->items()); + + $pageInfo = [ + 'data' => [['id' => 1], ['id' => 2]], + 'path' => '/', + 'per_page' => 2, + 'next_page_url' => '/?cursor='.$this->getCursor(['id' => 2]), + 'prev_page_url' => null, + ]; + + $this->assertEquals($pageInfo, $p->toArray()); + } + + public function testPaginatorRemovesTrailingSlashes() + { + $p = new CursorPaginator($array = [['id' => 4], ['id' => 5], ['id' => 6]], 2, null, + ['path' => 'http://website.com/test/', 'parameters' => ['id']]); + + $this->assertSame('http://website.com/test?cursor='.$this->getCursor(['id' => 5]), $p->nextPageUrl()); + } + + public function testPaginatorGeneratesUrlsWithoutTrailingSlash() + { + $p = new CursorPaginator($array = [['id' => 4], ['id' => 5], ['id' => 6]], 2, null, + ['path' => 'http://website.com/test', 'parameters' => ['id']]); + + $this->assertSame('http://website.com/test?cursor='.$this->getCursor(['id' => 5]), $p->nextPageUrl()); + } + + public function testItRetrievesThePaginatorOptions() + { + $p = new CursorPaginator($array = [['id' => 4], ['id' => 5], ['id' => 6]], 2, null, + $options = ['path' => 'http://website.com/test', 'parameters' => ['id']]); + + $this->assertSame($p->getOptions(), $options); + } + + public function testPaginatorReturnsPath() + { + $p = new CursorPaginator($array = [['id' => 4], ['id' => 5], ['id' => 6]], 2, null, + $options = ['path' => 'http://website.com/test', 'parameters' => ['id']]); + + $this->assertSame($p->path(), 'http://website.com/test'); + } + + public function testCanTransformPaginatorItems() + { + $p = new CursorPaginator($array = [['id' => 4], ['id' => 5], ['id' => 6]], 2, null, + $options = ['path' => 'http://website.com/test', 'parameters' => ['id']]); + + $p->through(function ($item) { + $item['id'] = $item['id'] + 2; + + return $item; + }); + + $this->assertInstanceOf(CursorPaginator::class, $p); + $this->assertSame([['id' => 6], ['id' => 7]], $p->items()); + } + + protected function getCursor($params, $isNext = true) + { + return (new Cursor($params, $isNext))->encode(); + } +} \ No newline at end of file diff --git a/tests/Pagination/CursorTest.php b/tests/Pagination/CursorTest.php new file mode 100644 index 0000000..5986ac3 --- /dev/null +++ b/tests/Pagination/CursorTest.php @@ -0,0 +1,40 @@ + 422, + 'created_at' => Carbon::now()->toDateTimeString(), + ], true); + + $this->assertEquals($cursor, Cursor::fromEncoded($cursor->encode())); + } + + public function testCanGetParams() + { + $cursor = new Cursor([ + 'id' => 422, + 'created_at' => ($now = Carbon::now()->toDateTimeString()), + ], true); + + $this->assertEquals([$now, 422], $cursor->parameters(['created_at', 'id'])); + } + + public function testCanGetParam() + { + $cursor = new Cursor([ + 'id' => 422, + 'created_at' => ($now = Carbon::now()->toDateTimeString()), + ], true); + + $this->assertEquals($now, $cursor->parameter('created_at')); + } +} \ No newline at end of file diff --git a/tests/Pagination/LengthAwarePaginatorTest.php b/tests/Pagination/LengthAwarePaginatorTest.php new file mode 100644 index 0000000..a6feaf6 --- /dev/null +++ b/tests/Pagination/LengthAwarePaginatorTest.php @@ -0,0 +1,127 @@ +options = ['onEachSide' => 5]; + $this->p = new LengthAwarePaginator($array = ['item1', 'item2', 'item3', 'item4'], 4, 2, 2, $this->options); + } + + protected function tearDown(): void + { + unset($this->p); + } + + public function testLengthAwarePaginatorGetAndSetPageName() + { + $this->assertSame('page', $this->p->getPageName()); + + $this->p->setPageName('p'); + $this->assertSame('p', $this->p->getPageName()); + } + + public function testLengthAwarePaginatorCanGiveMeRelevantPageInformation() + { + $this->assertEquals(2, $this->p->lastPage()); + $this->assertEquals(2, $this->p->currentPage()); + $this->assertTrue($this->p->hasPages()); + $this->assertFalse($this->p->hasMorePages()); + $this->assertEquals(['item1', 'item2', 'item3', 'item4'], $this->p->items()); + } + + public function testLengthAwarePaginatorSetCorrectInformationWithNoItems() + { + $paginator = new LengthAwarePaginator([], 0, 2, 1); + + $this->assertEquals(1, $paginator->lastPage()); + $this->assertEquals(1, $paginator->currentPage()); + $this->assertFalse($paginator->hasPages()); + $this->assertFalse($paginator->hasMorePages()); + $this->assertEmpty($paginator->items()); + } + + public function testLengthAwarePaginatorisOnFirstAndLastPage() + { + $paginator = new LengthAwarePaginator(['1', '2', '3', '4'], 4, 2, 2); + + $this->assertTrue($paginator->onLastPage()); + $this->assertFalse($paginator->onFirstPage()); + + $paginator = new LengthAwarePaginator(['1', '2', '3', '4'], 4, 2, 1); + + $this->assertFalse($paginator->onLastPage()); + $this->assertTrue($paginator->onFirstPage()); + } + + public function testLengthAwarePaginatorCanGenerateUrls() + { + $this->p->setPath('http://website.com'); + $this->p->setPageName('foo'); + + $this->assertSame('http://website.com', + $this->p->path()); + + $this->assertSame('http://website.com?foo=2', + $this->p->url($this->p->currentPage())); + + $this->assertSame('http://website.com?foo=1', + $this->p->url($this->p->currentPage() - 1)); + + $this->assertSame('http://website.com?foo=1', + $this->p->url($this->p->currentPage() - 2)); + } + + public function testLengthAwarePaginatorCanGenerateUrlsWithQuery() + { + $this->p->setPath('http://website.com?sort_by=date'); + $this->p->setPageName('foo'); + + $this->assertSame('http://website.com?sort_by=date&foo=2', + $this->p->url($this->p->currentPage())); + } + + public function testLengthAwarePaginatorCanGenerateUrlsWithoutTrailingSlashes() + { + $this->p->setPath('http://website.com/test'); + $this->p->setPageName('foo'); + + $this->assertSame('http://website.com/test?foo=2', + $this->p->url($this->p->currentPage())); + + $this->assertSame('http://website.com/test?foo=1', + $this->p->url($this->p->currentPage() - 1)); + + $this->assertSame('http://website.com/test?foo=1', + $this->p->url($this->p->currentPage() - 2)); + } + + public function testLengthAwarePaginatorCorrectlyGenerateUrlsWithQueryAndSpaces() + { + $this->p->setPath('http://website.com?key=value%20with%20spaces'); + $this->p->setPageName('foo'); + + $this->assertSame('http://website.com?key=value%20with%20spaces&foo=2', + $this->p->url($this->p->currentPage())); + } + + public function testItRetrievesThePaginatorOptions() + { + $this->assertSame($this->options, $this->p->getOptions()); + } +} \ No newline at end of file diff --git a/tests/Pagination/PaginatorLoadMorphCountTest.php b/tests/Pagination/PaginatorLoadMorphCountTest.php new file mode 100644 index 0000000..0419c74 --- /dev/null +++ b/tests/Pagination/PaginatorLoadMorphCountTest.php @@ -0,0 +1,29 @@ + 'photos', + 'App\\Company' => ['employees', 'calendars'], + ]; + + $items = m::mock(Collection::class); + $items->shouldReceive('loadMorphCount')->once()->with('parentable', $relations); + + $p = (new class extends AbstractPaginator + { + // + })->setCollection($items); + + $this->assertSame($p, $p->loadMorphCount('parentable', $relations)); + } +} \ No newline at end of file diff --git a/tests/Pagination/PaginatorLoadMorphTest.php b/tests/Pagination/PaginatorLoadMorphTest.php new file mode 100644 index 0000000..73e4571 --- /dev/null +++ b/tests/Pagination/PaginatorLoadMorphTest.php @@ -0,0 +1,29 @@ + 'photos', + 'App\\Company' => ['employees', 'calendars'], + ]; + + $items = m::mock(Collection::class); + $items->shouldReceive('loadMorph')->once()->with('parentable', $relations); + + $p = (new class extends AbstractPaginator + { + // + })->setCollection($items); + + $this->assertSame($p, $p->loadMorph('parentable', $relations)); + } +} \ No newline at end of file diff --git a/tests/Pagination/PaginatorTest.php b/tests/Pagination/PaginatorTest.php new file mode 100644 index 0000000..9f0b793 --- /dev/null +++ b/tests/Pagination/PaginatorTest.php @@ -0,0 +1,78 @@ +assertEquals(2, $p->currentPage()); + $this->assertTrue($p->hasPages()); + $this->assertTrue($p->hasMorePages()); + $this->assertEquals(['item3', 'item4'], $p->items()); + + $pageInfo = [ + 'per_page' => 2, + 'current_page' => 2, + 'first_page_url' => '/?page=1', + 'next_page_url' => '/?page=3', + 'prev_page_url' => '/?page=1', + 'from' => 3, + 'to' => 4, + 'data' => ['item3', 'item4'], + 'path' => '/', + ]; + + $this->assertEquals($pageInfo, $p->toArray()); + } + + public function testPaginatorRemovesTrailingSlashes() + { + $p = new Paginator($array = ['item1', 'item2', 'item3'], 2, 2, + ['path' => 'http://website.com/test/']); + + $this->assertSame('http://website.com/test?page=1', $p->previousPageUrl()); + } + + public function testPaginatorGeneratesUrlsWithoutTrailingSlash() + { + $p = new Paginator($array = ['item1', 'item2', 'item3'], 2, 2, + ['path' => 'http://website.com/test']); + + $this->assertSame('http://website.com/test?page=1', $p->previousPageUrl()); + } + + public function testItRetrievesThePaginatorOptions() + { + $p = new Paginator($array = ['item1', 'item2', 'item3'], 2, 2, + $options = ['path' => 'http://website.com/test']); + + $this->assertSame($p->getOptions(), $options); + } + + public function testPaginatorReturnsPath() + { + $p = new Paginator($array = ['item1', 'item2', 'item3'], 2, 2, + ['path' => 'http://website.com/test']); + + $this->assertSame($p->path(), 'http://website.com/test'); + } + + public function testCanTransformPaginatorItems() + { + $p = new Paginator($array = ['item1', 'item2', 'item3'], 3, 1, + ['path' => 'http://website.com/test']); + + $p->through(function ($item) { + return substr($item, 4, 1); + }); + + $this->assertInstanceOf(Paginator::class, $p); + $this->assertSame(['1', '2', '3'], $p->items()); + } +} \ No newline at end of file diff --git a/tests/Pagination/UrlWindowTest.php b/tests/Pagination/UrlWindowTest.php new file mode 100644 index 0000000..a488fc3 --- /dev/null +++ b/tests/Pagination/UrlWindowTest.php @@ -0,0 +1,74 @@ +assertTrue($window->hasPages()); + } + + public function testPresenterCanGetAUrlRangeForASmallNumberOfUrls() + { + $p = new LengthAwarePaginator($array = ['item1', 'item2', 'item3', 'item4'], 4, 2, 2); + $window = new UrlWindow($p); + $this->assertEquals(['first' => [1 => '/?page=1', 2 => '/?page=2'], 'slider' => null, 'last' => null], $window->get()); + } + + public function testPresenterCanGetAUrlRangeForAWindowOfLinks() + { + $array = []; + for ($i = 1; $i <= 20; $i++) { + $array[$i] = 'item'.$i; + } + $p = new LengthAwarePaginator($array, count($array), 1, 12); + $window = new UrlWindow($p); + $slider = []; + for ($i = 9; $i <= 15; $i++) { + $slider[$i] = '/?page='.$i; + } + + $this->assertEquals(['first' => [1 => '/?page=1', 2 => '/?page=2'], 'slider' => $slider, 'last' => [19 => '/?page=19', 20 => '/?page=20']], $window->get()); + + /* + * Test Being Near The End Of The List + */ + $array = []; + for ($i = 1; $i <= 20; $i++) { + $array[$i] = 'item'.$i; + } + $p = new LengthAwarePaginator($array, count($array), 1, 17); + $window = new UrlWindow($p); + $last = []; + for ($i = 11; $i <= 20; $i++) { + $last[$i] = '/?page='.$i; + } + $this->assertEquals(['first' => [1 => '/?page=1', 2 => '/?page=2'], 'slider' => null, 'last' => $last], $window->get()); + } + + public function testCustomUrlRangeForAWindowOfLinks() + { + $array = []; + for ($i = 1; $i <= 20; $i++) { + $array[$i] = 'item'.$i; + } + + $p = new LengthAwarePaginator($array, count($array), 1, 8); + $p->onEachSide(1); + $window = new UrlWindow($p); + + $slider = []; + for ($i = 7; $i <= 9; $i++) { + $slider[$i] = '/?page='.$i; + } + + $this->assertEquals(['first' => [1 => '/?page=1', 2 => '/?page=2'], 'slider' => $slider, 'last' => [19 => '/?page=19', 20 => '/?page=20']], $window->get()); + } +} \ No newline at end of file