mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-11-09 18:03:08 +00:00
Split CC:T into common and forge projects
After several weeks of carefully arranging ribbons, we pull the string and end up with, ... a bit of a messy bow. There were still some things I'd missed. - Split the mod into a common (vanilla-only) project and Forge-specific project. This gives us room to add Fabric support later on. - Split the project into main/client source sets. This is not currently statically checked: we'll do that soon. - Rename block/item/tile entities to use suffixes rather than prefixes.
This commit is contained in:
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import dan200.computercraft.api.filesystem.IMount;
|
||||
import dan200.computercraft.api.network.wired.IWiredElement;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.peripheral.IPeripheralProvider;
|
||||
import dan200.computercraft.impl.AbstractComputerCraftAPI;
|
||||
import dan200.computercraft.impl.ComputerCraftAPIService;
|
||||
import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
||||
import dan200.computercraft.shared.network.container.ContainerData;
|
||||
import dan200.computercraft.shared.platform.*;
|
||||
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.CraftingContainer;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.Recipe;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.IItemHandlerModifiable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
@AutoService({ PlatformHelper.class, dan200.computercraft.impl.PlatformHelper.class, ComputerCraftAPIService.class })
|
||||
public class TestPlatformHelper extends AbstractComputerCraftAPI implements PlatformHelper {
|
||||
@Override
|
||||
public <T> Registries.RegistryWrapper<T> wrap(ResourceKey<Registry<T>> registry) {
|
||||
throw new UnsupportedOperationException("Cannot query registry inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> RegistrationHelper<T> createRegistrationHelper(ResourceKey<Registry<T>> registry) {
|
||||
throw new UnsupportedOperationException("Cannot query registry inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K> ResourceLocation getRegistryKey(ResourceKey<Registry<K>> registry, K object) {
|
||||
throw new UnsupportedOperationException("Cannot query registry inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K> K getRegistryObject(ResourceKey<Registry<K>> registry, ResourceLocation id) {
|
||||
throw new UnsupportedOperationException("Cannot query registry inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockEntity> BlockEntityType<T> createBlockEntityType(BiFunction<BlockPos, BlockState, T> factory, Block block) {
|
||||
throw new UnsupportedOperationException("Cannot create BlockEntityType inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A extends ArgumentType<?>, T extends ArgumentTypeInfo.Template<A>, I extends ArgumentTypeInfo<A, T>> I registerArgumentTypeInfo(Class<A> klass, I info) {
|
||||
throw new UnsupportedOperationException("Cannot register ArgumentTypeInfo inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToPlayer(NetworkMessage<ClientNetworkContext> message, ServerPlayer player) {
|
||||
throw new UnsupportedOperationException("Cannot send NetworkMessages inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToPlayers(NetworkMessage<ClientNetworkContext> message, Collection<ServerPlayer> players) {
|
||||
throw new UnsupportedOperationException("Cannot send NetworkMessages inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToAllPlayers(NetworkMessage<ClientNetworkContext> message, MinecraftServer server) {
|
||||
throw new UnsupportedOperationException("Cannot send NetworkMessages inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToAllAround(NetworkMessage<ClientNetworkContext> message, ServerLevel level, Vec3 pos, float distance) {
|
||||
throw new UnsupportedOperationException("Cannot send NetworkMessages inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToAllTracking(NetworkMessage<ClientNetworkContext> message, LevelChunk chunk) {
|
||||
throw new UnsupportedOperationException("Cannot send NetworkMessages inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreativeModeTab getCreativeTab() {
|
||||
throw new UnsupportedOperationException("Cannot get creative tab inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TagKey<Item>> getDyeTags() {
|
||||
throw new UnsupportedOperationException("Cannot query tags inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C extends AbstractContainerMenu, T extends ContainerData> MenuType<C> createMenuType(Function<FriendlyByteBuf, T> reader, ContainerData.Factory<C, T> factory) {
|
||||
throw new UnsupportedOperationException("Cannot create MenuType inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openMenu(Player player, MenuProvider owner, ContainerData menu) {
|
||||
throw new UnsupportedOperationException("Cannot open menu inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentAccess<IPeripheral> createPeripheralAccess(Consumer<Direction> invalidate) {
|
||||
throw new UnsupportedOperationException("Cannot interact with the world inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentAccess<IWiredElement> createWiredElementAccess(Consumer<Direction> invalidate) {
|
||||
throw new UnsupportedOperationException("Cannot interact with the world inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasWiredElementIn(Level level, BlockPos pos, Direction direction) {
|
||||
throw new UnsupportedOperationException("Cannot interact with the world inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNotifyNeighbour(Level level, BlockPos pos, BlockState block, Direction direction) {
|
||||
throw new UnsupportedOperationException("Cannot interact with the world inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<CreativeModeTab> getCreativeTabs(ItemStack stack) {
|
||||
throw new UnsupportedOperationException("Cannot get creative tabs inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeIngredients getRecipeIngredients() {
|
||||
throw new UnsupportedOperationException("Cannot query recipes inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBurnTime(ItemStack stack) {
|
||||
throw new UnsupportedOperationException("Cannot get burn time inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getCraftingRemainingItem(ItemStack stack) {
|
||||
return new ItemStack(stack.getItem().getCraftingRemainingItem());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerPlayer createFakePlayer(ServerLevel world, GameProfile name) {
|
||||
throw new UnsupportedOperationException("Cannot interact with the world inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasToolUsage(ItemStack stack) {
|
||||
throw new UnsupportedOperationException("Cannot query item properties inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult canAttackEntity(ServerPlayer player, Entity entity) {
|
||||
throw new UnsupportedOperationException("Cannot get burn time inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interactWithEntity(ServerPlayer player, Entity entity, Vec3 hitPos) {
|
||||
throw new UnsupportedOperationException("Cannot interact with the world inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOn(ServerPlayer player, ItemStack stack, BlockHitResult hit) {
|
||||
throw new UnsupportedOperationException("Cannot interact with the world inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContainerTransfer.Slotted wrapContainer(Container container) {
|
||||
throw new UnsupportedOperationException("Cannot wrap container");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ContainerTransfer getContainer(ServerLevel level, BlockPos pos, Direction side) {
|
||||
throw new UnsupportedOperationException("Cannot interact with the world inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemStack> getRecipeRemainingItems(ServerPlayer player, Recipe<CraftingContainer> recipe, CraftingContainer container) {
|
||||
throw new UnsupportedOperationException("Cannot query recipes inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemCrafted(ServerPlayer player, CraftingContainer container, ItemStack stack) {
|
||||
throw new UnsupportedOperationException("Cannot interact with the world inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInstalledVersion() {
|
||||
return "1.0";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IMount createResourceMount(String domain, String subPath) {
|
||||
throw new UnsupportedOperationException("Cannot create resource mount");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerPeripheralProvider(IPeripheralProvider provider) {
|
||||
throw new UnsupportedOperationException("Cannot register peripheral provider");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerGenericCapability(Capability<?> capability) {
|
||||
throw new UnsupportedOperationException("Cannot register generic capability");
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyOptional<IWiredElement> getWiredElementAt(BlockGetter world, BlockPos pos, Direction side) {
|
||||
throw new UnsupportedOperationException("Cannot get wired element");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T tryGetRegistryObject(ResourceKey<Registry<T>> registry, ResourceLocation id) {
|
||||
throw new UnsupportedOperationException("Cannot query registries");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemHandlerModifiable wrapContainerToItemHandler(Container container) {
|
||||
throw new UnsupportedOperationException("Cannot wrap item handler ");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.client.sound;
|
||||
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class DfpwmStreamTest {
|
||||
@Test
|
||||
public void testDecodesBytes() {
|
||||
var stream = new DfpwmStream();
|
||||
|
||||
var input = ByteBufAllocator.DEFAULT.buffer();
|
||||
input.writeBytes(new byte[]{ 43, -31, 33, 44, 30, -16, -85, 23, -3, -55, 46, -70, 68, -67, 74, -96, -68, 16, 94, -87, -5, 87, 11, -16, 19, 92, 85, -71, 126, 5, -84, 64, 17, -6, 85, -11, -1, -87, -12, 1, 85, -56, 33, -80, 82, 104, -93, 17, 126, 23, 91, -30, 37, -32, 117, -72, -58, 11, -76, 19, -108, 86, -65, -10, -1, -68, -25, 10, -46, 85, 124, -54, 15, -24, 43, -94, 117, 63, -36, 15, -6, 88, 87, -26, -83, 106, 41, 13, -28, -113, -10, -66, 119, -87, -113, 68, -55, 40, -107, 62, 20, 72, 3, -96, 114, -87, -2, 39, -104, 30, 20, 42, 84, 24, 47, 64, 43, 61, -35, 95, -65, 42, 61, 42, -50, 4, -9, 81 });
|
||||
stream.push(input);
|
||||
|
||||
var buffer = stream.read(1024 + 1);
|
||||
assertEquals(1024, buffer.remaining(), "Must have read 1024 bytes");
|
||||
|
||||
var decoded = new byte[]{ 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 0, -1, -2, -2, -1, 0, 1, 0, -1, -3, -5, -5, -5, -7, -9, -11, -11, -9, -9, -9, -9, -10, -12, -12, -10, -8, -6, -6, -8, -10, -12, -14, -16, -18, -17, -15, -12, -9, -6, -3, -2, -2, -2, -2, -2, -2, 0, 3, 6, 7, 7, 7, 4, 1, 1, 1, 1, 3, 5, 7, 9, 12, 15, 15, 12, 12, 12, 9, 9, 11, 12, 12, 14, 16, 17, 17, 17, 14, 11, 11, 11, 10, 12, 14, 14, 13, 13, 10, 9, 9, 7, 5, 4, 4, 4, 4, 4, 6, 8, 10, 10, 10, 10, 10, 10, 10, 9, 8, 8, 8, 7, 6, 4, 2, 0, 0, 0, 0, 0, -1, -1, 0, 1, 3, 3, 3, 3, 2, 0, -2, -2, -2, -3, -5, -7, -7, -5, -3, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -1, -1, 0, 1, 1, 1, 2, 3, 4, 5, 6, 7, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 9, 8, 7, 6, 4, 2, 0, 0, 2, 4, 6, 8, 10, 10, 8, 7, 7, 5, 3, 1, -1, 0, 2, 4, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 4, 5, 5, 5, 5, 5, 6, 7, 8, 9, 10, 9, 9, 9, 9, 9, 8, 7, 6, 5, 3, 1, 1, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -3, -3, -3, -3, -2, -3, -4, -4, -3, -4, -5, -6, -6, -5, -5, -4, -3, -2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 18, 20, 20, 17, 16, 16, 15, 15, 15, 15, 13, 13, 13, 13, 14, 15, 16, 18, 18, 16, 14, 12, 10, 8, 5, 5, 5, 4, 4, 4, 4, 4, 4, 2, 0, -2, -2, -2, -4, -4, -2, 0, 0, -2, -4, -6, -6, -6, -8, -10, -12, -14, -16, -15, -13, -12, -11, -11, -11, -11, -13, -13, -13, -13, -13, -14, -16, -18, -18, -18, -18, -16, -16, -16, -14, -13, -14, -15, -15, -14, -14, -12, -11, -12, -13, -13, -12, -13, -14, -15, -15, -13, -11, -9, -7, -5, -5, -5, -3, -1, -1, -1, -1, -3, -5, -5, -3, -3, -3, -1, -1, -1, -1, -3, -3, -3, -4, -6, -6, -4, -2, 0, 0, 0, 0, -2, -2, -2, -3, -5, -7, -9, -11, -13, -13, -11, -9, -7, -6, -6, -6, -6, -4, -2, -2, -4, -6, -8, -7, -5, -3, -2, -2, -2, -2, 0, 0, -2, -4, -4, -2, 0, 2, 2, 1, 1, -1, -3, -5, -7, -10, -10, -10, -10, -8, -7, -7, -5, -3, -2, -4, -4, -4, -6, -8, -10, -12, -12, -12, -12, -12, -14, -13, -13, -13, -11, -11, -11, -11, -11, -11, -11, -9, -7, -5, -3, -1, -1, -1, -1, -1, 1, 1, 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 22, 19, 18, 20, 22, 24, 23, 22, 24, 26, 28, 27, 24, 23, 25, 28, 28, 28, 27, 26, 26, 23, 20, 17, 14, 14, 14, 11, 11, 11, 11, 13, 15, 16, 16, 16, 15, 15, 14, 14, 12, 10, 9, 11, 13, 15, 17, 17, 14, 13, 13, 12, 12, 10, 9, 11, 13, 15, 17, 19, 19, 16, 13, 10, 7, 4, 1, 1, 2, 2, 4, 7, 10, 13, 13, 13, 12, 12, 12, 9, 6, 6, 6, 3, 0, 0, 0, 0, 2, 3, 3, 3, 3, 5, 7, 7, 7, 9, 11, 13, 15, 18, 18, 15, 12, 9, 8, 10, 13, 13, 13, 15, 18, 21, 24, 27, 27, 23, 19, 15, 11, 10, 9, 9, 12, 16, 19, 22, 23, 19, 14, 13, 16, 16, 15, 15, 14, 17, 20, 20, 19, 19, 18, 17, 14, 13, 15, 15, 12, 11, 13, 16, 19, 19, 18, 20, 20, 19, 18, 18, 17, 17, 16, 16, 16, 15, 17, 17, 16, 16, 13, 12, 12, 11, 11, 9, 9, 9, 9, 11, 11, 9, 7, 5, 3, 1, 1, 1, -1, -1, 1, 3, 5, 7, 9, 11, 12, 9, 6, 6, 6, 6, 8, 8, 7, 9, 11, 13, 13, 12, 14, 16, 18, 20, 20, 20, 22, 24, 26, 25, 25, 27, 29, 28, 27, 26, 23, 22, 22, 21, 21, 20, 22, 24, 26, 28, 27, 24, 21, 21, 21, 18, 17, 17, 14, 11, 11, 11, 10, 10, 7, 6, 6, 4, 3, 5, 5, 3, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 0, -1, -1, 0, 0, 1, 2, 3, 4, 3, 1, -1, -3, -3, -3, -3, -2, -3, -4, -6, -8, -10, -10, -10, -12, -12, -12, -12, -10, -10, -11, -12, -14, -16, -18, -20, -22, -24, -26, -28, -27, -27, -26, -26, -25, -25, -27, -26, -24, -22, -22, -22, -22, -24, -24, -24, -24, -23, -23, -22, -22, -21, -20, -19, -17, -15, -13, -11, -9, -7, -7, -9, -9, -9, -11, -13, -15, -17, -16, -14, -13, -15, -14, -14, -14, -12, -10, -8, -7, -9, -11, -13, -15, -14, -14, -13, -13, -15, -17, -19, -18, -18, -17, -17, -16, -16, -18, -20, -22, -21, -21, -21, -21, -21, -20, -21, -22, -24, -24, -22, -22, -24, -26, -25, -23, -21, -19, -18, -17, -17, -19, -21, -23, -25, -27, -29, -31, -30, -29, -28, -26, -25, -24, -24, -23, -23, -25, -24, -24, -24, -22, -20, -18, -18, -20, -20, -20, -20, -18, -16, -16, -16, -14, -12, -10, -8, -6, -4, -4, -4, -4, -4, -2, 0, 2, 4, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 4, 5, 6, 5, 3, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, -1, -2, -3, -4, -4, -2, 0, 0, 0, 1, 3, 5, 7, 7, 5, 3, 3, 3, 3, 3 };
|
||||
for (var i = 0; i < 1024; i++) {
|
||||
assertEquals((byte) (decoded[i] ^ 0x80), buffer.get(), "Bad element at " + i);
|
||||
}
|
||||
|
||||
assertEquals(0, buffer.remaining(), "Must have read all bytes");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.impl.network.wired;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.network.wired.IWiredElement;
|
||||
import dan200.computercraft.api.network.wired.IWiredNetwork;
|
||||
import dan200.computercraft.api.network.wired.IWiredNetworkChange;
|
||||
import dan200.computercraft.api.network.wired.IWiredNode;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.shared.util.DirectionUtil;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class NetworkTest {
|
||||
@Test
|
||||
public void testConnect() {
|
||||
NetworkElement
|
||||
aE = new NetworkElement(null, null, "a"),
|
||||
bE = new NetworkElement(null, null, "b"),
|
||||
cE = new NetworkElement(null, null, "c");
|
||||
|
||||
IWiredNode
|
||||
aN = aE.getNode(),
|
||||
bN = bE.getNode(),
|
||||
cN = cE.getNode();
|
||||
|
||||
assertNotEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must be different");
|
||||
assertNotEquals(aN.getNetwork(), cN.getNetwork(), "A's and C's network must be different");
|
||||
assertNotEquals(bN.getNetwork(), cN.getNetwork(), "B's and C's network must be different");
|
||||
|
||||
assertTrue(aN.getNetwork().connect(aN, bN), "Must be able to add connection");
|
||||
assertFalse(aN.getNetwork().connect(aN, bN), "Cannot add connection twice");
|
||||
|
||||
assertEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must be equal");
|
||||
assertEquals(Sets.newHashSet(aN, bN), nodes(aN.getNetwork()), "A's network should be A and B");
|
||||
|
||||
assertEquals(Sets.newHashSet("a", "b"), aE.allPeripherals().keySet(), "A's peripheral set should be A, B");
|
||||
assertEquals(Sets.newHashSet("a", "b"), bE.allPeripherals().keySet(), "B's peripheral set should be A, B");
|
||||
|
||||
aN.getNetwork().connect(aN, cN);
|
||||
|
||||
assertEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must be equal");
|
||||
assertEquals(aN.getNetwork(), cN.getNetwork(), "A's and C's network must be equal");
|
||||
assertEquals(Sets.newHashSet(aN, bN, cN), nodes(aN.getNetwork()), "A's network should be A, B and C");
|
||||
|
||||
assertEquals(Sets.newHashSet(bN, cN), neighbours(aN), "A's neighbour set should be B, C");
|
||||
assertEquals(Sets.newHashSet(aN), neighbours(bN), "B's neighbour set should be A");
|
||||
assertEquals(Sets.newHashSet(aN), neighbours(cN), "C's neighbour set should be A");
|
||||
|
||||
assertEquals(Sets.newHashSet("a", "b", "c"), aE.allPeripherals().keySet(), "A's peripheral set should be A, B, C");
|
||||
assertEquals(Sets.newHashSet("a", "b", "c"), bE.allPeripherals().keySet(), "B's peripheral set should be A, B, C");
|
||||
assertEquals(Sets.newHashSet("a", "b", "c"), cE.allPeripherals().keySet(), "C's peripheral set should be A, B, C");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisconnectNoChange() {
|
||||
NetworkElement
|
||||
aE = new NetworkElement(null, null, "a"),
|
||||
bE = new NetworkElement(null, null, "b"),
|
||||
cE = new NetworkElement(null, null, "c");
|
||||
|
||||
IWiredNode
|
||||
aN = aE.getNode(),
|
||||
bN = bE.getNode(),
|
||||
cN = cE.getNode();
|
||||
|
||||
aN.getNetwork().connect(aN, bN);
|
||||
aN.getNetwork().connect(aN, cN);
|
||||
aN.getNetwork().connect(bN, cN);
|
||||
|
||||
aN.getNetwork().disconnect(aN, bN);
|
||||
|
||||
assertEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must be equal");
|
||||
assertEquals(aN.getNetwork(), cN.getNetwork(), "A's and C's network must be equal");
|
||||
assertEquals(Sets.newHashSet(aN, bN, cN), nodes(aN.getNetwork()), "A's network should be A, B and C");
|
||||
|
||||
assertEquals(Sets.newHashSet("a", "b", "c"), aE.allPeripherals().keySet(), "A's peripheral set should be A, B, C");
|
||||
assertEquals(Sets.newHashSet("a", "b", "c"), bE.allPeripherals().keySet(), "B's peripheral set should be A, B, C");
|
||||
assertEquals(Sets.newHashSet("a", "b", "c"), cE.allPeripherals().keySet(), "C's peripheral set should be A, B, C");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisconnectLeaf() {
|
||||
NetworkElement
|
||||
aE = new NetworkElement(null, null, "a"),
|
||||
bE = new NetworkElement(null, null, "b"),
|
||||
cE = new NetworkElement(null, null, "c");
|
||||
|
||||
IWiredNode
|
||||
aN = aE.getNode(),
|
||||
bN = bE.getNode(),
|
||||
cN = cE.getNode();
|
||||
|
||||
aN.getNetwork().connect(aN, bN);
|
||||
aN.getNetwork().connect(aN, cN);
|
||||
|
||||
aN.getNetwork().disconnect(aN, bN);
|
||||
|
||||
assertNotEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must not be equal");
|
||||
assertEquals(aN.getNetwork(), cN.getNetwork(), "A's and C's network must be equal");
|
||||
assertEquals(Sets.newHashSet(aN, cN), nodes(aN.getNetwork()), "A's network should be A and C");
|
||||
assertEquals(Sets.newHashSet(bN), nodes(bN.getNetwork()), "B's network should be B");
|
||||
|
||||
assertEquals(Sets.newHashSet("a", "c"), aE.allPeripherals().keySet(), "A's peripheral set should be A, C");
|
||||
assertEquals(Sets.newHashSet("b"), bE.allPeripherals().keySet(), "B's peripheral set should be B");
|
||||
assertEquals(Sets.newHashSet("a", "c"), cE.allPeripherals().keySet(), "C's peripheral set should be A, C");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisconnectSplit() {
|
||||
NetworkElement
|
||||
aE = new NetworkElement(null, null, "a"),
|
||||
aaE = new NetworkElement(null, null, "a_"),
|
||||
bE = new NetworkElement(null, null, "b"),
|
||||
bbE = new NetworkElement(null, null, "b_");
|
||||
|
||||
IWiredNode
|
||||
aN = aE.getNode(),
|
||||
aaN = aaE.getNode(),
|
||||
bN = bE.getNode(),
|
||||
bbN = bbE.getNode();
|
||||
|
||||
aN.getNetwork().connect(aN, aaN);
|
||||
bN.getNetwork().connect(bN, bbN);
|
||||
|
||||
aN.getNetwork().connect(aN, bN);
|
||||
|
||||
aN.getNetwork().disconnect(aN, bN);
|
||||
|
||||
assertNotEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must not be equal");
|
||||
assertEquals(aN.getNetwork(), aaN.getNetwork(), "A's and A_'s network must be equal");
|
||||
assertEquals(bN.getNetwork(), bbN.getNetwork(), "B's and B_'s network must be equal");
|
||||
|
||||
assertEquals(Sets.newHashSet(aN, aaN), nodes(aN.getNetwork()), "A's network should be A and A_");
|
||||
assertEquals(Sets.newHashSet(bN, bbN), nodes(bN.getNetwork()), "B's network should be B and B_");
|
||||
|
||||
assertEquals(Sets.newHashSet("a", "a_"), aE.allPeripherals().keySet(), "A's peripheral set should be A and A_");
|
||||
assertEquals(Sets.newHashSet("b", "b_"), bE.allPeripherals().keySet(), "B's peripheral set should be B and B_");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveSingle() {
|
||||
var aE = new NetworkElement(null, null, "a");
|
||||
var aN = aE.getNode();
|
||||
|
||||
var network = aN.getNetwork();
|
||||
assertFalse(aN.remove(), "Cannot remove node from an empty network");
|
||||
assertEquals(network, aN.getNetwork(), "Networks are same before and after");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveLeaf() {
|
||||
NetworkElement
|
||||
aE = new NetworkElement(null, null, "a"),
|
||||
bE = new NetworkElement(null, null, "b"),
|
||||
cE = new NetworkElement(null, null, "c");
|
||||
|
||||
IWiredNode
|
||||
aN = aE.getNode(),
|
||||
bN = bE.getNode(),
|
||||
cN = cE.getNode();
|
||||
|
||||
aN.getNetwork().connect(aN, bN);
|
||||
aN.getNetwork().connect(aN, cN);
|
||||
|
||||
assertTrue(aN.getNetwork().remove(bN), "Must be able to remove node");
|
||||
assertFalse(aN.getNetwork().remove(bN), "Cannot remove a second time");
|
||||
|
||||
assertNotEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must not be equal");
|
||||
assertEquals(aN.getNetwork(), cN.getNetwork(), "A's and C's network must be equal");
|
||||
|
||||
assertEquals(Sets.newHashSet(aN, cN), nodes(aN.getNetwork()), "A's network should be A and C");
|
||||
assertEquals(Sets.newHashSet(bN), nodes(bN.getNetwork()), "B's network should be B");
|
||||
|
||||
assertEquals(Sets.newHashSet("a", "c"), aE.allPeripherals().keySet(), "A's peripheral set should be A, C");
|
||||
assertEquals(Sets.newHashSet(), bE.allPeripherals().keySet(), "B's peripheral set should be empty");
|
||||
assertEquals(Sets.newHashSet("a", "c"), cE.allPeripherals().keySet(), "C's peripheral set should be A, C");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveSplit() {
|
||||
NetworkElement
|
||||
aE = new NetworkElement(null, null, "a"),
|
||||
aaE = new NetworkElement(null, null, "a_"),
|
||||
bE = new NetworkElement(null, null, "b"),
|
||||
bbE = new NetworkElement(null, null, "b_"),
|
||||
cE = new NetworkElement(null, null, "c");
|
||||
|
||||
IWiredNode
|
||||
aN = aE.getNode(),
|
||||
aaN = aaE.getNode(),
|
||||
bN = bE.getNode(),
|
||||
bbN = bbE.getNode(),
|
||||
cN = cE.getNode();
|
||||
|
||||
aN.getNetwork().connect(aN, aaN);
|
||||
bN.getNetwork().connect(bN, bbN);
|
||||
|
||||
cN.getNetwork().connect(aN, cN);
|
||||
cN.getNetwork().connect(bN, cN);
|
||||
|
||||
cN.getNetwork().remove(cN);
|
||||
|
||||
assertNotEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must not be equal");
|
||||
assertEquals(aN.getNetwork(), aaN.getNetwork(), "A's and A_'s network must be equal");
|
||||
assertEquals(bN.getNetwork(), bbN.getNetwork(), "B's and B_'s network must be equal");
|
||||
|
||||
assertEquals(Sets.newHashSet(aN, aaN), nodes(aN.getNetwork()), "A's network should be A and A_");
|
||||
assertEquals(Sets.newHashSet(bN, bbN), nodes(bN.getNetwork()), "B's network should be B and B_");
|
||||
assertEquals(Sets.newHashSet(cN), nodes(cN.getNetwork()), "C's network should be C");
|
||||
|
||||
assertEquals(Sets.newHashSet("a", "a_"), aE.allPeripherals().keySet(), "A's peripheral set should be A and A_");
|
||||
assertEquals(Sets.newHashSet("b", "b_"), bE.allPeripherals().keySet(), "B's peripheral set should be B and B_");
|
||||
assertEquals(Sets.newHashSet(), cE.allPeripherals().keySet(), "C's peripheral set should be empty");
|
||||
}
|
||||
|
||||
private static final int BRUTE_SIZE = 16;
|
||||
private static final int TOGGLE_CONNECTION_TIMES = 5;
|
||||
private static final int TOGGLE_NODE_TIMES = 5;
|
||||
|
||||
@Test
|
||||
@Disabled("Takes a long time to run, mostly for stress testing")
|
||||
public void testLarge() {
|
||||
var grid = new Grid<IWiredNode>(BRUTE_SIZE);
|
||||
grid.map((existing, pos) -> new NetworkElement(null, null, "n_" + pos).getNode());
|
||||
|
||||
// Test connecting
|
||||
{
|
||||
var start = System.nanoTime();
|
||||
|
||||
grid.forEach((existing, pos) -> {
|
||||
for (var facing : DirectionUtil.FACINGS) {
|
||||
var offset = pos.relative(facing);
|
||||
if (offset.getX() > BRUTE_SIZE / 2 == pos.getX() > BRUTE_SIZE / 2) {
|
||||
var other = grid.get(offset);
|
||||
if (other != null) existing.getNetwork().connect(existing, other);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var end = System.nanoTime();
|
||||
|
||||
System.out.printf("Connecting %s³ nodes took %s seconds\n", BRUTE_SIZE, (end - start) * 1e-9);
|
||||
}
|
||||
|
||||
// Test toggling
|
||||
{
|
||||
var left = grid.get(new BlockPos(BRUTE_SIZE / 2, 0, 0));
|
||||
var right = grid.get(new BlockPos(BRUTE_SIZE / 2 + 1, 0, 0));
|
||||
assertNotEquals(left.getNetwork(), right.getNetwork());
|
||||
|
||||
var start = System.nanoTime();
|
||||
for (var i = 0; i < TOGGLE_CONNECTION_TIMES; i++) {
|
||||
left.getNetwork().connect(left, right);
|
||||
left.getNetwork().disconnect(left, right);
|
||||
}
|
||||
|
||||
var end = System.nanoTime();
|
||||
|
||||
System.out.printf("Toggling connection %s times took %s seconds\n", TOGGLE_CONNECTION_TIMES, (end - start) * 1e-9);
|
||||
}
|
||||
|
||||
{
|
||||
var left = grid.get(new BlockPos(BRUTE_SIZE / 2, 0, 0));
|
||||
var right = grid.get(new BlockPos(BRUTE_SIZE / 2 + 1, 0, 0));
|
||||
var centre = new NetworkElement(null, null, "c").getNode();
|
||||
assertNotEquals(left.getNetwork(), right.getNetwork());
|
||||
|
||||
var start = System.nanoTime();
|
||||
for (var i = 0; i < TOGGLE_NODE_TIMES; i++) {
|
||||
left.getNetwork().connect(left, centre);
|
||||
right.getNetwork().connect(right, centre);
|
||||
|
||||
left.getNetwork().remove(centre);
|
||||
}
|
||||
|
||||
var end = System.nanoTime();
|
||||
|
||||
System.out.printf("Toggling node %s times took %s seconds\n", TOGGLE_NODE_TIMES, (end - start) * 1e-9);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class NetworkElement implements IWiredElement {
|
||||
private final Level world;
|
||||
private final Vec3 position;
|
||||
private final String id;
|
||||
private final IWiredNode node;
|
||||
private final Map<String, IPeripheral> localPeripherals = Maps.newHashMap();
|
||||
private final Map<String, IPeripheral> remotePeripherals = Maps.newHashMap();
|
||||
|
||||
private NetworkElement(Level world, Vec3 position, String id) {
|
||||
this.world = world;
|
||||
this.position = position;
|
||||
this.id = id;
|
||||
this.node = ComputerCraftAPI.createWiredNodeForElement(this);
|
||||
this.addPeripheral(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Level getLevel() {
|
||||
return world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSenderID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NetworkElement{" + id + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public IWiredNode getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void networkChanged(IWiredNetworkChange change) {
|
||||
remotePeripherals.keySet().removeAll(change.peripheralsRemoved().keySet());
|
||||
remotePeripherals.putAll(change.peripheralsAdded());
|
||||
}
|
||||
|
||||
public NetworkElement addPeripheral(String name) {
|
||||
localPeripherals.put(name, new NetworkPeripheral());
|
||||
getNode().updatePeripherals(localPeripherals);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, IPeripheral> allPeripherals() {
|
||||
return remotePeripherals;
|
||||
}
|
||||
}
|
||||
|
||||
private static class NetworkPeripheral implements IPeripheral {
|
||||
@Override
|
||||
public String getType() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable IPeripheral other) {
|
||||
return this == other;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Grid<T> {
|
||||
private final int size;
|
||||
private final T[] box;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Grid(int size) {
|
||||
this.size = size;
|
||||
this.box = (T[]) new Object[size * size * size];
|
||||
}
|
||||
|
||||
public T get(BlockPos pos) {
|
||||
int x = pos.getX(), y = pos.getY(), z = pos.getZ();
|
||||
|
||||
return x >= 0 && x < size && y >= 0 && y < size && z >= 0 && z < size
|
||||
? box[x * size * size + y * size + z]
|
||||
: null;
|
||||
}
|
||||
|
||||
public void forEach(BiConsumer<T, BlockPos> transform) {
|
||||
for (var x = 0; x < size; x++) {
|
||||
for (var y = 0; y < size; y++) {
|
||||
for (var z = 0; z < size; z++) {
|
||||
transform.accept(box[x * size * size + y * size + z], new BlockPos(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void map(BiFunction<T, BlockPos, T> transform) {
|
||||
for (var x = 0; x < size; x++) {
|
||||
for (var y = 0; y < size; y++) {
|
||||
for (var z = 0; z < size; z++) {
|
||||
box[x * size * size + y * size + z] = transform.apply(box[x * size * size + y * size + z], new BlockPos(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<WiredNode> nodes(IWiredNetwork network) {
|
||||
return ((WiredNetwork) network).nodes;
|
||||
}
|
||||
|
||||
private static Set<WiredNode> neighbours(IWiredNode node) {
|
||||
return ((WiredNode) node).neighbours;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.computer.core;
|
||||
|
||||
import dan200.computercraft.api.filesystem.IMount;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.server.packs.FolderPackResources;
|
||||
import net.minecraft.server.packs.PackType;
|
||||
import net.minecraft.server.packs.resources.ReloadableResourceManager;
|
||||
import net.minecraft.util.Unit;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ResourceMountTest {
|
||||
private IMount mount;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
var manager = new ReloadableResourceManager(PackType.SERVER_DATA);
|
||||
var done = new CompletableFuture<Unit>();
|
||||
manager.createReload(Util.backgroundExecutor(), Util.backgroundExecutor(), done, List.of(
|
||||
new FolderPackResources(new File("../core/src/main/resources"))
|
||||
));
|
||||
|
||||
mount = ResourceMount.get("computercraft", "lua/rom", manager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testList() throws IOException {
|
||||
List<String> files = new ArrayList<>();
|
||||
mount.list("", files);
|
||||
files.sort(Comparator.naturalOrder());
|
||||
|
||||
assertEquals(
|
||||
Arrays.asList("apis", "autorun", "help", "modules", "motd.txt", "programs", "startup.lua"),
|
||||
files
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExists() throws IOException {
|
||||
assertTrue(mount.exists(""));
|
||||
assertTrue(mount.exists("startup.lua"));
|
||||
assertTrue(mount.exists("programs/fun/advanced/paint.lua"));
|
||||
|
||||
assertFalse(mount.exists("programs/fun/advance/paint.lua"));
|
||||
assertFalse(mount.exists("programs/fun/advanced/paint.lu"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsDir() throws IOException {
|
||||
assertTrue(mount.isDirectory(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsFile() throws IOException {
|
||||
assertFalse(mount.isDirectory("startup.lua"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSize() throws IOException {
|
||||
assertNotEquals(mount.getSize("startup.lua"), 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.computer.terminal;
|
||||
|
||||
import dan200.computercraft.api.lua.LuaValues;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.test.core.CallCounter;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static dan200.computercraft.test.core.terminal.TerminalMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class NetworkedTerminalTest {
|
||||
@Test
|
||||
void testPacketBufferRoundtrip() {
|
||||
var writeTerminal = new NetworkedTerminal(2, 1, true);
|
||||
|
||||
blit(writeTerminal, "hi", "11", "ee");
|
||||
writeTerminal.setCursorPos(2, 5);
|
||||
writeTerminal.setTextColour(3);
|
||||
writeTerminal.setBackgroundColour(5);
|
||||
|
||||
var packetBuffer = new FriendlyByteBuf(Unpooled.buffer());
|
||||
writeTerminal.write(packetBuffer);
|
||||
|
||||
var callCounter = new CallCounter();
|
||||
var readTerminal = new NetworkedTerminal(2, 1, true, callCounter);
|
||||
packetBuffer.writeBytes(packetBuffer);
|
||||
readTerminal.read(packetBuffer);
|
||||
|
||||
assertThat(readTerminal, allOf(
|
||||
textMatches(new String[]{ "hi", }),
|
||||
textColourMatches(new String[]{ "11", }),
|
||||
backgroundColourMatches(new String[]{ "ee", })
|
||||
));
|
||||
|
||||
assertEquals(2, readTerminal.getCursorX());
|
||||
assertEquals(5, readTerminal.getCursorY());
|
||||
assertEquals(3, readTerminal.getTextColour());
|
||||
assertEquals(5, readTerminal.getBackgroundColour());
|
||||
callCounter.assertCalledTimes(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNbtRoundtrip() {
|
||||
var writeTerminal = new NetworkedTerminal(10, 5, true);
|
||||
blit(writeTerminal, "hi", "11", "ee");
|
||||
writeTerminal.setCursorPos(2, 5);
|
||||
writeTerminal.setTextColour(3);
|
||||
writeTerminal.setBackgroundColour(5);
|
||||
|
||||
var nbt = new CompoundTag();
|
||||
writeTerminal.writeToNBT(nbt);
|
||||
|
||||
var callCounter = new CallCounter();
|
||||
var readTerminal = new NetworkedTerminal(2, 1, true, callCounter);
|
||||
|
||||
readTerminal.readFromNBT(nbt);
|
||||
|
||||
assertThat(readTerminal, allOf(
|
||||
textMatches(new String[]{ "hi", }),
|
||||
textColourMatches(new String[]{ "11", }),
|
||||
backgroundColourMatches(new String[]{ "ee", })
|
||||
));
|
||||
|
||||
assertEquals(2, readTerminal.getCursorX());
|
||||
assertEquals(5, readTerminal.getCursorY());
|
||||
assertEquals(3, readTerminal.getTextColour());
|
||||
assertEquals(5, readTerminal.getBackgroundColour());
|
||||
callCounter.assertCalledTimes(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReadWriteNBTEmpty() {
|
||||
var terminal = new NetworkedTerminal(0, 0, true);
|
||||
|
||||
var nbt = new CompoundTag();
|
||||
terminal.writeToNBT(nbt);
|
||||
|
||||
var callCounter = new CallCounter();
|
||||
terminal = new NetworkedTerminal(0, 1, true, callCounter);
|
||||
terminal.readFromNBT(nbt);
|
||||
|
||||
assertThat(terminal, allOf(
|
||||
textMatches(new String[]{ "", }),
|
||||
textColourMatches(new String[]{ "", }),
|
||||
backgroundColourMatches(new String[]{ "", })
|
||||
));
|
||||
|
||||
assertEquals(0, terminal.getCursorX());
|
||||
assertEquals(0, terminal.getCursorY());
|
||||
assertEquals(0, terminal.getTextColour());
|
||||
assertEquals(15, terminal.getBackgroundColour());
|
||||
callCounter.assertCalledTimes(1);
|
||||
}
|
||||
|
||||
private static void blit(Terminal terminal, String text, String fg, String bg) {
|
||||
terminal.blit(LuaValues.encode(text), LuaValues.encode(fg), LuaValues.encode(bg));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.computer.terminal;
|
||||
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import org.junit.jupiter.api.RepeatedTest;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Tests {@link TerminalState} round tripping works as expected.
|
||||
*/
|
||||
public class TerminalStateTest {
|
||||
@RepeatedTest(5)
|
||||
public void testCompressed() {
|
||||
var terminal = randomTerminal();
|
||||
|
||||
var buffer = new FriendlyByteBuf(Unpooled.directBuffer());
|
||||
new TerminalState(terminal, true).write(buffer);
|
||||
|
||||
checkEqual(terminal, read(buffer));
|
||||
assertEquals(0, buffer.readableBytes());
|
||||
}
|
||||
|
||||
@RepeatedTest(5)
|
||||
public void testUncompressed() {
|
||||
var terminal = randomTerminal();
|
||||
|
||||
var buffer = new FriendlyByteBuf(Unpooled.directBuffer());
|
||||
new TerminalState(terminal, false).write(buffer);
|
||||
|
||||
checkEqual(terminal, read(buffer));
|
||||
assertEquals(0, buffer.readableBytes());
|
||||
}
|
||||
|
||||
private static NetworkedTerminal randomTerminal() {
|
||||
var random = new Random();
|
||||
var terminal = new NetworkedTerminal(10, 5, true);
|
||||
for (var y = 0; y < terminal.getHeight(); y++) {
|
||||
var buffer = terminal.getLine(y);
|
||||
for (var x = 0; x < buffer.length(); x++) buffer.setChar(x, (char) (random.nextInt(26) + 65));
|
||||
}
|
||||
|
||||
return terminal;
|
||||
}
|
||||
|
||||
private static void checkEqual(Terminal expected, Terminal actual) {
|
||||
assertNotNull(expected, "Expected cannot be null");
|
||||
assertNotNull(actual, "Actual cannot be null");
|
||||
assertEquals(expected.getHeight(), actual.getHeight(), "Heights must match");
|
||||
assertEquals(expected.getWidth(), actual.getWidth(), "Widths must match");
|
||||
|
||||
for (var y = 0; y < expected.getHeight(); y++) {
|
||||
assertEquals(expected.getLine(y).toString(), actual.getLine(y).toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static NetworkedTerminal read(FriendlyByteBuf buffer) {
|
||||
var state = new TerminalState(buffer);
|
||||
assertTrue(state.colour);
|
||||
|
||||
if (!state.hasTerminal()) return null;
|
||||
|
||||
var other = new NetworkedTerminal(state.width, state.height, true);
|
||||
state.apply(other);
|
||||
return other;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.network.server;
|
||||
|
||||
import dan200.computercraft.shared.computer.upload.FileUpload;
|
||||
import dan200.computercraft.test.core.ArbitraryByteBuffer;
|
||||
import dan200.computercraft.test.shared.FakeContainer;
|
||||
import dan200.computercraft.test.shared.WithMinecraft;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.jqwik.api.*;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dan200.computercraft.shared.network.server.UploadFileMessage.*;
|
||||
import static dan200.computercraft.test.core.ByteBufferMatcher.bufferEqual;
|
||||
import static dan200.computercraft.test.core.ContramapMatcher.contramap;
|
||||
import static dan200.computercraft.test.core.CustomMatchers.containsWith;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@WithMinecraft
|
||||
public class UploadFileMessageTest {
|
||||
/**
|
||||
* Sends packets on a roundtrip, ensuring that their contents are reassembled on the other end.
|
||||
*
|
||||
* @param sentFiles The files to send.
|
||||
*/
|
||||
@Property(tries = 200)
|
||||
@Tag("slow")
|
||||
public void testRoundTrip(@ForAll("fileUploads") List<FileUpload> sentFiles) {
|
||||
WithMinecraft.Setup.bootstrap(); // @Property doesn't run test lifecycle methods.
|
||||
var receivedFiles = receive(roundtripPackets(send(sentFiles)));
|
||||
assertThat(receivedFiles, containsWith(sentFiles, UploadFileMessageTest::uploadEqual));
|
||||
}
|
||||
|
||||
/**
|
||||
* "Send" our file uploads, converting them to a list of packets.
|
||||
*
|
||||
* @param uploads The files to send.
|
||||
* @return The list of packets.
|
||||
*/
|
||||
private static List<UploadFileMessage> send(List<FileUpload> uploads) {
|
||||
List<UploadFileMessage> packets = new ArrayList<>();
|
||||
UploadFileMessage.send(new FakeContainer(), uploads, packets::add);
|
||||
return packets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write our packets to a buffer and then read them out again.
|
||||
*
|
||||
* @param packets The packets to roundtrip.
|
||||
* @return The
|
||||
*/
|
||||
private static List<UploadFileMessage> roundtripPackets(List<UploadFileMessage> packets) {
|
||||
return packets.stream().map(packet -> {
|
||||
var buffer = new FriendlyByteBuf(Unpooled.directBuffer());
|
||||
packet.toBytes(buffer);
|
||||
// We include things like file size in the packet, but not in the count, so grant a slightly larger threshold.
|
||||
assertThat("Packet is too large", buffer.writerIndex(), lessThanOrEqualTo(MAX_PACKET_SIZE + 128));
|
||||
if ((packet.flag & FLAG_LAST) == 0) {
|
||||
var expectedSize = (packet.flag & FLAG_FIRST) != 0
|
||||
? MAX_PACKET_SIZE - MAX_FILE_NAME * MAX_FILES
|
||||
: MAX_PACKET_SIZE;
|
||||
assertThat(
|
||||
"Non-final packets should be efficiently packed", buffer.writerIndex(), greaterThanOrEqualTo(expectedSize)
|
||||
);
|
||||
}
|
||||
|
||||
var result = new UploadFileMessage(buffer);
|
||||
|
||||
buffer.release();
|
||||
assertEquals(0, buffer.refCnt(), "Buffer should have no references");
|
||||
|
||||
return result;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* "Receive" our upload packets.
|
||||
*
|
||||
* @param packets The packets to receive. Note that this will clobber the {@link FileUpload}s in the first packet,
|
||||
* so you may want to copy (or {@linkplain #roundtripPackets(List) roundtrip} first.
|
||||
* @return The consumed file uploads.
|
||||
*/
|
||||
private static List<FileUpload> receive(List<UploadFileMessage> packets) {
|
||||
var files = packets.get(0).files;
|
||||
for (var i = 0; i < packets.size(); i++) {
|
||||
var packet = packets.get(i);
|
||||
var isFirst = i == 0;
|
||||
var isLast = i == packets.size() - 1;
|
||||
assertEquals(isFirst, (packet.flag & FLAG_FIRST) != 0, "FLAG_FIRST");
|
||||
assertEquals(isLast, (packet.flag & FLAG_LAST) != 0, "FLAG_LAST");
|
||||
|
||||
for (var slice : packet.slices) slice.apply(files);
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
@Provide
|
||||
Arbitrary<FileUpload> fileUpload() {
|
||||
return Combinators.combine(
|
||||
Arbitraries.oneOf(Arrays.asList(
|
||||
// 1.16 doesn't correctly handle unicode file names. We'll be generous in our tests here.
|
||||
Arbitraries.strings().ofMinLength(1).ascii().ofMaxLength(MAX_FILE_NAME),
|
||||
Arbitraries.strings().ofMinLength(1).ofMaxLength(MAX_FILE_NAME / 4)
|
||||
)),
|
||||
ArbitraryByteBuffer.bytes().ofMaxSize(MAX_SIZE)
|
||||
).as(UploadFileMessageTest::file);
|
||||
}
|
||||
|
||||
@Provide
|
||||
Arbitrary<List<FileUpload>> fileUploads() {
|
||||
return fileUpload().list()
|
||||
.ofMinSize(1).ofMaxSize(MAX_FILES)
|
||||
.filter(us -> us.stream().mapToInt(u -> u.getBytes().remaining()).sum() <= MAX_SIZE);
|
||||
}
|
||||
|
||||
private static FileUpload file(String name, ByteBuffer buffer) {
|
||||
var checksum = FileUpload.getDigest(buffer);
|
||||
if (checksum == null) throw new IllegalStateException("Failed to compute checksum");
|
||||
|
||||
return new FileUpload(name, buffer, checksum);
|
||||
}
|
||||
|
||||
public static Matcher<FileUpload> uploadEqual(FileUpload upload) {
|
||||
return allOf(
|
||||
contramap(equalTo(upload.getName()), "name", FileUpload::getName),
|
||||
contramap(equalTo(upload.getChecksum()), "checksum", FileUpload::getChecksum),
|
||||
contramap(bufferEqual(upload.getBytes()), "bytes", FileUpload::getBytes)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.peripheral.speaker;
|
||||
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.lua.ObjectLuaTable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
|
||||
class DfpwmStateTest {
|
||||
@Test
|
||||
public void testEncoder() throws LuaException {
|
||||
var input = new int[]{ 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -4, -4, -4, -4, -4, -5, -5, -5, -5, -5, -6, -6, -6, -7, -7, -7, -7, -7, -7, -7, -7, -7, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, -5, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4, -5, -5, -5, -5, -5, -5, -5, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -7, -7, -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3 };
|
||||
Map<Object, Object> inputTbl = new HashMap<>();
|
||||
for (var i = 0; i < input.length; i++) inputTbl.put((double) (i + 1), input[i]);
|
||||
|
||||
var state = new DfpwmState();
|
||||
state.pushBuffer(new ObjectLuaTable(inputTbl), input.length, Optional.empty());
|
||||
var result = state.pullPending(0);
|
||||
var contents = new byte[result.remaining()];
|
||||
result.get(contents);
|
||||
|
||||
assertArrayEquals(
|
||||
new byte[]{ 87, 74, 42, -91, -92, -108, 84, -87, -86, 86, -83, 90, -83, -43, 90, -85, -42, 106, -43, -86, 106, -107, 42, -107, 74, -87, 74, -91, 74, -91, -86, -86, 106, 85, 107, -83, 106, -83, -83, 86, -75, -86, 42, 85, -107, 82, 41, -91, 82, 74, 41, -107, -86, -44, -86, 86, -75, 106, -83, -75, -86, -75, 90, -83, -86, -86, -86, 82, -91, 74, -107, -86, 82, -87, 82, 85, 85, 85, -83, 86, -75, -86, -43, 90, -83, 90, 85, 85, -107, 42, -91, 82, -86, 82, 74, 41, 85, -87, -86, -86, 106, -75, 90, -83, 86, -85, 106, -43, 106, 85, 85, 85, 85, -107, 42, 85, -86, 42, -107, -86, -86, -86, -86, 106, -75, -86, 86, -85 },
|
||||
contents
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user