Update tests.
This commit is contained in:
@@ -1,160 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
package li.cil.oc2.common.bus;
|
||||
|
||||
import li.cil.oc2.api.bus.DeviceBusElement;
|
||||
import li.cil.oc2.common.capabilities.Capabilities;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class BlockBusTests {
|
||||
@SuppressWarnings("unchecked") private static final Capability<DeviceBusElement> DEVICE_BUS_ELEMENT_CAPABILITY = (Capability<DeviceBusElement>) mock(Capability.class);
|
||||
|
||||
private FakeLevel fakeLevel;
|
||||
private LevelAccessor level;
|
||||
private MockedStatic<Capabilities> capabilitiesMock;
|
||||
|
||||
@BeforeEach
|
||||
public void setupEach() {
|
||||
fakeLevel = new FakeLevel();
|
||||
level = fakeLevel.getLevel();
|
||||
capabilitiesMock = mockStatic(Capabilities.class);
|
||||
capabilitiesMock.when(Capabilities::deviceBusElement).thenReturn(DEVICE_BUS_ELEMENT_CAPABILITY);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void teardownEach() {
|
||||
capabilitiesMock.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void busTouchingUnloadedChunkStaysIncomplete() {
|
||||
final BlockDeviceBusController busController = createBusController(new BlockPos(0, 0, 0));
|
||||
|
||||
busController.scan();
|
||||
|
||||
assertEquals(CommonDeviceBusController.BusState.INCOMPLETE, busController.getState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void busNotTouchingUnloadedChunkCompletes() {
|
||||
final BlockDeviceBusController busController = createBusController(new BlockPos(8, 0, 8));
|
||||
|
||||
busController.scan();
|
||||
|
||||
assertEquals(CommonDeviceBusController.BusState.READY, busController.getState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void busControllerDetectsBusElements() {
|
||||
final BlockDeviceBusController busController = createBusController(new BlockPos(8, 0, 8));
|
||||
|
||||
final DeviceBusElement busElement = createBusElement(new BlockPos(9, 0, 8));
|
||||
|
||||
busController.scan();
|
||||
|
||||
assertEquals(CommonDeviceBusController.BusState.READY, busController.getState());
|
||||
|
||||
assertTrue(busElement.getControllers().contains(busController));
|
||||
assertTrue(busController.getElements().contains(busElement));
|
||||
}
|
||||
|
||||
private BlockDeviceBusController createBusController(final BlockPos pos) {
|
||||
final TestBlockDeviceBusElement busElement = new TestBlockDeviceBusElement(level, pos);
|
||||
final BlockEntity blockEntity = mock(BlockEntity.class);
|
||||
when(blockEntity.getBlockPos()).thenReturn(pos);
|
||||
when(blockEntity.getCapability(any(), any())).thenReturn(LazyOptional.empty());
|
||||
final BlockDeviceBusController busController = new BlockDeviceBusController(busElement, 0, blockEntity);
|
||||
|
||||
fakeLevel.addBlockEntity(blockEntity);
|
||||
fakeLevel.setChunkLoaded(new ChunkPos(pos), true);
|
||||
|
||||
return busController;
|
||||
}
|
||||
|
||||
private AbstractBlockDeviceBusElement createBusElement(final BlockPos pos) {
|
||||
final TestBlockDeviceBusElement busElement = new TestBlockDeviceBusElement(level, pos);
|
||||
final BlockEntity blockEntity = mock(BlockEntity.class);
|
||||
when(blockEntity.getBlockPos()).thenReturn(pos);
|
||||
when(blockEntity.getCapability(any(), any())).thenReturn(LazyOptional.empty());
|
||||
when(blockEntity.getCapability(eq(Capabilities.deviceBusElement()), any())).thenReturn(LazyOptional.of(() -> busElement));
|
||||
|
||||
fakeLevel.addBlockEntity(blockEntity);
|
||||
fakeLevel.setChunkLoaded(new ChunkPos(pos), true);
|
||||
|
||||
return busElement;
|
||||
}
|
||||
|
||||
private static final class FakeLevel {
|
||||
private final LevelAccessor level = mock(LevelAccessor.class);
|
||||
private final HashMap<BlockPos, BlockEntity> blockEntities = new HashMap<>();
|
||||
private final HashSet<ChunkPos> loadedChunks = new HashSet<>();
|
||||
|
||||
public FakeLevel() {
|
||||
when(level.getBlockEntity(any())).then(a -> blockEntities.get(a.<BlockPos>getArgument(0)));
|
||||
|
||||
when(level.hasChunk(anyInt(), anyInt())).then(a -> {
|
||||
final int chunkX = a.getArgument(0);
|
||||
final int chunkZ = a.getArgument(1);
|
||||
return loadedChunks.contains(new ChunkPos(chunkX, chunkZ));
|
||||
});
|
||||
}
|
||||
|
||||
public LevelAccessor getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void addBlockEntity(final BlockEntity blockEntity) {
|
||||
blockEntities.put(blockEntity.getBlockPos(), blockEntity);
|
||||
}
|
||||
|
||||
public void removeBlockEntity(final BlockPos pos) {
|
||||
blockEntities.remove(pos);
|
||||
}
|
||||
|
||||
public void setChunkLoaded(final ChunkPos chunkPos, final boolean loaded) {
|
||||
if (loaded) {
|
||||
loadedChunks.add(chunkPos);
|
||||
} else {
|
||||
loadedChunks.remove(chunkPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class TestBlockDeviceBusElement extends AbstractBlockDeviceBusElement {
|
||||
private final LevelAccessor level;
|
||||
private final BlockPos blockPos;
|
||||
|
||||
public TestBlockDeviceBusElement(final LevelAccessor level, final BlockPos blockPos) {
|
||||
this.level = level;
|
||||
this.blockPos = blockPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelAccessor getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos getPosition() {
|
||||
return blockPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,521 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
package li.cil.oc2.common.bus;
|
||||
|
||||
import li.cil.oc2.api.API;
|
||||
import li.cil.oc2.api.bus.DeviceBusElement;
|
||||
import li.cil.oc2.api.bus.device.Device;
|
||||
import li.cil.oc2.api.bus.device.ItemDevice;
|
||||
import li.cil.oc2.api.bus.device.object.Callback;
|
||||
import li.cil.oc2.api.bus.device.object.ObjectDevice;
|
||||
import li.cil.oc2.api.bus.device.provider.BlockDeviceProvider;
|
||||
import li.cil.oc2.api.bus.device.provider.BlockDeviceQuery;
|
||||
import li.cil.oc2.api.bus.device.provider.ItemDeviceProvider;
|
||||
import li.cil.oc2.api.bus.device.provider.ItemDeviceQuery;
|
||||
import li.cil.oc2.api.util.Invalidatable;
|
||||
import li.cil.oc2.common.Constants;
|
||||
import li.cil.oc2.common.bus.device.provider.Providers;
|
||||
import li.cil.oc2.common.capabilities.Capabilities;
|
||||
import li.cil.oc2.common.util.LevelUtils;
|
||||
import li.cil.sedna.api.device.serial.SerialDevice;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.registries.ForgeRegistryEntry;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.stubbing.OngoingStubbing;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class BlockDeviceBusControllerTests {
|
||||
public static final IForgeRegistry<BlockDeviceProvider> BLOCK_DEVICE_PROVIDER_REGISTRY = createBlockDeviceProviderRegistry();
|
||||
public static final IForgeRegistry<ItemDeviceProvider> ITEM_DEVICE_PROVIDER_REGISTRY = createItemDeviceProviderRegistry();
|
||||
|
||||
private static final Set<Class<?>> REGISTERED_CAPABILITIES = new HashSet<>();
|
||||
|
||||
private static MockedStatic<Capabilities> capabilitiesMock;
|
||||
private static MockedStatic<Providers> providersMock;
|
||||
private static MockedStatic<LevelUtils> levelUtilsMock;
|
||||
|
||||
private FakeLevel fakeLevel;
|
||||
private LevelAccessor level;
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
capabilitiesMock = mockStatic(Capabilities.class);
|
||||
registerCapability(capabilitiesMock.when(Capabilities::energyStorage));
|
||||
registerCapability(capabilitiesMock.when(Capabilities::fluidHandler));
|
||||
registerCapability(capabilitiesMock.when(Capabilities::itemHandler));
|
||||
registerCapability(capabilitiesMock.when(Capabilities::deviceBusElement));
|
||||
registerCapability(capabilitiesMock.when(Capabilities::device));
|
||||
registerCapability(capabilitiesMock.when(Capabilities::redstoneEmitter));
|
||||
registerCapability(capabilitiesMock.when(Capabilities::networkInterface));
|
||||
registerCapability(capabilitiesMock.when(Capabilities::terminalUserProvider));
|
||||
registerCapability(capabilitiesMock.when(Capabilities::robot));
|
||||
Capabilities.registerCapabilities(type -> assertTrue(REGISTERED_CAPABILITIES.contains(type)));
|
||||
|
||||
providersMock = mockStatic(Providers.class);
|
||||
providersMock.when(Providers::blockDeviceProviderRegistry).thenReturn(BLOCK_DEVICE_PROVIDER_REGISTRY);
|
||||
providersMock.when(Providers::itemDeviceProviderRegistry).thenReturn(ITEM_DEVICE_PROVIDER_REGISTRY);
|
||||
|
||||
levelUtilsMock = mockStatic(LevelUtils.class);
|
||||
levelUtilsMock.when(() -> LevelUtils.getBlockName(any(), any())).thenReturn("test_block");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> void registerCapability(final OngoingStubbing<Capability<T>> stubbing) {
|
||||
final Capability<T> capability = mock(Capability.class);
|
||||
stubbing.thenReturn(capability);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void teardown() {
|
||||
REGISTERED_CAPABILITIES.clear();
|
||||
|
||||
capabilitiesMock.close();
|
||||
providersMock.close();
|
||||
levelUtilsMock.close();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setupEach() {
|
||||
fakeLevel = new FakeLevel();
|
||||
level = fakeLevel.getLevel();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void busTouchingUnloadedChunkStaysIncomplete() {
|
||||
final BlockPos posAtChunkEdge = new BlockPos(0, 0, 0);
|
||||
final BlockDeviceBusController busController = new TestBusControllerBlockEntity(posAtChunkEdge).getBusController();
|
||||
|
||||
busController.scan();
|
||||
|
||||
assertEquals(CommonDeviceBusController.BusState.INCOMPLETE, busController.getState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void busNotTouchingUnloadedChunkCompletes() {
|
||||
final BlockPos posInsideChunk = new BlockPos(8, 0, 8);
|
||||
final BlockDeviceBusController busController = new TestBusControllerBlockEntity(posInsideChunk).getBusController();
|
||||
|
||||
busController.scan();
|
||||
|
||||
assertEquals(CommonDeviceBusController.BusState.READY, busController.getState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void busControllerIgnoresNonAccessibleBusElements() {
|
||||
final BlockPos controllerPos = new BlockPos(8, 0, 8);
|
||||
final TestBusControllerBlockEntity busController = new TestBusControllerBlockEntity(controllerPos);
|
||||
|
||||
final BlockPos elementPos = controllerPos.east();
|
||||
final TestBusElementBlockEntity busElement = new TestBusElementBlockEntity(elementPos);
|
||||
busElement.setSideEnabled(Direction.WEST, false);
|
||||
|
||||
busController.getBusController().scan();
|
||||
|
||||
assertEquals(CommonDeviceBusController.BusState.READY, busController.getBusController().getState());
|
||||
|
||||
assertFalse(busElement.getBusElement().getControllers().contains(busController.getBusController()));
|
||||
assertFalse(busController.getBusController().getElements().contains(busElement.getBusElement()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void busControllerDetectsBusElements() {
|
||||
final BlockPos controllerPos = new BlockPos(8, 0, 8);
|
||||
final BlockDeviceBusController busController = new TestBusControllerBlockEntity(controllerPos).getBusController();
|
||||
|
||||
final BlockPos elementPos = controllerPos.east();
|
||||
final TestBusElementBlockEntity busElementInfo = new TestBusElementBlockEntity(elementPos);
|
||||
final DeviceBusElement busElement = busElementInfo.getBusElement();
|
||||
|
||||
busController.scan();
|
||||
|
||||
assertTrue(busElement.getControllers().contains(busController));
|
||||
assertTrue(busController.getElements().contains(busElement));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void devicesInUnloadedChunksAreMarkedAsUnloaded() {
|
||||
final BlockPos elementPos = new BlockPos(0, 0, 0);
|
||||
final TestBusElementBlockEntity busElementInfo = new TestBusElementBlockEntity(elementPos);
|
||||
final TestBlockDeviceBusElement busElement = busElementInfo.getBusElement();
|
||||
|
||||
busElement.updateDevicesForNeighbor(Direction.WEST);
|
||||
verify(busElement, atLeastOnce()).setEntriesForGroupUnloaded(Direction.WEST.get3DDataValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void devicesInLoadedChunksAreCollected() {
|
||||
final BlockPos elementPos = new BlockPos(0, 0, 0);
|
||||
final TestBusElementBlockEntity busElementInfo = new TestBusElementBlockEntity(elementPos);
|
||||
final TestBlockDeviceBusElement busElement = busElementInfo.getBusElement();
|
||||
|
||||
final BlockPos devicePos = elementPos.east();
|
||||
final TestDeviceBlockEntity deviceBlockEntity = new TestDeviceBlockEntity(devicePos);
|
||||
|
||||
busElement.updateDevicesForNeighbor(Direction.EAST);
|
||||
verify(busElement, atLeastOnce()).setEntriesForGroup(eq(Direction.EAST.get3DDataValue()), any());
|
||||
assertTrue(busElement.getDevices().contains(deviceBlockEntity.getObjectDevice()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalDevicesAreIgnored() {
|
||||
final BlockPos elementPos = new BlockPos(0, 0, 0);
|
||||
final TestBusElementBlockEntity busElementInfo = new TestBusElementBlockEntity(elementPos);
|
||||
final TestBlockDeviceBusElement busElement = busElementInfo.getBusElement();
|
||||
|
||||
final BlockPos devicePos = elementPos.east();
|
||||
final TestDeviceBlockEntity deviceBlockEntity = new TestDeviceBlockEntity(devicePos);
|
||||
|
||||
busElement.updateDevicesForNeighbor(Direction.EAST);
|
||||
|
||||
assertTrue(busElement.getDevices().contains(deviceBlockEntity.getObjectDevice()));
|
||||
|
||||
final ObjectDevice equalDevice = new ObjectDevice(deviceBlockEntity.getTestDevice());
|
||||
deviceBlockEntity.setObjectDevice(equalDevice);
|
||||
|
||||
busElement.updateDevicesForNeighbor(Direction.EAST);
|
||||
|
||||
assertTrue(busElement.getDevices().contains(deviceBlockEntity.getObjectDevice()));
|
||||
assertNotSame(busElement.getDevices().stream().findFirst().orElseThrow(), equalDevice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void busControllerDetectsDevices() {
|
||||
final BlockPos controllerPos = new BlockPos(8, 0, 8);
|
||||
final BlockDeviceBusController busController = new TestBusControllerBlockEntity(controllerPos).getBusController();
|
||||
|
||||
final BlockPos elementPos = controllerPos.east();
|
||||
final TestBusElementBlockEntity busElementInfo = new TestBusElementBlockEntity(elementPos);
|
||||
when(busElementInfo.getBlockEntity().getCapability(eq(Capabilities.deviceBusElement()), any())).thenReturn(LazyOptional.of(busElementInfo::getBusElement));
|
||||
|
||||
final BlockPos devicePos = elementPos.east();
|
||||
final TestDeviceBlockEntity deviceBlockEntity = new TestDeviceBlockEntity(devicePos);
|
||||
|
||||
busElementInfo.getBusElement().updateDevicesForNeighbor(Direction.EAST);
|
||||
busController.scan();
|
||||
|
||||
assertTrue(busController.getDevices().contains(deviceBlockEntity.getObjectDevice()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void devicesGetSerializedWhenUnloadedAndDeserializedWhenLoaded() {
|
||||
final BlockPos controllerPos = new BlockPos(1, 0, 8);
|
||||
final BlockDeviceBusController busController = new TestBusControllerBlockEntity(controllerPos).getBusController();
|
||||
|
||||
final BlockPos elementPos = controllerPos.west();
|
||||
final TestBusElementBlockEntity busElementInfo = new TestBusElementBlockEntity(elementPos);
|
||||
when(busElementInfo.getBlockEntity().getCapability(eq(Capabilities.deviceBusElement()), any())).thenReturn(LazyOptional.of(busElementInfo::getBusElement));
|
||||
|
||||
final BlockPos devicePos = elementPos.west();
|
||||
final TestDeviceBlockEntity deviceBlockEntity = new TestDeviceBlockEntity(devicePos);
|
||||
|
||||
fakeLevel.setChunkLoaded(new ChunkPos(devicePos), false);
|
||||
busController.scheduleBusScan();
|
||||
|
||||
final RPCDeviceBusAdapter rpcDeviceBusAdapter = new RPCDeviceBusAdapter(mock(SerialDevice.class));
|
||||
busController.onBeforeDeviceScan.add(rpcDeviceBusAdapter::pause);
|
||||
busController.onAfterDeviceScan.add(event -> rpcDeviceBusAdapter.resume(busController, event.didDevicesChange()));
|
||||
|
||||
busController.scan();
|
||||
|
||||
// Reminder: missing chunk -> bus scan cannot complete.
|
||||
assertEquals(CommonDeviceBusController.BusState.INCOMPLETE, busController.getState());
|
||||
|
||||
final ObjectDevice objectDevice = spy(deviceBlockEntity.getObjectDevice());
|
||||
deviceBlockEntity.setObjectDevice(objectDevice);
|
||||
|
||||
// Initialize with unloaded chunk.
|
||||
busElementInfo.getBusElement().updateDevicesForNeighbor(Direction.WEST);
|
||||
|
||||
assertFalse(busController.getDevices().contains(objectDevice));
|
||||
|
||||
verify(objectDevice, never()).mount();
|
||||
verify(objectDevice, never()).unmount();
|
||||
verify(objectDevice, never()).dispose();
|
||||
verify(objectDevice, never()).serializeNBT();
|
||||
verify(objectDevice, never()).deserializeNBT(any());
|
||||
|
||||
// Load device chunk.
|
||||
fakeLevel.setChunkLoaded(new ChunkPos(devicePos), true);
|
||||
busController.scheduleBusScan();
|
||||
busElementInfo.getBusElement().updateDevicesForNeighbor(Direction.WEST);
|
||||
|
||||
busController.scan();
|
||||
assertEquals(CommonDeviceBusController.BusState.READY, busController.getState());
|
||||
|
||||
assertTrue(busController.getDevices().contains(objectDevice));
|
||||
|
||||
rpcDeviceBusAdapter.mountDevices();
|
||||
|
||||
verify(objectDevice, times(1)).mount();
|
||||
verify(objectDevice, never()).unmount();
|
||||
verify(objectDevice, never()).dispose();
|
||||
verify(objectDevice, never()).serializeNBT();
|
||||
verify(objectDevice, never()).deserializeNBT(any()); // no state to deserialize
|
||||
|
||||
// Unload device chunk.
|
||||
fakeLevel.setChunkLoaded(new ChunkPos(devicePos), false);
|
||||
busController.scheduleBusScan();
|
||||
busElementInfo.getBusElement().updateDevicesForNeighbor(Direction.WEST);
|
||||
|
||||
busController.scan();
|
||||
assertEquals(CommonDeviceBusController.BusState.INCOMPLETE, busController.getState());
|
||||
|
||||
assertFalse(busController.getDevices().contains(objectDevice));
|
||||
|
||||
verify(objectDevice, times(1)).mount();
|
||||
verify(objectDevice, times(1)).unmount();
|
||||
verify(objectDevice, never()).dispose();
|
||||
verify(objectDevice, times(1)).serializeNBT();
|
||||
verify(objectDevice, never()).deserializeNBT(any());
|
||||
}
|
||||
|
||||
// TODO device in loaded chunk -> unloaded chunk + saved -> loaded chunk + loaded
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static IForgeRegistry<BlockDeviceProvider> createBlockDeviceProviderRegistry() {
|
||||
final IForgeRegistry<BlockDeviceProvider> registry = mock(IForgeRegistry.class);
|
||||
|
||||
final Map<ResourceLocation, BlockDeviceProvider> blockDeviceProviders = new HashMap<>();
|
||||
blockDeviceProviders.put(new ResourceLocation(API.MOD_ID, "test"), new TestBlockDeviceProvider());
|
||||
|
||||
when(registry.getValues()).thenReturn(blockDeviceProviders.values());
|
||||
when(registry.getValue(notNull())).then(a -> blockDeviceProviders.get(a.<ResourceLocation>getArgument(0)));
|
||||
|
||||
return registry;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static IForgeRegistry<ItemDeviceProvider> createItemDeviceProviderRegistry() {
|
||||
final IForgeRegistry<ItemDeviceProvider> registry = mock(IForgeRegistry.class);
|
||||
|
||||
final Map<ResourceLocation, ItemDeviceProvider> itemDeviceProviders = new HashMap<>();
|
||||
itemDeviceProviders.put(new ResourceLocation(API.MOD_ID, "test"), new TestItemDeviceProvider());
|
||||
|
||||
when(registry.getValues()).thenReturn(itemDeviceProviders.values());
|
||||
when(registry.getValue(notNull())).then(a -> itemDeviceProviders.get(a.<ResourceLocation>getArgument(0)));
|
||||
|
||||
return registry;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
private static final class FakeLevel {
|
||||
private final LevelAccessor level = mock(LevelAccessor.class);
|
||||
private final HashMap<BlockPos, BlockEntity> blockEntities = new HashMap<>();
|
||||
private final HashSet<ChunkPos> loadedChunks = new HashSet<>();
|
||||
|
||||
public FakeLevel() {
|
||||
when(level.getBlockEntity(any())).then(a -> blockEntities.get(a.<BlockPos>getArgument(0)));
|
||||
|
||||
when(level.hasChunk(anyInt(), anyInt())).then(a -> {
|
||||
final int chunkX = a.getArgument(0);
|
||||
final int chunkZ = a.getArgument(1);
|
||||
return loadedChunks.contains(new ChunkPos(chunkX, chunkZ));
|
||||
});
|
||||
}
|
||||
|
||||
public LevelAccessor getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void addBlockEntity(final BlockEntity blockEntity) {
|
||||
blockEntities.put(blockEntity.getBlockPos(), blockEntity);
|
||||
}
|
||||
|
||||
public void removeBlockEntity(final BlockPos pos) {
|
||||
blockEntities.remove(pos);
|
||||
}
|
||||
|
||||
public void setChunkLoaded(final ChunkPos chunkPos, final boolean loaded) {
|
||||
if (loaded) {
|
||||
loadedChunks.add(chunkPos);
|
||||
} else {
|
||||
loadedChunks.remove(chunkPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TestBlockEntity {
|
||||
private final BlockEntity blockEntity;
|
||||
|
||||
public TestBlockEntity(final BlockPos pos) {
|
||||
blockEntity = mock(BlockEntity.class);
|
||||
when(blockEntity.getBlockPos()).thenReturn(pos);
|
||||
when(blockEntity.getCapability(any(), any())).thenReturn(LazyOptional.empty());
|
||||
when(blockEntity.getCapability(any())).thenCallRealMethod();
|
||||
|
||||
fakeLevel.addBlockEntity(blockEntity);
|
||||
fakeLevel.setChunkLoaded(new ChunkPos(pos), true);
|
||||
}
|
||||
|
||||
public BlockEntity getBlockEntity() {
|
||||
return blockEntity;
|
||||
}
|
||||
}
|
||||
|
||||
private class TestBusElementBlockEntity extends TestBlockEntity {
|
||||
private final TestBlockDeviceBusElement busElement;
|
||||
private final boolean[] enabledSides = new boolean[Constants.BLOCK_FACE_COUNT];
|
||||
|
||||
public TestBusElementBlockEntity(final BlockPos pos) {
|
||||
super(pos);
|
||||
busElement = spy(new TestBlockDeviceBusElement(level, pos));
|
||||
when(getBlockEntity().getCapability(eq(Capabilities.deviceBusElement()), any())).then(a -> {
|
||||
if (enabledSides[a.<Direction>getArgument(1).get3DDataValue()]) {
|
||||
return LazyOptional.of(() -> busElement);
|
||||
} else {
|
||||
return LazyOptional.empty();
|
||||
}
|
||||
});
|
||||
Arrays.fill(enabledSides, true);
|
||||
}
|
||||
|
||||
public TestBlockDeviceBusElement getBusElement() {
|
||||
return busElement;
|
||||
}
|
||||
|
||||
public void setSideEnabled(final Direction side, final boolean value) {
|
||||
enabledSides[side.get3DDataValue()] = value;
|
||||
}
|
||||
}
|
||||
|
||||
private class TestBusControllerBlockEntity extends TestBusElementBlockEntity {
|
||||
private final BlockDeviceBusController busController;
|
||||
|
||||
public TestBusControllerBlockEntity(final BlockPos pos) {
|
||||
super(pos);
|
||||
busController = new BlockDeviceBusController(getBusElement(), 0, getBlockEntity());
|
||||
}
|
||||
|
||||
public BlockDeviceBusController getBusController() {
|
||||
return busController;
|
||||
}
|
||||
}
|
||||
|
||||
private class TestDeviceBlockEntity extends TestBlockEntity {
|
||||
private final TestDevice testDevice;
|
||||
private ObjectDevice objectDevice;
|
||||
|
||||
public TestDeviceBlockEntity(final BlockPos pos) {
|
||||
super(pos);
|
||||
testDevice = new TestDevice();
|
||||
objectDevice = new ObjectDevice(testDevice);
|
||||
when(getBlockEntity().getCapability(eq(Capabilities.device()), any())).thenReturn(LazyOptional.of(() -> objectDevice));
|
||||
}
|
||||
|
||||
public TestDevice getTestDevice() {
|
||||
return testDevice;
|
||||
}
|
||||
|
||||
public ObjectDevice getObjectDevice() {
|
||||
return objectDevice;
|
||||
}
|
||||
|
||||
public void setObjectDevice(final ObjectDevice device) {
|
||||
this.objectDevice = device;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class TestBlockDeviceBusElement extends AbstractBlockDeviceBusElement {
|
||||
private final LevelAccessor level;
|
||||
private final BlockPos blockPos;
|
||||
|
||||
public TestBlockDeviceBusElement(final LevelAccessor level, final BlockPos blockPos) {
|
||||
this.level = level;
|
||||
this.blockPos = blockPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelAccessor getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos getPosition() {
|
||||
return blockPos;
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestBlockDeviceProvider implements BlockDeviceProvider {
|
||||
@Override
|
||||
public BlockDeviceProvider setRegistryName(final ResourceLocation name) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ResourceLocation getRegistryName() {
|
||||
return new ResourceLocation(API.MOD_ID, "test");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<BlockDeviceProvider> getRegistryType() {
|
||||
return BlockDeviceProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Invalidatable<Device> getDevice(final BlockDeviceQuery query) {
|
||||
final LevelAccessor level = query.getLevel();
|
||||
final BlockEntity blockEntity = level.getBlockEntity(query.getQueryPosition());
|
||||
if (blockEntity != null) {
|
||||
final Optional<Device> optional = blockEntity.getCapability(Capabilities.device()).resolve();
|
||||
return optional.map(Invalidatable::of).orElseGet(Invalidatable::empty);
|
||||
}
|
||||
return Invalidatable.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestItemDeviceProvider implements ItemDeviceProvider {
|
||||
@Override
|
||||
public ItemDeviceProvider setRegistryName(final ResourceLocation name) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ResourceLocation getRegistryName() {
|
||||
return new ResourceLocation(API.MOD_ID, "test");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<ItemDeviceProvider> getRegistryType() {
|
||||
return ItemDeviceProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ItemDevice> getDevice(final ItemDeviceQuery query) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestDevice {
|
||||
@Callback
|
||||
public int test() {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class DeviceBusTests {
|
||||
public class CommonDeviceBusControllerTests {
|
||||
private CommonDeviceBusController busController;
|
||||
private DeviceBusElement busControllerBusElement;
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.util.*;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public final class RPCDeviceTests {
|
||||
public final class RPCDeviceBusAdapterTests {
|
||||
private RPCDeviceBusAdapter adapter;
|
||||
private Set<Device> busDevices;
|
||||
private Map<Device, Set<UUID>> deviceIdentifiers;
|
||||
@@ -56,7 +56,7 @@ public final class RPCDeviceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mountedDevicesAreUnmountedAndDisposedWhenRemoved() {
|
||||
public void mountedDevicesAreUnmountedWhenRemoved() {
|
||||
final RPCDevice device = addDevice();
|
||||
adapter.resume(controller, true);
|
||||
adapter.mountDevices();
|
||||
@@ -64,18 +64,18 @@ public final class RPCDeviceTests {
|
||||
removeDevice(device);
|
||||
adapter.resume(controller, true);
|
||||
verify(device).unmount();
|
||||
verify(device).dispose();
|
||||
verify(device, never()).dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unmountedDevicesAreDisposedWhenRemoved() {
|
||||
public void unmountedDevicesAreSilentlyRemoved() {
|
||||
final RPCDevice device = addDevice();
|
||||
adapter.resume(controller, true);
|
||||
|
||||
removeDevice(device);
|
||||
adapter.resume(controller, true);
|
||||
verify(device, never()).unmount();
|
||||
verify(device).dispose();
|
||||
verify(device, never()).dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -24,7 +24,7 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public final class VMDeviceTests {
|
||||
public final class VMDeviceBusAdapterTests {
|
||||
private MemoryMap memoryMap;
|
||||
private InterruptController interruptController;
|
||||
private R5MemoryRangeAllocationStrategy allocationStrategy;
|
||||
@@ -106,7 +106,7 @@ public final class VMDeviceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mountedDevicesAreUnmountedAndDisposedIfOtherMountFails() {
|
||||
public void mountedDevicesAreUnmountedIfOtherMountFails() {
|
||||
final VMDevice device1 = mock(VMDevice.class);
|
||||
final VMDevice device2 = mock(VMDevice.class);
|
||||
when(device1.mount(any())).thenReturn(VMDeviceLoadResult.success());
|
||||
@@ -119,11 +119,11 @@ public final class VMDeviceTests {
|
||||
verify(device1).mount(any());
|
||||
verify(device2).mount(any());
|
||||
verify(device1).unmount();
|
||||
verify(device1).dispose();
|
||||
verify(device1, never()).dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mountedDevicesAreUnmountedAndDisposedWhenRemoved() {
|
||||
public void mountedDevicesAreUnmountedWhenRemoved() {
|
||||
final VMDevice device = mock(VMDevice.class);
|
||||
when(device.mount(any())).thenReturn(VMDeviceLoadResult.success());
|
||||
|
||||
@@ -132,17 +132,24 @@ public final class VMDeviceTests {
|
||||
|
||||
adapter.removeDevices(Collections.singleton(device));
|
||||
verify(device).unmount();
|
||||
verify(device).dispose();
|
||||
verify(device, never()).dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unmountedDevicesAreDisposedWhenRemoved() {
|
||||
public void unmountedDevicesAreSilentlyRemoved() {
|
||||
final VMDevice device = mock(VMDevice.class);
|
||||
when(device.mount(any())).thenReturn(VMDeviceLoadResult.success());
|
||||
|
||||
adapter.addDevices(Collections.singleton(device));
|
||||
adapter.mountDevices();
|
||||
verify(device).mount(any());
|
||||
|
||||
adapter.unmountDevices();
|
||||
verify(device).unmount();
|
||||
|
||||
adapter.removeDevices(Collections.singleton(device));
|
||||
verify(device).dispose();
|
||||
|
||||
verify(device, never()).dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
Reference in New Issue
Block a user