@@ -119,6 +119,76 @@ ActionChainArbitrary<String> xOrFailing() {
119119 .withMaxTransformations (30 );
120120 }
121121
122+ static class SetMutatingChainState {
123+ final List <String > actualOps = new ArrayList <>();
124+ final Set <Integer > set = new HashSet <>();
125+
126+ @ Override
127+ public String toString () {
128+ return "set=" + set + ", actualOps=" + actualOps ;
129+ }
130+ }
131+
132+ @ Property
133+ void chainActionsAreProperlyDescribedEvenAfterChainExecution (@ ForAll ("setMutatingChain" ) ActionChain <SetMutatingChainState > chain ) {
134+ SetMutatingChainState finalState = chain .run ();
135+
136+ assertThat (chain .transformations ())
137+ .describedAs ("chain.transformations() should be the same as the list of operations in finalState.actualOps, final state is %s" , finalState .set )
138+ .isEqualTo (finalState .actualOps );
139+ }
140+
141+ @ Provide
142+ public ActionChainArbitrary <SetMutatingChainState > setMutatingChain () {
143+ return
144+ ActionChain
145+ .startWith (SetMutatingChainState ::new )
146+ // This is an action that does not depend on the state to produce the transformation
147+ .addAction (
148+ 1 ,
149+ Action .just ("clear anyway" , state -> {
150+ state .actualOps .add ("clear anyway" );
151+ state .set .clear ();
152+ return state ;
153+ })
154+ )
155+ // Below actions depend on the state to derive the transformations
156+ .addAction (
157+ 1 ,
158+ (Action .Dependent <SetMutatingChainState >)
159+ state ->
160+ Arbitraries
161+ .just (
162+ state .set .isEmpty ()
163+ ? Transformer .noop ()
164+ : Transformer .<SetMutatingChainState >mutate ("clear " + state .set , set -> {
165+ state .actualOps .add ("clear " + set .set );
166+ state .set .clear ();
167+ })
168+ )
169+ )
170+ .addAction (
171+ 2 ,
172+ (Action .Dependent <SetMutatingChainState >)
173+ state ->
174+ Arbitraries
175+ .integers ()
176+ .between (1 , 10 )
177+ .map (i -> {
178+ if (state .set .contains (i )) {
179+ return Transformer .noop ();
180+ } else {
181+ return Transformer .mutate ("add " + i + " to " + state .set , newState -> {
182+ newState .actualOps .add ("add " + i + " to " + newState .set );
183+ newState .set .add (i );
184+ });
185+ }
186+ }
187+ )
188+ )
189+ .withMaxTransformations (5 );
190+ }
191+
122192 @ Property
123193 void chainChoosesBetweenTwoActions (@ ForAll ("xOrY" ) ActionChain <String > chain ) {
124194 String result = chain .run ();
0 commit comments