@@ -4,8 +4,10 @@ import (
44 "testing"
55 "time"
66
7+ "github.com/go-faker/faker/v4/pkg/options"
78 "github.com/stretchr/testify/assert"
89
10+ "github.com/ourstudio-se/puan-sdk-go/internal/fake"
911 "github.com/ourstudio-se/puan-sdk-go/puan"
1012)
1113
@@ -454,3 +456,121 @@ func Test_givenTimeEnabledWithoutTimeboundConstraints_andLateFromSpecified_shoul
454456 _ , err := solutionCreator .Create (nil , ruleset , & afterEnd )
455457 assert .Error (t , err )
456458}
459+
460+ // Global XOR rule for item1 and item2,
461+ // item2 has many consequences in the first period.
462+ // The solver should choose the first period when item2 is selected.
463+ func Test_givenXORWithManyConsequencesInFirstPeriod_shouldChooseFirstPeriod (t * testing.T ) {
464+ creator := puan .NewRulesetCreator ()
465+ startTime := time .Now ()
466+ endTime := startTime .Add (1 * time .Hour )
467+ _ = creator .EnableTime (startTime , endTime )
468+
469+ item1 := fake .New [string ]()
470+ item2 := fake .New [string ]()
471+ _ = creator .AddPrimitives (item1 , item2 )
472+ xorID , _ := creator .SetXor (item1 , item2 )
473+ _ = creator .Assume (xorID )
474+
475+ item2Consequences := fake.New [[]string ](
476+ func (oo * options.Options ) {
477+ oo .RandomMinSliceSize = 50
478+ oo .RandomMaxSliceSize = 50
479+ },
480+ )
481+ _ = creator .AddPrimitives (item2Consequences ... )
482+
483+ andID , _ := creator .SetAnd (item2Consequences ... )
484+ item2Implies , _ := creator .SetImply (item2 , andID )
485+
486+ endOfFirstPeriod := startTime .Add (30 * time .Minute )
487+ _ = creator .AssumeInPeriod (item2Implies , startTime , endOfFirstPeriod )
488+
489+ ruleset , _ := creator .Create ()
490+
491+ envelope , _ := solutionCreator .Create (
492+ puan.Selections {
493+ puan .NewSelectionBuilder (item2 ).Build (),
494+ },
495+ ruleset ,
496+ & startTime ,
497+ )
498+
499+ solution := envelope .Solution ()
500+
501+ asserter := newSolutionAsserter (solution )
502+ asserter .assertActive (t , item2 )
503+ asserter .assertActive (t , "period_0" )
504+ asserter .assertActive (t , item2Consequences ... )
505+ asserter .assertInactive (t , item1 )
506+ asserter .assertInactive (t , "period_1" )
507+ }
508+
509+ // Global XOR rules for item1 and many other items,
510+ // all other items are preferred in the first period.
511+ // The solver should choose the first period when item1 is selected.
512+ func Test_givenXORWithManyPreferredInFirstPeriod_shouldChooseFirstPeriod (t * testing.T ) {
513+ creator := puan .NewRulesetCreator ()
514+ startTime := time .Now ()
515+ endTime := startTime .Add (1 * time .Hour )
516+ _ = creator .EnableTime (startTime , endTime )
517+
518+ item1 := fake .New [string ]()
519+ _ = creator .AddPrimitives (item1 )
520+
521+ otherItems := fake.New [[]string ](
522+ func (oo * options.Options ) {
523+ oo .RandomMinSliceSize = 50
524+ oo .RandomMaxSliceSize = 50
525+ },
526+ )
527+ _ = creator .AddPrimitives (otherItems ... )
528+
529+ endOfFirstPeriod := startTime .Add (30 * time .Minute )
530+ for _ , otherItem := range otherItems {
531+ xorID , _ := creator .SetXor (item1 , otherItem )
532+ _ = creator .Assume (xorID )
533+ preferredOtherItem , _ := creator .SetImply (xorID , otherItem )
534+ _ = creator .PreferInPeriod (preferredOtherItem , startTime , endOfFirstPeriod )
535+ }
536+
537+ ruleset , _ := creator .Create ()
538+
539+ envelope , _ := solutionCreator .Create (
540+ puan.Selections {
541+ puan .NewSelectionBuilder (item1 ).Build (),
542+ },
543+ ruleset ,
544+ & startTime ,
545+ )
546+
547+ solution := envelope .Solution ()
548+
549+ asserter := newSolutionAsserter (solution )
550+ asserter .assertActive (t , item1 )
551+ asserter .assertActive (t , "period_0" )
552+ asserter .assertInactive (t , otherItems ... )
553+ asserter .assertInactive (t , "period_1" )
554+ }
555+
556+ type solutionAsserter struct {
557+ puan.Solution
558+ }
559+
560+ func newSolutionAsserter (solution puan.Solution ) solutionAsserter {
561+ return solutionAsserter {solution }
562+ }
563+
564+ func (s solutionAsserter ) assertActive (t * testing.T , variables ... string ) {
565+ solution := s .Extract (variables ... )
566+ for variable , value := range solution {
567+ assert .Equal (t , 1 , value , "expected %s to be active" , variable )
568+ }
569+ }
570+
571+ func (s solutionAsserter ) assertInactive (t * testing.T , variables ... string ) {
572+ solution := s .Extract (variables ... )
573+ for variable , value := range solution {
574+ assert .Equal (t , 0 , value , "expected %s to be inactive" , variable )
575+ }
576+ }
0 commit comments