1+ package net .darkhax .bookshelf .impl .gametest ;
2+
3+ import com .google .common .base .CaseFormat ;
4+ import net .darkhax .bookshelf .Constants ;
5+ import net .darkhax .bookshelf .api .serialization .Serializers ;
6+ import net .darkhax .bookshelf .api .util .ItemStackHelper ;
7+ import net .minecraft .ChatFormatting ;
8+ import net .minecraft .core .BlockPos ;
9+ import net .minecraft .core .particles .ParticleTypes ;
10+ import net .minecraft .gametest .framework .GameTest ;
11+ import net .minecraft .gametest .framework .GameTestGenerator ;
12+ import net .minecraft .gametest .framework .StructureUtils ;
13+ import net .minecraft .gametest .framework .TestFunction ;
14+ import net .minecraft .nbt .CompoundTag ;
15+ import net .minecraft .network .chat .TextComponent ;
16+ import net .minecraft .network .chat .TranslatableComponent ;
17+ import net .minecraft .resources .ResourceLocation ;
18+ import net .minecraft .sounds .SoundEvents ;
19+ import net .minecraft .tags .ItemTags ;
20+ import net .minecraft .world .effect .MobEffectInstance ;
21+ import net .minecraft .world .effect .MobEffects ;
22+ import net .minecraft .world .entity .EntityType ;
23+ import net .minecraft .world .entity .ai .attributes .AttributeModifier ;
24+ import net .minecraft .world .entity .ai .attributes .Attributes ;
25+ import net .minecraft .world .entity .decoration .Motive ;
26+ import net .minecraft .world .entity .npc .VillagerProfession ;
27+ import net .minecraft .world .entity .npc .VillagerType ;
28+ import net .minecraft .world .inventory .MenuType ;
29+ import net .minecraft .world .item .CreativeModeTab ;
30+ import net .minecraft .world .item .ItemStack ;
31+ import net .minecraft .world .item .Items ;
32+ import net .minecraft .world .item .Rarity ;
33+ import net .minecraft .world .item .alchemy .Potions ;
34+ import net .minecraft .world .item .crafting .Ingredient ;
35+ import net .minecraft .world .item .enchantment .Enchantment ;
36+ import net .minecraft .world .item .enchantment .Enchantments ;
37+ import net .minecraft .world .level .block .Blocks ;
38+ import net .minecraft .world .level .block .PressurePlateBlock ;
39+ import net .minecraft .world .level .block .Rotation ;
40+ import net .minecraft .world .level .block .entity .BlockEntityType ;
41+ import net .minecraft .world .level .gameevent .GameEvent ;
42+
43+ import java .lang .reflect .InvocationTargetException ;
44+ import java .lang .reflect .Method ;
45+ import java .util .ArrayList ;
46+ import java .util .Arrays ;
47+ import java .util .Collection ;
48+ import java .util .Objects ;
49+ import java .util .UUID ;
50+
51+ public class BookshelfGameTests {
52+
53+ @ GameTestGenerator
54+ public static Collection <TestFunction > generate () {
55+
56+ final Collection <TestFunction > testFunctions = new ArrayList <>();
57+
58+ // Test Java Type Serializers
59+ testFrom (testFunctions , new TestSerialization <>("boolean" , Serializers .BOOLEAN , false , true , true , false ));
60+ testFrom (testFunctions , new TestSerialization <>("byte" , Serializers .BYTE , (byte ) 1 , (byte ) 32 , (byte ) 44 , (byte ) 0 ));
61+ testFrom (testFunctions , new TestSerialization <>("short" , Serializers .SHORT , (short ) 800 , (short ) 1337 ));
62+ testFrom (testFunctions , new TestSerialization <>("int" , Serializers .INT , 54 , 23 , Integer .MAX_VALUE , 234234 , Integer .MIN_VALUE ));
63+ testFrom (testFunctions , new TestSerialization <>("long" , Serializers .LONG , 99L , 23441322L , Long .MIN_VALUE , 93249L -234L , Long .MAX_VALUE ));
64+ testFrom (testFunctions , new TestSerialization <>("float" , Serializers .FLOAT , 8f , -23.456f , 789.01f , Float .MAX_VALUE , -11f , Float .MIN_VALUE ));
65+ testFrom (testFunctions , new TestSerialization <>("double" , Serializers .DOUBLE , 24.92d , Double .MAX_VALUE , -922321.12345d , Double .MIN_VALUE ));
66+ testFrom (testFunctions , new TestSerialization <>("string" , Serializers .STRING , "one" , "two" , "3" , "IV" , "....." , "/I" , "!@#$%^&*()_-" ));
67+ testFrom (testFunctions , new TestSerialization <>("uuid" , Serializers .UUID , UUID .randomUUID (), UUID .fromString ("da0317d2-e550-11ec-8fea-0242ac120002" ), UUID .randomUUID ()));
68+
69+ // Test Minecraft Type Serializers
70+ testFrom (testFunctions , new TestSerialization <>("resource_location" , Serializers .RESOURCE_LOCATION , new ResourceLocation ("hello_world" ), new ResourceLocation ("test" , "two" ), new ResourceLocation ("test_from" , "stuff/things/okay_stuff" )));
71+ testFrom (testFunctions , new TestSerialization <>("item_stack" , Serializers .ITEM_STACK , ItemStackHelper ::areStacksEquivalent , ItemStackHelper .getTabItems (CreativeModeTab .TAB_COMBAT )));
72+ testFrom (testFunctions , new TestSerialization <>("nbt_compound_tag" , Serializers .COMPOUND_TAG , Arrays .stream (ItemStackHelper .getTabItems (CreativeModeTab .TAB_COMBAT )).filter (ItemStack ::hasTag ).map (ItemStack ::getTag ).toArray (CompoundTag []::new )));
73+ testFrom (testFunctions , new TestSerialization <>("text_component" , Serializers .TEXT , new TranslatableComponent ("moon.phase.full" ).withStyle (ChatFormatting .DARK_AQUA ), new TextComponent ("Hello World" ), new TextComponent ("okay" ).withStyle (s -> s .withFont (new ResourceLocation ("minecraft:alt" )))));
74+ testFrom (testFunctions , new TestSerialization <>("block_pos" , Serializers .BLOCK_POS , new BlockPos (1 , 2 , 3 ), new BlockPos (0 , 0 , 0 ), BlockPos .of (123456L )));
75+ testFrom (testFunctions , new TestSerialization <>("ingredient" , Serializers .INGREDIENT , BookshelfGameTests ::assertEqual , new Ingredient [] {Ingredient .of (Items .STONE_AXE ), Ingredient .EMPTY , Ingredient .of (Items .COAL ), Ingredient .of (new ItemStack (Items .ACACIA_BOAT )), Ingredient .of (ItemTags .BEDS ) }));
76+ testFrom (testFunctions , new TestSerialization <>("block_state" , Serializers .BLOCK_STATE , Blocks .STONE .defaultBlockState (), Blocks .CHEST .defaultBlockState (), Blocks .ACACIA_PRESSURE_PLATE .defaultBlockState ().setValue (PressurePlateBlock .POWERED , true )));
77+ testFrom (testFunctions , new TestSerialization <>("attribute_modifier" , Serializers .ATTRIBUTE_MODIFIER , new AttributeModifier ("test" , 15d , AttributeModifier .Operation .MULTIPLY_BASE ), new AttributeModifier (UUID .randomUUID (), "test_2" , 9.55d , AttributeModifier .Operation .ADDITION ), new AttributeModifier ("test3" , 35d , AttributeModifier .Operation .MULTIPLY_TOTAL )));
78+ testFrom (testFunctions , new TestSerialization <>("effect_instance" , Serializers .EFFECT_INSTANCE , new MobEffectInstance (MobEffects .ABSORPTION , 100 , 10 ), new MobEffectInstance (MobEffects .BAD_OMEN , 10 )));
79+
80+ // Test Minecraft Enum Serializers
81+ testFrom (testFunctions , new TestSerialization <>("item_rarity" , Serializers .ITEM_RARITY , Rarity .COMMON , Rarity .EPIC , Rarity .RARE , Rarity .RARE ));
82+ testFrom (testFunctions , new TestSerialization <>("enchantment_rarity" , Serializers .ENCHANTMENT_RARITY , Enchantment .Rarity .COMMON , Enchantment .Rarity .COMMON , Enchantment .Rarity .RARE , Enchantment .Rarity .UNCOMMON ));
83+ testFrom (testFunctions , new TestSerialization <>("attribute_modifier" , Serializers .ATTRIBUTE_OPERATION , AttributeModifier .Operation .ADDITION , AttributeModifier .Operation .ADDITION , AttributeModifier .Operation .MULTIPLY_BASE , AttributeModifier .Operation .MULTIPLY_TOTAL , AttributeModifier .Operation .MULTIPLY_TOTAL ));
84+
85+ // Test Game Registry Serializers
86+ testFrom (testFunctions , new TestSerialization <>("registry_block" , Serializers .BLOCK , Blocks .SAND , Blocks .STONE , Blocks .KELP , Blocks .SAND ));
87+ testFrom (testFunctions , new TestSerialization <>("registry_item" , Serializers .ITEM , Items .APPLE , Items .STICK , Items .STICK , Items .COOKED_PORKCHOP ));
88+ testFrom (testFunctions , new TestSerialization <>("registry_enchantment" , Serializers .ENCHANTMENT , Enchantments .ALL_DAMAGE_PROTECTION , Enchantments .BLAST_PROTECTION , Enchantments .BLAST_PROTECTION , Enchantments .SILK_TOUCH ));
89+ testFrom (testFunctions , new TestSerialization <>("registry_motive" , Serializers .MOTIVE , Motive .SEA , Motive .SEA , Motive .AZTEC2 , Motive .DONKEY_KONG ));
90+ testFrom (testFunctions , new TestSerialization <>("registry_potion" , Serializers .POTION , Potions .EMPTY , Potions .AWKWARD , Potions .AWKWARD , Potions .FIRE_RESISTANCE , Potions .HEALING ));
91+ testFrom (testFunctions , new TestSerialization <>("registry_attribute" , Serializers .ATTRIBUTE , Attributes .ARMOR , Attributes .ATTACK_SPEED , Attributes .MAX_HEALTH , Attributes .SPAWN_REINFORCEMENTS_CHANCE ));
92+ testFrom (testFunctions , new TestSerialization <>("registry_villager_profession" , Serializers .VILLAGER_PROFESSION , VillagerProfession .ARMORER , VillagerProfession .ARMORER , VillagerProfession .BUTCHER , VillagerProfession .LEATHERWORKER , VillagerProfession .WEAPONSMITH ));
93+ testFrom (testFunctions , new TestSerialization <>("registry_villager_type" , Serializers .VILLAGER_TYPE , VillagerType .SWAMP , VillagerType .JUNGLE , VillagerType .JUNGLE , VillagerType .PLAINS ));
94+ testFrom (testFunctions , new TestSerialization <>("registry_sound_event" , Serializers .SOUND_EVENT , SoundEvents .ANVIL_STEP , SoundEvents .BAMBOO_STEP , SoundEvents .AXE_STRIP , SoundEvents .DOLPHIN_JUMP ));
95+ testFrom (testFunctions , new TestSerialization <>("registry_menu" , Serializers .MENU , MenuType .ANVIL , MenuType .GENERIC_9x2 , MenuType .ENCHANTMENT , MenuType .CARTOGRAPHY_TABLE ));
96+ testFrom (testFunctions , new TestSerialization <>("registry_particle_type" , Serializers .PARTICLE , ParticleTypes .BUBBLE_POP , ParticleTypes .BUBBLE_COLUMN_UP , ParticleTypes .CLOUD , ParticleTypes .CAMPFIRE_SIGNAL_SMOKE , ParticleTypes .DRIPPING_OBSIDIAN_TEAR ));
97+ testFrom (testFunctions , new TestSerialization <>("registry_entity_type" , Serializers .ENTITY , EntityType .BAT , EntityType .ARROW , EntityType .AXOLOTL , EntityType .DRAGON_FIREBALL ));
98+ testFrom (testFunctions , new TestSerialization <>("registry_block_entity_type" , Serializers .BLOCK_ENTITY , BlockEntityType .BARREL , BlockEntityType .BEACON , BlockEntityType .BEEHIVE , BlockEntityType .JUKEBOX ));
99+ testFrom (testFunctions , new TestSerialization <>("registry_game_event" , Serializers .GAME_EVENT , GameEvent .FLAP , GameEvent .FLUID_PICKUP , GameEvent .PRIME_FUSE , GameEvent .LIGHTNING_STRIKE ));
100+ return testFunctions ;
101+ }
102+
103+ public static <T > void testFrom (Collection <TestFunction > functions , T testImpl ) {
104+
105+ final String parentBatch = testImpl instanceof ITestable testObj ? testObj .getDefaultBatch () : null ;
106+
107+ for (Method method : testImpl .getClass ().getDeclaredMethods ()) {
108+
109+ if (method .isAnnotationPresent (GameTest .class )) {
110+
111+ final GameTest annotation = method .getAnnotation (GameTest .class );
112+
113+ final String template = annotation .template ().isEmpty () ? "bookshelf:empty" : annotation .template ();
114+ final String batch = parentBatch != null && annotation .batch ().equalsIgnoreCase ("defaultBatch" ) ? parentBatch : annotation .batch ();
115+ final String testName = batch + "." + CaseFormat .LOWER_CAMEL .to (CaseFormat .LOWER_UNDERSCORE , method .getName ());
116+ final Rotation rotation = StructureUtils .getRotationForRotationSteps (annotation .rotationSteps ());
117+
118+ functions .add (new TestFunction (batch , testName , template , rotation , annotation .timeoutTicks (), annotation .setupTicks (), annotation .required (), annotation .requiredSuccesses (), annotation .attempts (), gameTestHelper -> {
119+
120+ try {
121+
122+ method .invoke (testImpl , gameTestHelper );
123+ }
124+
125+ catch (IllegalAccessException e ) {
126+
127+ throw new RuntimeException ("Failed to invoke test method (%s) in (%s) because %s" .formatted (method .getName (), method .getDeclaringClass ().getCanonicalName (), e .getMessage ()), e );
128+ }
129+
130+ catch (InvocationTargetException e ) {
131+
132+ final RuntimeException rte = (e .getCause () instanceof RuntimeException runtimeException ) ? runtimeException : new RuntimeException (e .getCause ());
133+ Constants .LOG .error ("The test {} failed to run!" , testName , e );
134+ throw rte ;
135+ }
136+ }));
137+ }
138+ }
139+ }
140+
141+ private static boolean assertEqual (Ingredient original , Ingredient result ) {
142+
143+ if (Objects .equals (original , result )) {
144+
145+ return true ;
146+ }
147+
148+ final ItemStack [] originalStacks = original .getItems ();
149+ final ItemStack [] resultStacks = result .getItems ();
150+
151+ if (originalStacks .length != resultStacks .length ) {
152+
153+ Constants .LOG .error ("Size mismatch. original={} result={}" , originalStacks .length , resultStacks .length );
154+ return false ;
155+ }
156+
157+ for (int index = 0 ; index < originalStacks .length ; index ++) {
158+
159+ if (!ItemStackHelper .areStacksEquivalent (originalStacks [index ], resultStacks [index ])) {
160+
161+ Constants .LOG .error ("Mismatch at index {}. original={} result={}" , index , originalStacks [index ], resultStacks [index ]);
162+
163+ return false ;
164+ }
165+ }
166+
167+ return true ;
168+
169+ }
170+ }
0 commit comments