Skip to content

Commit 0e89f73

Browse files
committed
Add gametests for data serializers.
1 parent 282ac49 commit 0e89f73

File tree

4 files changed

+604
-0
lines changed

4 files changed

+604
-0
lines changed
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
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+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package net.darkhax.bookshelf.impl.gametest;
2+
3+
import javax.annotation.Nullable;
4+
5+
public interface ITestable {
6+
7+
/**
8+
* Gets a default batch name that will supersede the annotation default when not null.
9+
*
10+
* @return The default batch name for all tests in the implementation.
11+
*/
12+
@Nullable
13+
default String getDefaultBatch() {
14+
15+
return null;
16+
}
17+
}

0 commit comments

Comments
 (0)