@@ -356,12 +356,12 @@ void testSingleActivityPlanSimpleCoexistenceGoalWithValueAtParams() {
356
356
BANANANATION ,
357
357
List .of (new ActivityDirective (
358
358
Duration .ZERO ,
359
- "GrowBanana" ,
360
- Map .of (
361
- "quantity" , SerializedValue .of (3 ),
362
- "growingDuration" , SerializedValue .of (growBananaDuration .in (Duration .MICROSECONDS ))),
363
- null ,
364
- true )),
359
+ "GrowBanana" ,
360
+ Map .of (
361
+ "quantity" , SerializedValue .of (3 ),
362
+ "growingDuration" , SerializedValue .of (growBananaDuration .in (Duration .MICROSECONDS ))),
363
+ null ,
364
+ true )),
365
365
List .of (new SchedulingGoal (new GoalId (0L , 0L ), """
366
366
export default () => Goal.CoexistenceGoal({
367
367
forEach: ActivityExpression.ofType(ActivityTypes.GrowBanana),
@@ -440,6 +440,54 @@ export default () => Goal.CoexistenceGoal({
440
440
}
441
441
}
442
442
443
+ /**
444
+ * Here the anchor window is [01:00:00, plan end]. The coexisting activity starts at 00:55:00 and the `valueAt` interval for
445
+ * the parametric parameter is then outside of the anchor window causing the intervals not to intersect as the valueAt
446
+ * was evaluated only in the start ([00:55:00, 00:55:00]) interval. Now, it is evaluated in Interval.FOREVER. Determining
447
+ * the right bounds for simulation is the scheduler's responsability (upstream of the goal conflict evaluation).
448
+ */
449
+ @ Test
450
+ void testBugValueAt () {
451
+ final var growBananaDuration = Duration .of (1 , Duration .HOUR );
452
+ final var results = runScheduler (
453
+ BANANANATION ,
454
+ List .of (new ActivityDirective (
455
+ Duration .HOUR ,
456
+ "GrowBanana" ,
457
+ Map .of (
458
+ "quantity" , SerializedValue .of (3 ),
459
+ "growingDuration" , SerializedValue .of (growBananaDuration .in (Duration .MICROSECONDS ))),
460
+ null ,
461
+ true ),
462
+ new ActivityDirective (
463
+ Duration .MINUTE .times (50 ),
464
+ "ChangeProducer" ,
465
+ Map .of (
466
+ "producer" , SerializedValue .of ("Company" )),
467
+ null ,
468
+ true )),
469
+ List .of (new SchedulingGoal (new GoalId (0L , 0L ), """
470
+ export default () => Goal.CoexistenceGoal({
471
+ forEach: Real.Resource("/fruit").greaterThan(4.0),
472
+ activityTemplate: interval => ActivityTemplates.ChangeProducer({producer: Discrete.Resource("/producer").valueAt(Spans.FromInterval(interval).starts())}),
473
+ startsAt: TimingConstraint.singleton(WindowProperty.START).minus(Temporal.Duration.from({ minutes : 5}))
474
+ })
475
+ """ , true )),
476
+ PLANNING_HORIZON );
477
+
478
+ assertEquals (1 , results .scheduleResults .goalResults ().size ());
479
+ final var goalResult = results .scheduleResults .goalResults ().get (new GoalId (0L , 0L ));
480
+
481
+ assertTrue (goalResult .satisfied ());
482
+ assertEquals (1 , goalResult .createdActivities ().size ());
483
+ assertEquals (1 , goalResult .satisfyingActivities ().size ());
484
+ final var activityCreated = results .updatedPlan
485
+ .stream ()
486
+ .filter (a -> a .startOffset ().isEqualTo (Duration .MINUTES .times (55 )))
487
+ .collect (Collectors .toSet ());
488
+ assertEquals (1 , activityCreated .size ());
489
+ assertEquals (new SerializedValue .StringValue ("Company" ), activityCreated .iterator ().next ().serializedActivity ().getArguments ().get ("producer" ));
490
+ }
443
491
444
492
@ Test
445
493
void testCoexistenceGoalWithAnchors () {
0 commit comments