@@ -191,6 +191,169 @@ public void filter_1_changed() {
191191 assertMatch (value2 , entity3 ));
192192 }
193193
194+ @ TestTemplate
195+ public void filter_0_changed_forEachUnfilteredUniquePair () {
196+ var solution = TestdataLavishSolution .generateSolution ();
197+ var entityGroup = new TestdataLavishEntityGroup ("MyEntityGroup" );
198+ var valueGroup = new TestdataLavishValueGroup ("MyValueGroup" );
199+ solution .getEntityGroupList ().add (entityGroup );
200+ solution .getValueGroupList ().add (valueGroup );
201+
202+ var value1 = Mockito .spy (new TestdataLavishValue ("MyValue 1" , valueGroup ));
203+ solution .getValueList ().add (value1 );
204+ var value2 = Mockito .spy (new TestdataLavishValue ("MyValue 2" , valueGroup ));
205+ solution .getValueList ().add (value2 );
206+ var value3 = Mockito .spy (new TestdataLavishValue ("MyValue 3" , null ));
207+ solution .getValueList ().add (value3 );
208+
209+ var entity1 = Mockito .spy (new TestdataLavishEntity ("MyEntity 1" , entityGroup , value1 ));
210+ solution .getEntityList ().add (entity1 );
211+ var entity2 = new TestdataLavishEntity ("MyEntity 2" , entityGroup , value1 );
212+ solution .getEntityList ().add (entity2 );
213+ var entity3 = new TestdataLavishEntity ("MyEntity 3" , solution .getFirstEntityGroup (),
214+ value1 );
215+ solution .getEntityList ().add (entity3 );
216+
217+ var scoreDirector =
218+ buildScoreDirector (factory -> factory
219+ .precompute (data -> data .forEachUnfilteredUniquePair (TestdataLavishEntity .class ,
220+ Joiners .equal (TestdataLavishEntity ::getEntityGroup )))
221+ .filter ((a , b ) -> a .getValue () == value1 )
222+ .penalize (SimpleScore .ONE )
223+ .asConstraint (TEST_CONSTRAINT_NAME ));
224+
225+ // From scratch
226+ Mockito .reset (entity1 );
227+ scoreDirector .setWorkingSolution (solution );
228+ assertScore (scoreDirector ,
229+ assertMatch (entity1 , entity2 ));
230+ Mockito .verify (entity1 , Mockito .atLeastOnce ()).getEntityGroup ();
231+
232+ // Incrementally update a variable
233+ Mockito .reset (entity1 );
234+ scoreDirector .beforeVariableChanged (entity1 , "value" );
235+ entity1 .setValue (solution .getFirstValue ());
236+ scoreDirector .afterVariableChanged (entity1 , "value" );
237+ assertScore (scoreDirector );
238+ Mockito .verify (entity1 , Mockito .never ()).getEntityGroup ();
239+
240+ // Incrementally update a variable
241+ Mockito .reset (entity1 );
242+ scoreDirector .beforeVariableChanged (entity1 , "value" );
243+ entity1 .setValue (value1 );
244+ scoreDirector .afterVariableChanged (entity1 , "value" );
245+ assertScore (scoreDirector ,
246+ assertMatch (entity1 , entity2 ));
247+ Mockito .verify (entity1 , Mockito .never ()).getEntityGroup ();
248+
249+ // Incrementally update a fact
250+ scoreDirector .beforeProblemPropertyChanged (entity3 );
251+ entity3 .setEntityGroup (entityGroup );
252+ scoreDirector .afterProblemPropertyChanged (entity3 );
253+ assertScore (scoreDirector ,
254+ assertMatch (entity1 , entity2 ),
255+ assertMatch (entity1 , entity3 ),
256+ assertMatch (entity2 , entity3 ));
257+
258+ // Remove entity
259+ scoreDirector .beforeEntityRemoved (entity3 );
260+ solution .getEntityList ().remove (entity3 );
261+ scoreDirector .afterEntityRemoved (entity3 );
262+ assertScore (scoreDirector ,
263+ assertMatch (entity1 , entity2 ));
264+
265+ // Add it back again, to make sure it was properly removed before
266+ scoreDirector .beforeEntityAdded (entity3 );
267+ solution .getEntityList ().add (entity3 );
268+ scoreDirector .afterEntityAdded (entity3 );
269+ assertScore (scoreDirector ,
270+ assertMatch (entity1 , entity2 ),
271+ assertMatch (entity1 , entity3 ),
272+ assertMatch (entity2 , entity3 ));
273+ }
274+
275+ @ TestTemplate
276+ public void filter_1_changed_forEachUnfilteredUniquePair () {
277+ var solution = TestdataLavishSolution .generateSolution ();
278+ var entityGroup = new TestdataLavishEntityGroup ("MyEntityGroup" );
279+ var valueGroup = new TestdataLavishValueGroup ("MyValueGroup" );
280+ solution .getEntityGroupList ().add (entityGroup );
281+ solution .getValueGroupList ().add (valueGroup );
282+
283+ var value1 = Mockito .spy (new TestdataLavishValue ("MyValue 1" , valueGroup ));
284+ solution .getValueList ().add (value1 );
285+ var value2 = Mockito .spy (new TestdataLavishValue ("MyValue 2" , valueGroup ));
286+ solution .getValueList ().add (value2 );
287+ var value3 = Mockito .spy (new TestdataLavishValue ("MyValue 3" , null ));
288+ solution .getValueList ().add (value3 );
289+
290+ var entity1 = new TestdataLavishEntity ("MyEntity 1" , entityGroup , value1 );
291+ solution .getEntityList ().add (entity1 );
292+ var entity2 = Mockito .spy (new TestdataLavishEntity ("MyEntity 2" , entityGroup , value1 ));
293+ solution .getEntityList ().add (entity2 );
294+ var entity3 = new TestdataLavishEntity ("MyEntity 3" , solution .getFirstEntityGroup (),
295+ value2 );
296+ solution .getEntityList ().add (entity3 );
297+
298+ var scoreDirector =
299+ buildScoreDirector (factory -> factory
300+ .precompute (data -> data .forEachUnfilteredUniquePair (TestdataLavishEntity .class ,
301+ Joiners .equal (TestdataLavishEntity ::getEntityGroup )))
302+ .filter ((a , b ) -> b .getValue () == value1 )
303+ .penalize (SimpleScore .ONE )
304+ .asConstraint (TEST_CONSTRAINT_NAME ));
305+
306+ // From scratch
307+ Mockito .reset (entity2 );
308+ scoreDirector .setWorkingSolution (solution );
309+ assertScore (scoreDirector ,
310+ assertMatch (entity1 , entity2 ));
311+ Mockito .verify (entity2 , Mockito .atLeastOnce ()).getEntityGroup ();
312+
313+ // Incrementally update a variable
314+ Mockito .reset (entity2 );
315+ scoreDirector .beforeVariableChanged (entity2 , "value" );
316+ entity2 .setValue (solution .getFirstValue ());
317+ scoreDirector .afterVariableChanged (entity2 , "value" );
318+ assertScore (scoreDirector );
319+ Mockito .verify (entity2 , Mockito .never ()).getEntityGroup ();
320+
321+ // Incrementally update a variable
322+ Mockito .reset (entity2 );
323+ scoreDirector .beforeVariableChanged (entity2 , "value" );
324+ entity2 .setValue (value1 );
325+ scoreDirector .afterVariableChanged (entity2 , "value" );
326+ assertScore (scoreDirector ,
327+ assertMatch (entity1 , entity2 ));
328+ Mockito .verify (entity2 , Mockito .never ()).getEntityGroup ();
329+
330+ // Incrementally update a fact
331+ scoreDirector .beforeProblemPropertyChanged (entity3 );
332+ entity3 .setValue (value1 );
333+ entity3 .setEntityGroup (entityGroup );
334+ scoreDirector .afterProblemPropertyChanged (entity3 );
335+ assertScore (scoreDirector ,
336+ assertMatch (entity1 , entity2 ),
337+ assertMatch (entity1 , entity3 ),
338+ assertMatch (entity2 , entity3 ));
339+
340+ // Remove entity
341+ scoreDirector .beforeEntityRemoved (entity3 );
342+ solution .getEntityList ().remove (entity3 );
343+ scoreDirector .afterEntityRemoved (entity3 );
344+ assertScore (scoreDirector ,
345+ assertMatch (entity1 , entity2 ));
346+
347+ // Add it back again, to make sure it was properly removed before
348+ scoreDirector .beforeEntityAdded (entity3 );
349+ solution .getEntityList ().add (entity3 );
350+ scoreDirector .afterEntityAdded (entity3 );
351+ assertScore (scoreDirector ,
352+ assertMatch (entity1 , entity2 ),
353+ assertMatch (entity1 , entity3 ),
354+ assertMatch (entity2 , entity3 ));
355+ }
356+
194357 private <A , B > void assertPrecompute (TestdataLavishSolution solution ,
195358 List <Pair <A , B >> expectedValues ,
196359 Function <PrecomputeFactory , BiConstraintStream <A , B >> entityStreamSupplier ) {
0 commit comments