1
+ <?php
2
+ /*
3
+ * Copyright 2023 Cloud Creativity Limited
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ declare (strict_types=1 );
19
+
20
+ namespace LaravelJsonApi \Eloquent \Tests \Unit \Pagination ;
21
+
22
+ use Illuminate \Database \Eloquent \Builder ;
23
+ use LaravelJsonApi \Contracts \Pagination \Page ;
24
+ use LaravelJsonApi \Eloquent \Contracts \Paginator ;
25
+ use LaravelJsonApi \Eloquent \Pagination \MultiPagination ;
26
+ use PHPUnit \Framework \TestCase ;
27
+
28
+ class MultiPaginationTest extends TestCase
29
+ {
30
+ public function testKeys (): void
31
+ {
32
+ $ paginator1 = $ this ->createMock (Paginator::class);
33
+ $ paginator1 ->expects ($ this ->once ())->method ('keys ' )->willReturn (['number ' , 'size ' ]);
34
+
35
+ $ paginator2 = $ this ->createMock (Paginator::class);
36
+ $ paginator2 ->expects ($ this ->once ())->method ('keys ' )->willReturn (['before ' , 'after ' , 'limit ' ]);
37
+
38
+ $ paginator3 = $ this ->createMock (Paginator::class);
39
+ $ paginator3 ->expects ($ this ->once ())->method ('keys ' )->willReturn (['number ' , 'chunk ' ]);
40
+
41
+ $ paginator = new MultiPagination (
42
+ $ paginator1 ,
43
+ $ paginator2 ,
44
+ $ paginator3 ,
45
+ );
46
+
47
+ $ this ->assertSame ($ expected = [
48
+ 'number ' ,
49
+ 'size ' ,
50
+ 'before ' ,
51
+ 'after ' ,
52
+ 'limit ' ,
53
+ 'chunk ' ,
54
+ ], $ paginator ->keys ());
55
+ $ this ->assertSame ($ expected , $ paginator ->keys ());
56
+ }
57
+
58
+ public function testWithColumns (): void
59
+ {
60
+ $ columns = ['foo ' , 'bar ' , 'baz ' ];
61
+
62
+ $ paginator1 = $ this ->createMock (Paginator::class);
63
+ $ paginator1
64
+ ->expects ($ this ->once ())
65
+ ->method ('withColumns ' )
66
+ ->with ($ this ->identicalTo ($ columns ))
67
+ ->willReturnSelf ();
68
+
69
+ $ paginator2 = $ this ->createMock (Paginator::class);
70
+ $ paginator2
71
+ ->expects ($ this ->once ())
72
+ ->method ('withColumns ' )
73
+ ->with ($ this ->identicalTo ($ columns ))
74
+ ->willReturnSelf ();
75
+
76
+ $ paginator = new MultiPagination ($ paginator1 , $ paginator2 );
77
+ $ actual = $ paginator ->withColumns ($ columns );
78
+
79
+ $ this ->assertSame ($ paginator , $ actual );
80
+ }
81
+
82
+ public function testWithKeyName (): void
83
+ {
84
+ $ key = 'blah ' ;
85
+
86
+ $ paginator1 = $ this ->createMock (Paginator::class);
87
+ $ paginator1
88
+ ->expects ($ this ->once ())
89
+ ->method ('withKeyName ' )
90
+ ->with ($ this ->identicalTo ($ key ))
91
+ ->willReturnSelf ();
92
+
93
+ $ paginator2 = $ this ->createMock (Paginator::class);
94
+ $ paginator2
95
+ ->expects ($ this ->once ())
96
+ ->method ('withKeyName ' )
97
+ ->with ($ this ->identicalTo ($ key ))
98
+ ->willReturnSelf ();
99
+
100
+ $ paginator = new MultiPagination ($ paginator1 , $ paginator2 );
101
+ $ actual = $ paginator ->withKeyName ($ key );
102
+
103
+ $ this ->assertSame ($ paginator , $ actual );
104
+ }
105
+
106
+ public function testItQueriesPaginatorBasedOnKeys (): void
107
+ {
108
+ $ query = $ this ->createMock (Builder::class);
109
+ $ page = ['number ' => 2 , 'chunk ' => 3 ];
110
+
111
+ $ paginator1 = $ this ->createMock (Paginator::class);
112
+ $ paginator1 ->method ('keys ' )->willReturn (['number ' , 'size ' ]);
113
+ $ paginator1 ->expects ($ this ->never ())->method ('paginate ' );
114
+
115
+ $ paginator2 = $ this ->createMock (Paginator::class);
116
+ $ paginator2 ->method ('keys ' )->willReturn (['before ' , 'after ' , 'limit ' ]);
117
+ $ paginator2 ->expects ($ this ->never ())->method ('paginate ' );
118
+
119
+ $ paginator3 = $ this ->createMock (Paginator::class);
120
+ $ paginator3 ->method ('keys ' )->willReturn (['number ' , 'chunk ' ]);
121
+ $ paginator3
122
+ ->expects ($ this ->once ())
123
+ ->method ('paginate ' )
124
+ ->with ($ this ->identicalTo ($ query ), $ this ->identicalTo ($ page ))
125
+ ->willReturn ($ expected = $ this ->createMock (Page::class));
126
+
127
+ $ paginator = new MultiPagination (
128
+ $ paginator1 ,
129
+ $ paginator2 ,
130
+ $ paginator3 ,
131
+ );
132
+
133
+ $ actual = $ paginator ->paginate ($ query , $ page );
134
+
135
+ $ this ->assertSame ($ expected , $ actual );
136
+ }
137
+
138
+ public function testItQueriesPaginatorBasedOnSomeKeys (): void
139
+ {
140
+ $ query = $ this ->createMock (Builder::class);
141
+ $ page = ['after ' => 'some-id ' , 'limit ' => 10 ];
142
+
143
+ $ paginator1 = $ this ->createMock (Paginator::class);
144
+ $ paginator1 ->method ('keys ' )->willReturn (['number ' , 'limit ' ]);
145
+ $ paginator1 ->expects ($ this ->never ())->method ('paginate ' );
146
+
147
+ $ paginator2 = $ this ->createMock (Paginator::class);
148
+ $ paginator2 ->method ('keys ' )->willReturn (['before ' , 'after ' , 'limit ' ]);
149
+ $ paginator2
150
+ ->expects ($ this ->once ())
151
+ ->method ('paginate ' )
152
+ ->with ($ this ->identicalTo ($ query ), $ this ->identicalTo ($ page ))
153
+ ->willReturn ($ expected = $ this ->createMock (Page::class));
154
+
155
+ $ paginator3 = $ this ->createMock (Paginator::class);
156
+ $ paginator3 ->method ('keys ' )->willReturn (['number ' , 'chunk ' ]);
157
+ $ paginator3 ->expects ($ this ->never ())->method ('paginate ' );
158
+
159
+ $ paginator = new MultiPagination (
160
+ $ paginator1 ,
161
+ $ paginator2 ,
162
+ $ paginator3 ,
163
+ );
164
+
165
+ $ actual = $ paginator ->paginate ($ query , $ page );
166
+
167
+ $ this ->assertSame ($ expected , $ actual );
168
+ }
169
+
170
+ /**
171
+ * If the page keys match multiple paginators, we'll use the first matching paginator.
172
+ *
173
+ * @return void
174
+ */
175
+ public function testItUsesFirstMatchingPaginatorWhenNoneAreConclusive (): void
176
+ {
177
+ $ query = $ this ->createMock (Builder::class);
178
+ $ page = ['number ' => 1 , 'after ' => 'some-id ' ];
179
+
180
+ $ paginator1 = $ this ->createMock (Paginator::class);
181
+ $ paginator1 ->method ('keys ' )->willReturn (['foo ' , 'bar ' ]);
182
+ $ paginator1 ->expects ($ this ->never ())->method ('paginate ' );
183
+
184
+ $ paginator2 = $ this ->createMock (Paginator::class);
185
+ $ paginator2 ->method ('keys ' )->willReturn (['before ' , 'after ' , 'limit ' ]);
186
+ $ paginator2
187
+ ->expects ($ this ->once ())
188
+ ->method ('paginate ' )
189
+ ->with ($ this ->identicalTo ($ query ), $ this ->identicalTo ($ page ))
190
+ ->willReturn ($ expected = $ this ->createMock (Page::class));
191
+
192
+ $ paginator3 = $ this ->createMock (Paginator::class);
193
+ $ paginator3 ->method ('keys ' )->willReturn (['number ' , 'size ' ]);
194
+ $ paginator3 ->expects ($ this ->never ())->method ('paginate ' );
195
+
196
+ $ paginator = new MultiPagination (
197
+ $ paginator1 ,
198
+ $ paginator2 ,
199
+ $ paginator3 ,
200
+ );
201
+
202
+ $ actual = $ paginator ->paginate ($ query , $ page );
203
+
204
+ $ this ->assertSame ($ expected , $ actual );
205
+ }
206
+
207
+ public function testItHasInconclusivePageParameters (): void
208
+ {
209
+ $ query = $ this ->createMock (Builder::class);
210
+ $ page = ['foo ' => 'bar ' , 'baz ' => 'bat ' ];
211
+
212
+ $ paginator1 = $ this ->createMock (Paginator::class);
213
+ $ paginator1 ->method ('keys ' )->willReturn (['number ' , 'size ' ]);
214
+ $ paginator1 ->expects ($ this ->never ())->method ('paginate ' );
215
+
216
+ $ paginator2 = $ this ->createMock (Paginator::class);
217
+ $ paginator2 ->method ('keys ' )->willReturn (['before ' , 'after ' , 'limit ' ]);
218
+ $ paginator2 ->expects ($ this ->never ())->method ('paginate ' );
219
+
220
+ $ paginator = new MultiPagination ($ paginator1 , $ paginator2 );
221
+
222
+ $ this ->expectException (\LogicException::class);
223
+ $ this ->expectExceptionMessage (
224
+ 'Could not determine which paginator to use. ' .
225
+ 'Use validation to ensure the client provides query parameters that match at least one paginator. ' .
226
+ 'Keys received: foo,baz ' ,
227
+ );
228
+
229
+ $ paginator ->paginate ($ query , $ page );
230
+ }
231
+ }
0 commit comments