Skip to content

Commit 83efab1

Browse files
committed
Refactor deterministic ordering tests to utilize shared fixtures for post creation. Introduced separate arrays for posts with identical dates, titles, and menu orders to enhance test clarity and maintainability. Updated queries to reference these shared fixtures, ensuring consistent results across pagination and ordering scenarios.
1 parent 0fedb3f commit 83efab1

File tree

1 file changed

+200
-71
lines changed

1 file changed

+200
-71
lines changed

tests/phpunit/tests/query/deterministicOrdering.php

Lines changed: 200 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,135 @@
1111
class Tests_Query_DeterministicOrdering extends WP_UnitTestCase {
1212

1313
/**
14-
* Test that deterministic ordering prevents duplicate records across pages.
14+
* Post IDs for posts with identical dates (for date ordering tests).
1515
*
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.
16+
* @var array
17+
*/
18+
protected static $date_identical_post_ids = array();
19+
20+
/**
21+
* Post IDs for posts with identical titles (for title ordering tests).
1922
*
20-
* @ticket xxxxx
23+
* @var array
2124
*/
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();
25+
protected static $title_identical_post_ids = array();
26+
27+
/**
28+
* Post IDs for search tests.
29+
*
30+
* @var array
31+
*/
32+
protected static $search_post_ids = array();
33+
34+
/**
35+
* Post IDs for menu_order tests.
36+
*
37+
* @var array
38+
*/
39+
protected static $menu_order_post_ids = array();
40+
41+
/**
42+
* Set up shared fixtures for all tests.
43+
*/
44+
public static function set_up_before_class() {
45+
parent::set_up_before_class();
2646

47+
// Register custom post types for test isolation.
48+
register_post_type(
49+
'wptests_time_ident',
50+
array(
51+
'public' => true,
52+
)
53+
);
54+
55+
register_post_type(
56+
'wptests_title_ident',
57+
array(
58+
'public' => true,
59+
)
60+
);
61+
62+
// Create posts with identical dates for date ordering tests.
63+
$identical_date = '2023-01-01 10:00:00';
2764
for ( $i = 1; $i <= 20; $i++ ) {
28-
$post_ids[] = self::factory()->post->create(
65+
self::$date_identical_post_ids[] = self::factory()->post->create(
2966
array(
67+
'post_type' => 'wptests_time_ident',
3068
'post_title' => "Post $i",
3169
'post_date' => $identical_date,
3270
)
3371
);
3472
}
3573

74+
// Create posts with identical titles for title ordering tests.
75+
$identical_title = 'Same Title';
76+
for ( $i = 1; $i <= 15; $i++ ) {
77+
self::$title_identical_post_ids[] = self::factory()->post->create(
78+
array(
79+
'post_type' => 'wptests_title_ident',
80+
'post_title' => $identical_title,
81+
'post_date' => '2023-01-' . str_pad( (string) $i, 2, '0', STR_PAD_LEFT ) . ' 10:00:00',
82+
)
83+
);
84+
}
85+
86+
// Create posts for search tests.
87+
$identical_date = '2023-01-01 10:00:00';
88+
for ( $i = 1; $i <= 12; $i++ ) {
89+
self::$search_post_ids[] = self::factory()->post->create(
90+
array(
91+
'post_type' => 'wptests_time_ident',
92+
'post_title' => "Test Post $i",
93+
'post_content' => 'This is a test post',
94+
'post_date' => $identical_date,
95+
)
96+
);
97+
}
98+
99+
// Create pages with identical menu_order for menu_order tests.
100+
for ( $i = 1; $i <= 20; $i++ ) {
101+
self::$menu_order_post_ids[] = self::factory()->post->create(
102+
array(
103+
'post_type' => 'page',
104+
'post_title' => "Page $i",
105+
'menu_order' => 0, // All pages have same menu_order
106+
)
107+
);
108+
}
109+
}
110+
111+
/**
112+
* Clean up after all tests.
113+
*/
114+
public static function tear_down_after_class() {
115+
_unregister_post_type( 'wptests_time_ident' );
116+
_unregister_post_type( 'wptests_title_ident' );
117+
118+
self::$date_identical_post_ids = array();
119+
self::$title_identical_post_ids = array();
120+
self::$search_post_ids = array();
121+
self::$menu_order_post_ids = array();
122+
123+
parent::tear_down_after_class();
124+
}
125+
126+
/**
127+
* Test that deterministic ordering prevents duplicate records across pages.
128+
*
129+
* This is the core test for the bug fix. When multiple posts have the same
130+
* value for a field (like post_date), pagination can show duplicate records
131+
* without deterministic ordering.
132+
*
133+
* @ticket xxxxx
134+
*/
135+
public function test_deterministic_ordering_prevents_duplicates_across_pages() {
136+
// Use shared fixtures with identical post_date
137+
36138
// Get first page
37139
$query1 = new WP_Query(
38140
array(
141+
'post_type' => 'wptests_time_ident',
142+
'post__in' => self::$date_identical_post_ids,
39143
'orderby' => 'post_date',
40144
'order' => 'ASC',
41145
'posts_per_page' => 10,
@@ -46,6 +150,8 @@ public function test_deterministic_ordering_prevents_duplicates_across_pages() {
46150
// Get second page
47151
$query2 = new WP_Query(
48152
array(
153+
'post_type' => 'wptests_time_ident',
154+
'post__in' => self::$date_identical_post_ids,
49155
'orderby' => 'post_date',
50156
'order' => 'ASC',
51157
'posts_per_page' => 10,
@@ -68,6 +174,8 @@ public function test_deterministic_ordering_prevents_duplicates_across_pages() {
68174
// Verify deterministic ordering: same query should return same results
69175
$query1_repeat = new WP_Query(
70176
array(
177+
'post_type' => 'wptests_time_ident',
178+
'post__in' => self::$date_identical_post_ids,
71179
'orderby' => 'post_date',
72180
'order' => 'ASC',
73181
'posts_per_page' => 10,
@@ -85,21 +193,12 @@ public function test_deterministic_ordering_prevents_duplicates_across_pages() {
85193
* @ticket xxxxx
86194
*/
87195
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-" . str_pad((string) $i, 2, '0', STR_PAD_LEFT) . " 10:00:00",
96-
)
97-
);
98-
}
99-
196+
// Use shared fixtures with identical post_title
100197
// Get first page
101198
$query1 = new WP_Query(
102199
array(
200+
'post_type' => 'wptests_title_ident',
201+
'post__in' => self::$title_identical_post_ids,
103202
'orderby' => 'post_title',
104203
'order' => 'ASC',
105204
'posts_per_page' => 8,
@@ -110,6 +209,8 @@ public function test_deterministic_ordering_with_post_title() {
110209
// Get second page
111210
$query2 = new WP_Query(
112211
array(
212+
'post_type' => 'wptests_title_ident',
213+
'post__in' => self::$title_identical_post_ids,
113214
'orderby' => 'post_title',
114215
'order' => 'ASC',
115216
'posts_per_page' => 8,
@@ -131,21 +232,12 @@ public function test_deterministic_ordering_with_post_title() {
131232
* @ticket xxxxx
132233
*/
133234
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-
235+
// Use shared fixtures with identical post_date
146236
// Get first page with DESC order
147237
$query1 = new WP_Query(
148238
array(
239+
'post_type' => 'wptests_time_ident',
240+
'post__in' => self::$date_identical_post_ids,
149241
'orderby' => 'post_date',
150242
'order' => 'DESC',
151243
'posts_per_page' => 6,
@@ -156,6 +248,8 @@ public function test_deterministic_ordering_with_desc_order() {
156248
// Get second page with DESC order
157249
$query2 = new WP_Query(
158250
array(
251+
'post_type' => 'wptests_time_ident',
252+
'post__in' => self::$date_identical_post_ids,
159253
'orderby' => 'post_date',
160254
'order' => 'DESC',
161255
'posts_per_page' => 6,
@@ -177,21 +271,12 @@ public function test_deterministic_ordering_with_desc_order() {
177271
* @ticket xxxxx
178272
*/
179273
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-
274+
// Use shared fixtures with identical post_date
192275
// Test with array orderby
193276
$query1 = new WP_Query(
194277
array(
278+
'post_type' => 'wptests_time_ident',
279+
'post__in' => self::$date_identical_post_ids,
195280
'orderby' => array(
196281
'post_date' => 'ASC',
197282
'post_title' => 'ASC',
@@ -203,6 +288,8 @@ public function test_deterministic_ordering_with_array_orderby() {
203288

204289
$query2 = new WP_Query(
205290
array(
291+
'post_type' => 'wptests_time_ident',
292+
'post__in' => self::$date_identical_post_ids,
206293
'orderby' => array(
207294
'post_date' => 'ASC',
208295
'post_title' => 'ASC',
@@ -226,20 +313,11 @@ public function test_deterministic_ordering_with_array_orderby() {
226313
* @ticket xxxxx
227314
*/
228315
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-
316+
// Use shared fixtures with identical post_date
241317
$query = new WP_Query(
242318
array(
319+
'post_type' => 'wptests_time_ident',
320+
'post__in' => self::$date_identical_post_ids,
243321
'orderby' => 'ID',
244322
'order' => 'ASC',
245323
'posts_per_page' => 10,
@@ -257,22 +335,12 @@ public function test_deterministic_ordering_does_not_duplicate_id() {
257335
* @ticket xxxxx
258336
*/
259337
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-
338+
// Use shared fixtures for search tests
273339
// Test with search
274340
$query1 = new WP_Query(
275341
array(
342+
'post_type' => 'wptests_time_ident',
343+
'post__in' => self::$search_post_ids,
276344
's' => 'test',
277345
'orderby' => 'post_date',
278346
'order' => 'ASC',
@@ -283,6 +351,8 @@ public function test_deterministic_ordering_with_search() {
283351

284352
$query2 = new WP_Query(
285353
array(
354+
'post_type' => 'wptests_time_ident',
355+
'post__in' => self::$search_post_ids,
286356
's' => 'test',
287357
'orderby' => 'post_date',
288358
'order' => 'ASC',
@@ -298,4 +368,63 @@ public function test_deterministic_ordering_with_search() {
298368
$overlap = array_intersect( $page1_ids, $page2_ids );
299369
$this->assertEmpty( $overlap, 'Pages should not contain duplicate posts even with search' );
300370
}
371+
372+
/**
373+
* Test that deterministic ordering works with menu_order field.
374+
*
375+
* @ticket xxxxx
376+
*/
377+
public function test_deterministic_ordering_with_menu_order() {
378+
// Use shared fixtures with identical menu_order
379+
// Get first page
380+
$query1 = new WP_Query(
381+
array(
382+
'post_type' => 'page',
383+
'post__in' => self::$menu_order_post_ids,
384+
'orderby' => 'menu_order',
385+
'order' => 'ASC',
386+
'posts_per_page' => 10,
387+
'paged' => 1,
388+
)
389+
);
390+
391+
// Get second page
392+
$query2 = new WP_Query(
393+
array(
394+
'post_type' => 'page',
395+
'post__in' => self::$menu_order_post_ids,
396+
'orderby' => 'menu_order',
397+
'order' => 'ASC',
398+
'posts_per_page' => 10,
399+
'paged' => 2,
400+
)
401+
);
402+
403+
$page1_ids = wp_list_pluck( $query1->posts, 'ID' );
404+
$page2_ids = wp_list_pluck( $query2->posts, 'ID' );
405+
406+
// Verify no overlap between pages (no duplicates)
407+
$overlap = array_intersect( $page1_ids, $page2_ids );
408+
$this->assertEmpty( $overlap, 'Pages should not contain duplicate posts when ordering by menu_order' );
409+
410+
// Verify total count is correct
411+
$this->assertEquals( 20, $query1->found_posts, 'Total pages should be 20' );
412+
$this->assertEquals( 10, count( $page1_ids ), 'First page should have 10 pages' );
413+
$this->assertEquals( 10, count( $page2_ids ), 'Second page should have 10 pages' );
414+
415+
// Verify deterministic ordering: same query should return same results
416+
$query1_repeat = new WP_Query(
417+
array(
418+
'post_type' => 'page',
419+
'post__in' => self::$menu_order_post_ids,
420+
'orderby' => 'menu_order',
421+
'order' => 'ASC',
422+
'posts_per_page' => 10,
423+
'paged' => 1,
424+
)
425+
);
426+
$page1_repeat_ids = wp_list_pluck( $query1_repeat->posts, 'ID' );
427+
428+
$this->assertEquals( $page1_ids, $page1_repeat_ids, 'Same query should return same results when ordering by menu_order' );
429+
}
301430
}

0 commit comments

Comments
 (0)