6060import org .spongepowered .common .accessor .world .inventory .AbstractFurnaceMenuAccessor ;
6161import org .spongepowered .common .item .util .ItemStackUtil ;
6262
63+ import java .util .ArrayList ;
6364import java .util .Collections ;
6465import java .util .List ;
6566import java .util .UUID ;
@@ -129,12 +130,12 @@ private static Stream<TestContext> streamCraftingRecipes() {
129130 && stack .maxStackQuantity () == bigPearl .maxStackQuantity (),
130131 pearl );
131132
132- return Stream .of (
133- new TestPopulator ("regular_shaped_crafting" , CraftingRecipe .shapedBuilder ()
133+ return Stream .< TestPopulator > of (
134+ new DefaultedTestPopulator ( new TestContext ("regular_shaped_crafting" , CraftingRecipe .shapedBuilder ()
134135 .aisle ("S S" , " P " )
135136 .where ('S' , stoneIngredient )
136137 .where ('P' , anyPearlIngredient )
137- .result (result ))
138+ .result (result )))
138139
139140 .expectCrafts (8 , 16 )
140141 .expectInput (List .of (
@@ -151,11 +152,11 @@ private static Stream<TestContext> streamCraftingRecipes() {
151152 .badInventory (Collections .nCopies (9 , bedrock ))
152153 .badInput (Collections .nCopies (9 , bedrock )),
153154
154- new TestPopulator ("custom_shaped_crafting" , CraftingRecipe .shapedBuilder ()
155+ new DefaultedTestPopulator ( new TestContext ("custom_shaped_crafting" , CraftingRecipe .shapedBuilder ()
155156 .aisle ("SSS" , "BBB" , "SSS" )
156157 .where ('S' , smallPearlIngredient )
157158 .where ('B' , bigPearlIngredient )
158- .result (result ))
159+ .result (result )))
159160
160161 .expectCrafts (4 , 4 )
161162 .expectInput (List .of (
@@ -172,8 +173,8 @@ private static Stream<TestContext> streamCraftingRecipes() {
172173 .badInventory (List .of (pearl16 ))
173174 .badInput (Collections .nCopies (9 , pearl )),
174175
175- new TestPopulator ("regular_shapeless_crafting" , CraftingRecipe .shapelessBuilder ()
176- .addIngredients (anyPearlIngredient , stoneIngredient , anyPearlIngredient ))
176+ new DefaultedTestPopulator ( new TestContext ("regular_shapeless_crafting" , CraftingRecipe .shapelessBuilder ()
177+ .addIngredients (anyPearlIngredient , stoneIngredient , anyPearlIngredient )))
177178
178179 .expectCrafts (16 , 16 )
179180 .expectInput (List .of (
@@ -191,10 +192,10 @@ private static Stream<TestContext> streamCraftingRecipes() {
191192 .badInput (Collections .nCopies (3 , bedrock ))/*,
192193
193194 //TODO uncomment after shapeless recipe fix
194- new TestPopulator ("custom_shapeless_crafting", CraftingRecipe.shapelessBuilder()
195+ new DefaultedTestPopulator(new TestContext ("custom_shapeless_crafting", CraftingRecipe.shapelessBuilder()
195196 .addIngredients(
196197 smallPearlIngredient, smallPearlIngredient, smallPearlIngredient,
197- bigPearlIngredient, bigPearlIngredient, bigPearlIngredient))
198+ bigPearlIngredient, bigPearlIngredient, bigPearlIngredient)))
198199
199200 .expectCrafts(8, 16)
200201 .expectInput(List.of(
@@ -221,11 +222,11 @@ private static Stream<TestContext> streamSmeltingRecipes() {
221222 bigSnowball .offer (Keys .MAX_STACK_SIZE , 4 );
222223 final ItemStack result = ItemStack .of (ItemTypes .BARRIER );
223224
224- return Stream .of (
225- new TestPopulator ("regular_smelting" , CookingRecipe .builder ()
225+ return Stream .< TestPopulator > of (
226+ new DefaultedTestPopulator ( new TestContext ("regular_smelting" , CookingRecipe .builder ()
226227 .type (RecipeTypes .SMELTING )
227228 .ingredient (Ingredient .of (snowball .type ()))
228- .result (result ))
229+ .result (result )))
229230
230231 .expectCrafts (4 , 8 )
231232 .expectInput (List .of (bigSnowball ))
@@ -234,13 +235,13 @@ private static Stream<TestContext> streamSmeltingRecipes() {
234235 .badInventory (List .of (bedrock ))
235236 .badInput (List .of (bedrock )),
236237
237- new TestPopulator ("custom_smelting" , CookingRecipe .builder ()
238+ new DefaultedTestPopulator ( new TestContext ("custom_smelting" , CookingRecipe .builder ()
238239 .type (RecipeTypes .SMELTING )
239240 .ingredient (Ingredient .of (ResourceKey .sponge ("big_snowball" ),
240241 stack -> stack .type () == bigSnowball .type ()
241242 && stack .maxStackQuantity () == bigSnowball .maxStackQuantity (),
242243 snowball ))
243- .result (result ))
244+ .result (result )))
244245
245246 .expectCrafts (4 , 8 )
246247 .expectInput (List .of (bigSnowball ))
@@ -252,7 +253,7 @@ private static Stream<TestContext> streamSmeltingRecipes() {
252253 }
253254
254255 @ TestFactory
255- public Stream <DynamicTest > testRecipes () {
256+ public Stream <DynamicTest > generateTests () {
256257 return Stream .of (
257258 RecipePlaceTest .streamCraftingRecipes ().map (context ->
258259 dynamicTest (context .asTestName (), context ::testCrafting )),
@@ -261,7 +262,38 @@ public Stream<DynamicTest> testRecipes() {
261262 ).flatMap (Function .identity ());
262263 }
263264
264- private static final class TestPopulator {
265+ @ FunctionalInterface
266+ private interface TestPopulator {
267+
268+ Stream <TestContext > populate ();
269+ }
270+
271+ private static final class SimpleTestPopulator implements TestPopulator {
272+
273+ private final TestContext base ;
274+ private final List <TestContext > tests = new ArrayList <>();
275+
276+ public SimpleTestPopulator (final TestContext base ) {
277+ this .base = base ;
278+ }
279+
280+ public SimpleTestPopulator add (final Function <TestContext , TestContext > testProvider ) {
281+ this .tests .add (testProvider .apply (this .base ));
282+ return this ;
283+ }
284+
285+ public SimpleTestPopulator addAll (final Function <TestContext , Stream <TestContext >> testProvider ) {
286+ testProvider .apply (this .base ).forEach (this .tests ::add );
287+ return this ;
288+ }
289+
290+ @ Override
291+ public Stream <TestContext > populate () {
292+ return this .tests .stream ();
293+ }
294+ }
295+
296+ private static final class DefaultedTestPopulator implements TestPopulator {
265297
266298 private final TestContext base ;
267299
@@ -280,33 +312,27 @@ private static final class TestPopulator {
280312 private List <ItemStack > badInventory = List .of ();
281313 private List <ItemStack > badInput = List .of ();
282314
283- public TestPopulator (final String key , final Builder <? extends org .spongepowered .api .item .recipe .Recipe <?>, ?> recipe ) {
284- this (new RecipeHolder <>(
285- net .minecraft .resources .ResourceKey .create (Registries .RECIPE , ResourceLocation .fromNamespaceAndPath ("sponge" , key )),
286- (Recipe <?>) recipe .build ()));
287- }
288-
289- public TestPopulator (final RecipeHolder <?> recipe ) {
290- this .base = new TestContext (recipe );
315+ public DefaultedTestPopulator (final TestContext base ) {
316+ this .base = base ;
291317 }
292318
293- public TestPopulator expectCrafts (final int regularCrafts , final int shiftCrafts ) {
319+ public DefaultedTestPopulator expectCrafts (final int regularCrafts , final int shiftCrafts ) {
294320 this .expectedRegularCrafts = regularCrafts ;
295321 this .expectedShiftCrafts = shiftCrafts ;
296322 return this ;
297323 }
298324
299- public TestPopulator expectInput (final List <ItemStack > items ) {
325+ public DefaultedTestPopulator expectInput (final List <ItemStack > items ) {
300326 this .expectedInput = items ;
301327 return this ;
302328 }
303329
304- public TestPopulator partialInventory (final List <ItemStack > items ) {
330+ public DefaultedTestPopulator partialInventory (final List <ItemStack > items ) {
305331 this .partialInventory = items ;
306332 return this ;
307333 }
308334
309- public TestPopulator partialInput (final List <ItemStack > items ) {
335+ public DefaultedTestPopulator partialInput (final List <ItemStack > items ) {
310336 this .partialInput = items ;
311337 return this ;
312338 }
@@ -321,6 +347,7 @@ public TestPopulator badInput(final List<ItemStack> items) {
321347 return this ;
322348 }
323349
350+ @ Override
324351 public Stream <TestContext > populate () {
325352 final List <ItemStack > totalInitialInventory = Stream .concat (this .partialInventory .stream (), this .partialInput .stream ()).toList ();
326353 final List <ItemStack > expectedShiftInput = RecipePlaceTest .createExpectedInput (this .expectedInput , this .expectedShiftCrafts );
@@ -329,28 +356,31 @@ public Stream<TestContext> populate() {
329356 this .base .name ("Bad input" ).input (this .badInput )
330357 );
331358
332- final Stream <TestContext > toFail = baseInputs .stream ()
359+ final Stream <TestContext > testBadLayouts = baseInputs .stream ()
333360 .flatMap (context -> Stream .of (
334361 context .name ("Empty inventory" ).inventory (List .of ()),
335362 context .name ("Bad inventory" ).inventory (this .badInventory )
336363 ))
337364 .flatMap (context -> Stream .of (context , context .shift ()))
338- // 2 clicks is enough to ensure we always fail
365+ .flatMap (context -> Stream .of (context , context .creative ()))
366+ // 2 clicks is enough to ensure we always get empty input
339367 .map (context -> context .expectInputs (List .of (List .of (), List .of ())));
340368
341- final Stream <TestContext > toMatchSingleClick = baseInputs .stream ()
369+ final Stream <TestContext > testSingleClick = baseInputs .stream ()
342370 .map (context -> context .name ("Total inventory" ).inventory (totalInitialInventory ))
371+ .flatMap (context -> Stream .of (context , context .creative ()))
343372 .flatMap (context -> Stream .of (
344373 context .expectInput (RecipePlaceTest .createExpectedInput (this .expectedInput , 1 )),
345374 context .shift ().expectInput (expectedShiftInput )
346375 ));
347376
348377 // After first click we end up with the same layout no matter the initial input.
349378 // So we can perform multiple-click tests on a single input.
350- final Stream <TestContext > toMatchMultipleClicks = Stream .of (this .base )
379+ final Stream <TestContext > testMultipleClicks = Stream .of (this .base )
351380 .map (context -> context
352381 .name ("Partial input" ).input (this .partialInput )
353382 .name ("Partial inventory" ).inventory (this .partialInventory ))
383+ .flatMap (context -> Stream .of (context , context .creative ()))
354384 .flatMap (context -> Stream .of (
355385 context
356386 .expectInputs (IntStream .rangeClosed (1 , this .expectedRegularCrafts )
@@ -360,50 +390,73 @@ public Stream<TestContext> populate() {
360390 context .shift ().expectInputs (List .of (expectedShiftInput , expectedShiftInput ))
361391 ));
362392
363- return Stream .concat (toFail , Stream .concat (toMatchSingleClick , toMatchMultipleClicks ));
393+ final Stream <TestContext > testFullInventory = Stream .of (this .base )
394+ .map (context -> context
395+ .name ("Partial input" ).input (this .partialInput )
396+ .name ("Full inventory" ).inventory (Collections .nCopies (36 , ItemStack .of (ItemTypes .BARRIER , 64 ))))
397+ .flatMap (context -> Stream .of (context , context .shift ()))
398+ .flatMap (context -> Stream .of (
399+ context .expectInput (this .partialInput ),
400+ context .creative ().expectInput (List .of ())
401+ ));
402+
403+ return Stream .of (testBadLayouts , testSingleClick , testMultipleClicks , testFullInventory )
404+ .flatMap (Function .identity ());
364405 }
365406 }
366407
367408 private record TestContext (
368- RecipeHolder <?> recipe , String testName , boolean shiftClick ,
409+ RecipeHolder <?> recipe , String testName ,
410+ boolean shiftClick , boolean creativeMode ,
369411 List <ItemStack > inventory , List <ItemStack > input ,
370412 List <List <ItemStack >> expectedInputs
371413 ) {
414+ public TestContext (final String key , final Builder <? extends org .spongepowered .api .item .recipe .Recipe <?>, ?> recipe ) {
415+ this (new RecipeHolder <>(
416+ net .minecraft .resources .ResourceKey .create (Registries .RECIPE , ResourceLocation .fromNamespaceAndPath ("sponge" , key )),
417+ (Recipe <?>) recipe .build ()));
418+ }
419+
372420 public TestContext (final RecipeHolder <?> recipe ) {
373- this (recipe , "" , false , List .of (), List .of (), List .of ());
421+ this (recipe , "" , false , false , List .of (), List .of (), List .of ());
374422 }
375423
376424 public TestContext name (final String testName ) {
377425 final String newTestName = this .testName .isEmpty () ? testName : (this .testName + ", " + testName );
378- return new TestContext (this .recipe , newTestName , this .shiftClick , this .inventory , this .input , this .expectedInputs );
426+ return new TestContext (this .recipe , newTestName , this .shiftClick , this .creativeMode , this . inventory , this .input , this .expectedInputs );
379427 }
380428
381429 public TestContext shift () {
382- return new TestContext (this .recipe , this .testName , true , this .inventory , this .input , this .expectedInputs );
430+ return new TestContext (this .recipe , this .testName , true , this .creativeMode , this .inventory , this .input , this .expectedInputs );
431+ }
432+
433+ public TestContext creative () {
434+ return new TestContext (this .recipe , this .testName , this .shiftClick , true , this .inventory , this .input , this .expectedInputs );
383435 }
384436
385437 public TestContext inventory (final List <ItemStack > items ) {
386- return new TestContext (this .recipe , this .testName , this .shiftClick , items , this .input , this .expectedInputs );
438+ return new TestContext (this .recipe , this .testName , this .shiftClick , this . creativeMode , items , this .input , this .expectedInputs );
387439 }
388440
389441 public TestContext input (final List <ItemStack > items ) {
390- return new TestContext (this .recipe , this .testName , this .shiftClick , this .inventory , items , this .expectedInputs );
442+ return new TestContext (this .recipe , this .testName , this .shiftClick , this .creativeMode , this . inventory , items , this .expectedInputs );
391443 }
392444
393445 public TestContext expectInputs (final List <List <ItemStack >> expectedInputs ) {
394- return new TestContext (this .recipe , this .testName , this .shiftClick , this .inventory , this .input , expectedInputs );
446+ return new TestContext (this .recipe , this .testName , this .shiftClick , this .creativeMode , this . inventory , this .input , expectedInputs );
395447 }
396448
397449 public TestContext expectInput (final List <ItemStack > expectedInput ) {
398450 return this .expectInputs (Stream .concat (this .expectedInputs .stream (), Stream .of (expectedInput )).toList ());
399451 }
400452
401453 public String asTestName () {
402- return String .format ("Place recipe %s (Shift click: %s, Total clicks : %s, %s)" ,
454+ return String .format ("Place recipe %s, %s (Shift click: %s, Creative mode : %s, Total clicks: %s)" ,
403455 this .recipe .id ().location ().getPath (),
456+ this .testName ,
404457 this .shiftClick ,
405- this .expectedInputs . size () ,
406- this .testName );
458+ this .creativeMode ,
459+ this .expectedInputs . size () );
407460 }
408461
409462 // Tests
@@ -443,7 +496,7 @@ public void test(
443496 }
444497
445498 for (int i = 0 ; i < this .expectedInputs ().size (); ++i ) {
446- menu .handlePlacement (this .shiftClick (), true , this .recipe (), player .serverLevel (), player .getInventory ());
499+ menu .handlePlacement (this .shiftClick (), this . creativeMode () , this .recipe (), player .serverLevel (), player .getInventory ());
447500
448501 final List <ItemStack > actualInput = input .slots ().stream ().map (Slot ::peek ).toList ();
449502 final List <ItemStack > expectedInput = this .expectedInputs ().get (i );
0 commit comments