@@ -76,12 +76,12 @@ protected function setUp(): void
7676 $ this ->invalid_stream_elements = $ this ->setup_capped_invalid_stream_elements ($ blog_ids );
7777
7878 $ this ->enabled_ranker_instance = $ this ->getMockBuilder (CappedPostRanker::class)
79- ->setConstructorArgs ([$ this ->mock_user , $ this ->identity , false , true , 2 , 'dashboard ' , false ])
79+ ->setConstructorArgs ([$ this ->mock_user , $ this ->identity , true , 2 , 'dashboard ' , false , false ])
8080 ->getMock ();
8181 $ this ->enabled_ranker_instance ->method ('can_rank ' )->willReturn (true );
8282
8383 $ this ->disabled_ranker_instance = $ this ->getMockBuilder (CappedPostRanker::class)
84- ->setConstructorArgs ([$ this ->mock_user , $ this ->identity , false , true , 2 , 'dashboard ' , false ])
84+ ->setConstructorArgs ([$ this ->mock_user , $ this ->identity , true , 2 , 'dashboard ' , false , false ])
8585 ->getMock ();
8686 $ this ->disabled_ranker_instance ->method ('can_rank ' )->willReturn (false );
8787 }
@@ -165,7 +165,7 @@ public function test_disabled_rank(): void
165165 public function test_invalid_elements (): void
166166 {
167167 $ this ->expectException (TypeMismatchException::class);
168- $ this ->invokeMethod ($ this ->enabled_ranker_instance , 'pre_fetch ' , $ this ->invalid_stream_elements );
168+ $ this ->invokeMethod ($ this ->enabled_ranker_instance , 'pre_fetch ' , [ $ this ->invalid_stream_elements ] );
169169 }
170170
171171 /**
@@ -176,7 +176,7 @@ public function test_get_blog_dictionaries(): void
176176 $ dictionaries = $ this ->invokeMethod (
177177 $ this ->enabled_ranker_instance ,
178178 'get_blog_dictionaries ' ,
179- $ this ->stream_elements
179+ [ $ this ->stream_elements ]
180180 );
181181 $ post_to_element = $ dictionaries [0 ];
182182 $ blog_to_posts_ids = $ dictionaries [1 ];
@@ -186,28 +186,101 @@ public function test_get_blog_dictionaries(): void
186186 $ this ->assertSame ($ post_id , $ original_element ->get_post_id ());
187187 }
188188 # Which posts belong to which blogs
189- $ expected_blog_to_posts_ids = [111 => [1 , 2 , 3 , 4 , 5 ], 222 => [6 , 7 ], 333 => [8 ]];
190- $ this ->assertEquals ( $ blog_to_posts_ids , $ expected_blog_to_posts_ids );
189+ $ expected_blog_to_posts_ids = [111 => [' 1 ' , ' 2 ' , ' 3 ' , ' 4 ' , ' 5 ' ], 222 => [' 6 ' , ' 7 ' ], 333 => [' 8 ' ]];
190+ $ this ->assertSame ( $ expected_blog_to_posts_ids , $ blog_to_posts_ids );
191191 $ expected_stats_per_blog = [111 => [5 , 0 ], 222 => [2 , 0 ], 333 => [1 , 0 ]];
192- $ this ->assertEquals ($ stats_per_blog , $ expected_stats_per_blog );
192+ $ this ->assertSame ($ expected_stats_per_blog , $ stats_per_blog );
193+ }
194+
195+ /**
196+ * Test that invalidate_post_id properly removes posts from blog_to_posts_ids
197+ */
198+ public function test_invalidate_post_id_removes_posts (): void
199+ {
200+ $ ranker = new CappedPostRanker ($ this ->mock_user , $ this ->identity , true , 2 , 'dashboard ' , false );
201+
202+ // Get initial blog dictionaries using reflection
203+ $ dictionaries = $ this ->invokeMethod ($ ranker , 'get_blog_dictionaries ' , [$ this ->stream_elements ]);
204+ $ blog_to_posts_ids = $ dictionaries [1 ];
205+
206+ // Verify initial state
207+ $ expected_initial = [111 => ['1 ' , '2 ' , '3 ' , '4 ' , '5 ' ], 222 => ['6 ' , '7 ' ], 333 => ['8 ' ]];
208+ $ expected_post_counts = [111 => [5 , 0 ], 222 => [2 , 0 ], 333 => [1 , 0 ]];
209+ $ this ->assertSame ($ expected_initial , $ blog_to_posts_ids );
210+ $ this ->assertSame ($ expected_post_counts , $ dictionaries [2 ]);
211+
212+ // Test invalidating a specific post using reflection
213+ $ violated_post_id = $ this ->invokeMethod ($ ranker , 'invalidate_post_id ' , ['111 ' , '3 ' , &$ blog_to_posts_ids ]);
214+ // The method returns null when a specific post ID is provided, but the post should be removed
215+ $ this ->assertNull ($ violated_post_id );
216+
217+ // Verify post was removed from blog 111
218+ $ this ->assertCount (4 , $ blog_to_posts_ids [111 ]); // Should have 4 posts instead of 5
219+ $ this ->assertContains ('1 ' , $ blog_to_posts_ids [111 ]);
220+ $ this ->assertContains ('2 ' , $ blog_to_posts_ids [111 ]);
221+ $ this ->assertContains ('4 ' , $ blog_to_posts_ids [111 ]);
222+ $ this ->assertContains ('5 ' , $ blog_to_posts_ids [111 ]);
223+ }
224+
225+ /**
226+ * Test that invalidate_post_id returns the first available post when no specific post is provided
227+ */
228+ public function test_invalidate_post_id_returns_first_available (): void
229+ {
230+ $ ranker = new CappedPostRanker ($ this ->mock_user , $ this ->identity , true , 2 , 'dashboard ' , false );
231+
232+ $ dictionaries = $ this ->invokeMethod ($ ranker , 'get_blog_dictionaries ' , [$ this ->stream_elements ]);
233+ $ blog_to_posts_ids = $ dictionaries [1 ];
234+
235+ // Test getting first available post from blog 111 using reflection
236+ $ first_post = $ this ->invokeMethod ($ ranker , 'invalidate_post_id ' , ['111 ' , null , &$ blog_to_posts_ids ]);
237+ $ this ->assertSame (1 , $ first_post ); // Returns integer, not string
238+
239+ // Verify first post was removed
240+ $ this ->assertNotContains ('1 ' , $ blog_to_posts_ids [111 ]);
241+ $ this ->assertCount (4 , $ blog_to_posts_ids [111 ]);
242+ $ this ->assertContains ('2 ' , $ blog_to_posts_ids [111 ]);
243+ $ this ->assertContains ('3 ' , $ blog_to_posts_ids [111 ]);
244+ $ this ->assertContains ('4 ' , $ blog_to_posts_ids [111 ]);
245+ $ this ->assertContains ('5 ' , $ blog_to_posts_ids [111 ]);
246+ }
247+
248+ /**
249+ * Test that invalidate_post_id handles non-existent posts gracefully
250+ */
251+ public function test_invalidate_post_id_nonexistent_post (): void
252+ {
253+ $ ranker = new CappedPostRanker ($ this ->mock_user , $ this ->identity , true , 2 , 'dashboard ' , false , false );
254+
255+ $ dictionaries = $ this ->invokeMethod ($ ranker , 'get_blog_dictionaries ' , [$ this ->stream_elements ]);
256+ $ blog_to_posts_ids = $ dictionaries [1 ];
257+
258+ // Try to invalidate a non-existent post using reflection
259+ $ result = $ this ->invokeMethod ($ ranker , 'invalidate_post_id ' , ['111 ' , '999 ' , &$ blog_to_posts_ids ]);
260+ $ this ->assertNull ($ result );
261+
262+ // Verify no changes were made
263+ $ this ->assertCount (5 , $ blog_to_posts_ids [111 ]);
264+ $ this ->assertContains ('1 ' , $ blog_to_posts_ids [111 ]);
265+ $ this ->assertContains ('2 ' , $ blog_to_posts_ids [111 ]);
266+ $ this ->assertContains ('3 ' , $ blog_to_posts_ids [111 ]);
267+ $ this ->assertContains ('4 ' , $ blog_to_posts_ids [111 ]);
268+ $ this ->assertContains ('5 ' , $ blog_to_posts_ids [111 ]);
193269 }
194270
195271 /**
196272 * Helper method to enable testing private and protected methods
197- * @param object $object The object that the private method belongs to
273+ * @param CappedPostRanker $object The object that the private method belongs to
198274 * @param string $method_name The name of the method we want to test
199275 * @param array $parameters List of parameters passed to the method
200276 * @return mixed Whatever the method would return
201277 * @throws \ReflectionException Something went wrong with reflection
202278 */
203- public function invokeMethod (object &$ object , string $ method_name , array $ parameters = [])
279+ public function invokeMethod (CappedPostRanker &$ object , string $ method_name , array $ parameters = [])
204280 {
205- $ reflection = new \ReflectionClass (get_class ( $ object ) );
281+ $ reflection = new \ReflectionClass (CappedPostRanker::class );
206282 $ method = $ reflection ->getMethod ($ method_name );
207283 $ method ->setAccessible (true );
208- if ($ method_name = 'get_blog_dictionaries ' ) {
209- $ parameters = [$ parameters ];
210- }
211284 return $ method ->invokeArgs ($ object , $ parameters );
212285 }
213286}
0 commit comments