Skip to content

Commit be28e33

Browse files
committed
Tests only for deterministic ordering.
1 parent 70ca20b commit be28e33

File tree

1 file changed

+301
-0
lines changed

1 file changed

+301
-0
lines changed
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
<?php
2+
/**
3+
* Test deterministic ordering functionality in WP_Query.
4+
*
5+
* @package WordPress\UnitTests
6+
*
7+
* @group query
8+
* @group ordering
9+
* @ticket xxxxx
10+
*/
11+
class Tests_Query_DeterministicOrdering extends WP_UnitTestCase {
12+
13+
/**
14+
* Test that deterministic ordering prevents duplicate records across pages.
15+
*
16+
* This is the core test for the bug fix. When multiple posts have the same
17+
* value for a field (like post_date), pagination can show duplicate records
18+
* without deterministic ordering.
19+
*
20+
* @ticket xxxxx
21+
*/
22+
public function test_deterministic_ordering_prevents_duplicates_across_pages() {
23+
// Create multiple posts with identical post_date to trigger the bug
24+
$identical_date = '2023-01-01 10:00:00';
25+
$post_ids = array();
26+
27+
for ( $i = 1; $i <= 20; $i++ ) {
28+
$post_ids[] = self::factory()->post->create(
29+
array(
30+
'post_title' => "Post $i",
31+
'post_date' => $identical_date,
32+
)
33+
);
34+
}
35+
36+
// Get first page
37+
$query1 = new WP_Query(
38+
array(
39+
'orderby' => 'post_date',
40+
'order' => 'ASC',
41+
'posts_per_page' => 10,
42+
'paged' => 1,
43+
)
44+
);
45+
46+
// Get second page
47+
$query2 = new WP_Query(
48+
array(
49+
'orderby' => 'post_date',
50+
'order' => 'ASC',
51+
'posts_per_page' => 10,
52+
'paged' => 2,
53+
)
54+
);
55+
56+
$page1_ids = wp_list_pluck( $query1->posts, 'ID' );
57+
$page2_ids = wp_list_pluck( $query2->posts, 'ID' );
58+
59+
// Verify no overlap between pages (no duplicates)
60+
$overlap = array_intersect( $page1_ids, $page2_ids );
61+
$this->assertEmpty( $overlap, 'Pages should not contain duplicate posts' );
62+
63+
// Verify total count is correct
64+
$this->assertEquals( 20, $query1->found_posts, 'Total posts should be 20' );
65+
$this->assertEquals( 10, count( $page1_ids ), 'First page should have 10 posts' );
66+
$this->assertEquals( 10, count( $page2_ids ), 'Second page should have 10 posts' );
67+
68+
// Verify deterministic ordering: same query should return same results
69+
$query1_repeat = new WP_Query(
70+
array(
71+
'orderby' => 'post_date',
72+
'order' => 'ASC',
73+
'posts_per_page' => 10,
74+
'paged' => 1,
75+
)
76+
);
77+
$page1_repeat_ids = wp_list_pluck( $query1_repeat->posts, 'ID' );
78+
79+
$this->assertEquals( $page1_ids, $page1_repeat_ids, 'Same query should return same results' );
80+
}
81+
82+
/**
83+
* Test that deterministic ordering works with post_title field.
84+
*
85+
* @ticket xxxxx
86+
*/
87+
public function test_deterministic_ordering_with_post_title() {
88+
$identical_title = 'Same Title';
89+
$post_ids = array();
90+
91+
for ( $i = 1; $i <= 15; $i++ ) {
92+
$post_ids[] = self::factory()->post->create(
93+
array(
94+
'post_title' => $identical_title,
95+
'post_date' => "2023-01-0$i 10:00:00",
96+
)
97+
);
98+
}
99+
100+
// Get first page
101+
$query1 = new WP_Query(
102+
array(
103+
'orderby' => 'post_title',
104+
'order' => 'ASC',
105+
'posts_per_page' => 8,
106+
'paged' => 1,
107+
)
108+
);
109+
110+
// Get second page
111+
$query2 = new WP_Query(
112+
array(
113+
'orderby' => 'post_title',
114+
'order' => 'ASC',
115+
'posts_per_page' => 8,
116+
'paged' => 2,
117+
)
118+
);
119+
120+
$page1_ids = wp_list_pluck( $query1->posts, 'ID' );
121+
$page2_ids = wp_list_pluck( $query2->posts, 'ID' );
122+
123+
// Verify no duplicates across pages
124+
$overlap = array_intersect( $page1_ids, $page2_ids );
125+
$this->assertEmpty( $overlap, 'Pages should not contain duplicate posts when ordering by title' );
126+
}
127+
128+
/**
129+
* Test that deterministic ordering works with DESC order.
130+
*
131+
* @ticket xxxxx
132+
*/
133+
public function test_deterministic_ordering_with_desc_order() {
134+
$identical_date = '2023-01-01 10:00:00';
135+
$post_ids = array();
136+
137+
for ( $i = 1; $i <= 12; $i++ ) {
138+
$post_ids[] = self::factory()->post->create(
139+
array(
140+
'post_title' => "Post $i",
141+
'post_date' => $identical_date,
142+
)
143+
);
144+
}
145+
146+
// Get first page with DESC order
147+
$query1 = new WP_Query(
148+
array(
149+
'orderby' => 'post_date',
150+
'order' => 'DESC',
151+
'posts_per_page' => 6,
152+
'paged' => 1,
153+
)
154+
);
155+
156+
// Get second page with DESC order
157+
$query2 = new WP_Query(
158+
array(
159+
'orderby' => 'post_date',
160+
'order' => 'DESC',
161+
'posts_per_page' => 6,
162+
'paged' => 2,
163+
)
164+
);
165+
166+
$page1_ids = wp_list_pluck( $query1->posts, 'ID' );
167+
$page2_ids = wp_list_pluck( $query2->posts, 'ID' );
168+
169+
// Verify no duplicates across pages
170+
$overlap = array_intersect( $page1_ids, $page2_ids );
171+
$this->assertEmpty( $overlap, 'Pages should not contain duplicate posts with DESC order' );
172+
}
173+
174+
/**
175+
* Test that deterministic ordering works with array orderby.
176+
*
177+
* @ticket xxxxx
178+
*/
179+
public function test_deterministic_ordering_with_array_orderby() {
180+
$identical_date = '2023-01-01 10:00:00';
181+
$post_ids = array();
182+
183+
for ( $i = 1; $i <= 16; $i++ ) {
184+
$post_ids[] = self::factory()->post->create(
185+
array(
186+
'post_title' => "Post $i",
187+
'post_date' => $identical_date,
188+
)
189+
);
190+
}
191+
192+
// Test with array orderby
193+
$query1 = new WP_Query(
194+
array(
195+
'orderby' => array(
196+
'post_date' => 'ASC',
197+
'post_title' => 'ASC',
198+
),
199+
'posts_per_page' => 8,
200+
'paged' => 1,
201+
)
202+
);
203+
204+
$query2 = new WP_Query(
205+
array(
206+
'orderby' => array(
207+
'post_date' => 'ASC',
208+
'post_title' => 'ASC',
209+
),
210+
'posts_per_page' => 8,
211+
'paged' => 2,
212+
)
213+
);
214+
215+
$page1_ids = wp_list_pluck( $query1->posts, 'ID' );
216+
$page2_ids = wp_list_pluck( $query2->posts, 'ID' );
217+
218+
// Verify no duplicates across pages
219+
$overlap = array_intersect( $page1_ids, $page2_ids );
220+
$this->assertEmpty( $overlap, 'Pages should not contain duplicate posts with array orderby' );
221+
}
222+
223+
/**
224+
* Test that deterministic ordering doesn't add ID when ID is already present.
225+
*
226+
* @ticket xxxxx
227+
*/
228+
public function test_deterministic_ordering_does_not_duplicate_id() {
229+
$identical_date = '2023-01-01 10:00:00';
230+
$post_ids = array();
231+
232+
for ( $i = 1; $i <= 10; $i++ ) {
233+
$post_ids[] = self::factory()->post->create(
234+
array(
235+
'post_title' => "Post $i",
236+
'post_date' => $identical_date,
237+
)
238+
);
239+
}
240+
241+
$query = new WP_Query(
242+
array(
243+
'orderby' => 'ID',
244+
'order' => 'ASC',
245+
'posts_per_page' => 10,
246+
)
247+
);
248+
249+
// Should not add duplicate ID ordering
250+
$this->assertStringContainsString( 'ID ASC', $query->request );
251+
$this->assertStringNotContainsString( 'ID ASC, ID ASC', $query->request );
252+
}
253+
254+
/**
255+
* Test that deterministic ordering works with search queries.
256+
*
257+
* @ticket xxxxx
258+
*/
259+
public function test_deterministic_ordering_with_search() {
260+
$identical_date = '2023-01-01 10:00:00';
261+
$post_ids = array();
262+
263+
for ( $i = 1; $i <= 12; $i++ ) {
264+
$post_ids[] = self::factory()->post->create(
265+
array(
266+
'post_title' => "Test Post $i",
267+
'post_content' => 'This is a test post',
268+
'post_date' => $identical_date,
269+
)
270+
);
271+
}
272+
273+
// Test with search
274+
$query1 = new WP_Query(
275+
array(
276+
's' => 'test',
277+
'orderby' => 'post_date',
278+
'order' => 'ASC',
279+
'posts_per_page' => 6,
280+
'paged' => 1,
281+
)
282+
);
283+
284+
$query2 = new WP_Query(
285+
array(
286+
's' => 'test',
287+
'orderby' => 'post_date',
288+
'order' => 'ASC',
289+
'posts_per_page' => 6,
290+
'paged' => 2,
291+
)
292+
);
293+
294+
$page1_ids = wp_list_pluck( $query1->posts, 'ID' );
295+
$page2_ids = wp_list_pluck( $query2->posts, 'ID' );
296+
297+
// Verify no duplicates across pages even with search
298+
$overlap = array_intersect( $page1_ids, $page2_ids );
299+
$this->assertEmpty( $overlap, 'Pages should not contain duplicate posts even with search' );
300+
}
301+
}

0 commit comments

Comments
 (0)