CC-Tweaked/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt

687 lines
26 KiB
Kotlin

// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.gametest
import dan200.computercraft.api.detail.BasicItemDetailProvider
import dan200.computercraft.api.detail.VanillaDetailRegistries
import dan200.computercraft.api.lua.ObjectArguments
import dan200.computercraft.api.turtle.ITurtleUpgrade
import dan200.computercraft.api.turtle.TurtleSide
import dan200.computercraft.api.upgrades.UpgradeData
import dan200.computercraft.core.apis.PeripheralAPI
import dan200.computercraft.gametest.api.*
import dan200.computercraft.gametest.core.TestHooks
import dan200.computercraft.impl.TurtleUpgrades
import dan200.computercraft.mixin.gametest.GameTestHelperAccessor
import dan200.computercraft.mixin.gametest.GameTestInfoAccessor
import dan200.computercraft.shared.ModRegistry
import dan200.computercraft.shared.media.items.PrintoutItem
import dan200.computercraft.shared.peripheral.modem.wired.CableBlock
import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant
import dan200.computercraft.shared.peripheral.monitor.MonitorBlock
import dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState
import dan200.computercraft.shared.turtle.apis.TurtleAPI
import dan200.computercraft.shared.util.WaterloggableHelpers
import dan200.computercraft.test.core.assertArrayEquals
import dan200.computercraft.test.core.computer.LuaTaskContext
import dan200.computercraft.test.core.computer.getApi
import net.minecraft.core.BlockPos
import net.minecraft.gametest.framework.GameTest
import net.minecraft.gametest.framework.GameTestHelper
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.item.PrimedTnt
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.item.enchantment.Enchantments
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.FenceBlock
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.properties.BlockStateProperties
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.array
import org.hamcrest.Matchers.instanceOf
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotEquals
import java.util.*
import java.util.concurrent.CopyOnWriteArrayList
import kotlin.time.Duration.Companion.milliseconds
class Turtle_Test {
@GameTest
fun Unequip_refreshes_peripheral(helper: GameTestHelper) = helper.sequence {
thenOnComputer {
getApi<PeripheralAPI>().getType("right").assertArrayEquals("modem", message = "Starts with a modem")
turtle.equipRight().await()
getApi<PeripheralAPI>().getType("right").assertArrayEquals("drive", message = "Unequipping gives a drive")
}
}
/**
* Checks turtles can sheer sheep (and drop items)
*
* @see [#537](https://github.com/cc-tweaked/CC-Tweaked/issues/537)
*/
@GameTest
fun Shears_sheep(helper: GameTestHelper) = helper.sequence {
thenOnComputer {
turtle.placeDown(ObjectArguments()).await()
.assertArrayEquals(true, message = "Shears the sheep")
assertEquals("minecraft:white_wool", getTurtleItemDetail(2)["name"])
}
}
/**
* Checks turtles can place lava.
*
* @see [#518](https://github.com/cc-tweaked/CC-Tweaked/issues/518)
*/
@GameTest
fun Place_lava(helper: GameTestHelper) = helper.sequence {
thenOnComputer {
turtle.placeDown(ObjectArguments()).await()
.assertArrayEquals(true, message = "Placed lava")
}
thenExecute { helper.assertBlockPresent(Blocks.LAVA, BlockPos(2, 2, 2)) }
}
/**
* Checks turtles can write to signs.
*
* @see [#1611](https://github.com/cc-tweaked/CC-Tweaked/issues/1611)
*/
@GameTest
fun Place_sign(helper: GameTestHelper) = helper.sequence {
thenOnComputer {
turtle.place(ObjectArguments("Test\nmessage")).await()
.assertArrayEquals(true, message = "Placed sign")
}
thenExecute {
val sign = helper.getBlockEntity(BlockPos(2, 2, 1), BlockEntityType.SIGN)
val lines = listOf("", "Test", "message", "")
for ((i, line) in lines.withIndex()) {
assertEquals(line, sign.frontText.getMessage(i, false).string, "Line $i")
}
}
}
/**
* Checks that calling [net.minecraft.world.item.Item.use] will not place blocks too far away.
*
* This is caused by items using [net.minecraft.world.item.Item.getPlayerPOVHitResult] to perform a ray trace, which
* ignores turtle's reduced reach distance.
*
* @see [#1497](https://github.com/cc-tweaked/CC-Tweaked/issues/1497)
*/
@GameTest
fun Place_use_reach_limit(helper: GameTestHelper) = helper.sequence {
thenOnComputer {
turtle.placeDown(ObjectArguments()).await()
.assertArrayEquals(true, message = "Placed water")
}
thenExecute {
helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 2))
helper.assertBlockHas(BlockPos(2, 5, 2), BlockStateProperties.WATERLOGGED, true)
}
}
/**
* Checks turtles can place when waterlogged.
*
* @see [#385](https://github.com/cc-tweaked/CC-Tweaked/issues/385)
*/
@GameTest
fun Place_waterlogged(helper: GameTestHelper) = helper.sequence {
thenOnComputer {
turtle.place(ObjectArguments()).await()
.assertArrayEquals(true, message = "Placed oak fence")
}
thenExecute {
helper.assertBlockIs(BlockPos(2, 2, 2)) { it.block == Blocks.OAK_FENCE && it.getValue(FenceBlock.WATERLOGGED) }
}
}
/**
* Checks turtles can pick up lava
*
* @see [#297](https://github.com/cc-tweaked/CC-Tweaked/issues/297)
*/
@GameTest
fun Gather_lava(helper: GameTestHelper) = helper.sequence {
thenOnComputer {
turtle.placeDown(ObjectArguments()).await()
.assertArrayEquals(true, message = "Picked up lava")
assertEquals("minecraft:lava_bucket", getTurtleItemDetail()["name"])
}
thenExecute { helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 2)) }
}
/**
* Checks turtles can hoe dirt.
*
* @see [#258](https://github.com/cc-tweaked/CC-Tweaked/issues/258)
*/
@GameTest
fun Hoe_dirt(helper: GameTestHelper) = helper.sequence {
thenOnComputer { turtle.dig(Optional.empty()).await().assertArrayEquals(true, message = "Dug with hoe") }
thenExecute { helper.assertBlockPresent(Blocks.FARMLAND, BlockPos(1, 2, 1)) }
}
/**
* Checks turtles can hoe dirt with a block gap below them.
*
* @see [#1527](https://github.com/cc-tweaked/CC-Tweaked/issues/1527)
*/
@GameTest
fun Hoe_dirt_below(helper: GameTestHelper) = helper.sequence {
thenOnComputer { turtle.digDown(Optional.empty()).await().assertArrayEquals(true, message = "Dug with hoe") }
thenExecute { helper.assertBlockPresent(Blocks.FARMLAND, BlockPos(1, 1, 1)) }
}
/**
* Checks turtles cannot hoe dirt with a block gap in front of them.
*/
@GameTest
fun Hoe_dirt_distant(helper: GameTestHelper) = helper.sequence {
thenOnComputer {
turtle.dig(Optional.empty()).await()
.assertArrayEquals(false, "Nothing to dig here", message = "Dug with hoe")
}
thenExecute { helper.assertBlockPresent(Blocks.DIRT, BlockPos(1, 2, 2)) }
}
/**
* Checks turtles break cables in two parts.
*/
@GameTest
fun Break_cable(helper: GameTestHelper) = helper.sequence {
thenOnComputer { turtle.dig(Optional.empty()).await() }
thenExecute {
helper.assertBlockIs(BlockPos(2, 2, 3)) {
it.block == ModRegistry.Blocks.CABLE.get() && !it.getValue(CableBlock.CABLE) && it.getValue(CableBlock.MODEM) == CableModemVariant.DownOff
}
helper.assertContainerExactly(BlockPos(2, 2, 2), listOf(ItemStack(ModRegistry.Items.CABLE.get())))
}
thenOnComputer { turtle.dig(Optional.empty()).await().assertArrayEquals(true) }
thenExecute {
helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 3))
helper.assertContainerExactly(
BlockPos(2, 2, 2),
listOf(
ItemStack(ModRegistry.Items.CABLE.get()),
ItemStack(ModRegistry.Items.WIRED_MODEM.get()),
),
)
}
}
/**
* Digging using a pickaxe with `{"consumesDurability": "always"}`, consumes durability.
*/
@GameTest
fun Dig_consume_durability(helper: GameTestHelper) = helper.sequence {
thenOnComputer { turtle.dig(Optional.empty()).await() }
thenExecute {
helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 3))
helper.assertContainerExactly(BlockPos(2, 2, 2), listOf(ItemStack(Items.COBBLESTONE)))
val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access
val upgrade = turtle.getUpgrade(TurtleSide.LEFT)
assertEquals(TurtleUpgrades.instance().get("cctest:wooden_pickaxe"), upgrade, "Upgrade is a wooden pickaxe")
val item = ItemStack(Items.WOODEN_PICKAXE)
item.damageValue = 1
helper.assertUpgradeItem(item, turtle.getUpgradeWithData(TurtleSide.LEFT)!!)
}
}
/**
* Digging using a pickaxe with `{"consumesDurability": "always"}` and no durability removes the tool.
*/
@GameTest
fun Dig_breaks_tool(helper: GameTestHelper) = helper.sequence {
thenOnComputer { turtle.dig(Optional.empty()).await() }
thenExecute {
helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 3))
helper.assertContainerExactly(BlockPos(2, 2, 2), listOf(ItemStack(Items.COBBLESTONE)))
val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access
val upgrade = turtle.getUpgrade(TurtleSide.LEFT)
assertEquals(null, upgrade, "Upgrade broke")
helper.assertUpgradeItem(
ItemStack(Items.WOODEN_PICKAXE),
UpgradeData.ofDefault(TurtleUpgrades.instance().get("cctest:wooden_pickaxe")),
)
}
}
/**
* Digging using a silk-touch enchanted pickaxe with `{"consumesDurability": "when_enchanted"}`, consumes durability
* uses silk touch.
*/
@GameTest
fun Dig_enchanted_consume_durability(helper: GameTestHelper) = helper.sequence {
thenOnComputer { turtle.dig(Optional.empty()).await() }
thenExecute {
helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 3))
helper.assertContainerExactly(BlockPos(2, 2, 2), listOf(ItemStack(Items.STONE)))
val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access
val upgrade = turtle.getUpgrade(TurtleSide.LEFT)
assertEquals(
TurtleUpgrades.instance().get("cctest:netherite_pickaxe"),
upgrade,
"Upgrade is a netherite pickaxe",
)
val item = ItemStack(Items.NETHERITE_PICKAXE)
item.damageValue = 1
item.enchant(Enchantments.SILK_TOUCH, 1)
item.setRepairCost(1)
helper.assertUpgradeItem(item, turtle.getUpgradeWithData(TurtleSide.LEFT)!!)
}
}
private fun GameTestHelper.assertUpgradeItem(expected: ItemStack, upgrade: UpgradeData<ITurtleUpgrade>) {
if (!ItemStack.matches(expected, upgrade.upgradeItem)) {
fail("Invalid upgrade item\n Expected => ${expected.tag}\n Actual => ${upgrade.upgradeItem.tag}")
}
if (!ItemStack.matches(ItemStack(expected.item), upgrade.upgrade.craftingItem)) {
fail("Original upgrade item has changed (is now ${upgrade.upgrade.craftingItem})")
}
}
/**
* Checks turtles can place monitors
*
* @see [#691](https://github.com/cc-tweaked/CC-Tweaked/issues/691)
*/
@GameTest
fun Place_monitor(helper: GameTestHelper) = helper.sequence {
thenOnComputer {
turtle.place(ObjectArguments()).await()
.assertArrayEquals(true, message = "Block was placed")
}
thenIdle(1)
thenExecute { helper.assertBlockHas(BlockPos(1, 2, 3), MonitorBlock.STATE, MonitorEdgeState.LR) }
}
/**
* Checks turtles can place into compostors. These are non-typical inventories, so
* worth testing.
*/
@GameTest
fun Use_compostors(helper: GameTestHelper) = helper.sequence {
thenOnComputer {
turtle.dropDown(Optional.empty()).await()
.assertArrayEquals(true, message = "Item was dropped")
assertEquals(63, turtle.getItemCount(Optional.of(1)), "Only dropped one item")
}
}
/**
* Checks turtles can be cleaned in cauldrons.
*/
@GameTest
fun Cleaned_with_cauldrons(helper: GameTestHelper) = helper.sequence {
thenOnComputer {
val details = getTurtleItemDetail(1, true)
turtle.place(ObjectArguments()).await()
.assertArrayEquals(true, message = "Used item on cauldron")
val newDetails = getTurtleItemDetail(1, true)
assertEquals("computercraft:turtle_normal", newDetails["name"], "Still a turtle")
assertNotEquals(details["nbt"], newDetails["nbt"], "Colour should have changed")
}
}
/**
* Checks turtles can use IDetailProviders by getting details for a printed page.
*/
@GameTest
fun Item_detail_provider(helper: GameTestHelper) = helper.sequence {
// Register a dummy provider for printout items
thenExecute {
VanillaDetailRegistries.ITEM_STACK.addProvider(
object :
BasicItemDetailProvider<PrintoutItem>("printout", PrintoutItem::class.java) {
override fun provideDetails(data: MutableMap<in String, Any>, stack: ItemStack, item: PrintoutItem) {
data["type"] = item.type.toString().lowercase()
}
},
)
}
thenOnComputer {
val details = getTurtleItemDetail(detailed = true)
assertEquals(mapOf("type" to "page"), details["printout"]) {
"Printout information is returned (whole map is $details)"
}
}
}
/**
* Advanced turtles resist all explosions but normal ones don't.
*/
@GameTest
fun Resists_explosions(helper: GameTestHelper) = helper.sequence {
thenExecute {
val pos = helper.absolutePos(BlockPos(2, 2, 2))
val tnt = PrimedTnt(helper.level, pos.x + 0.5, pos.y + 1.0, pos.z + 0.5, null)
tnt.fuse = 1
helper.level.addFreshEntity(tnt)
}
thenWaitUntil { helper.assertEntityNotPresent(EntityType.TNT) }
thenExecute {
helper.assertBlockPresent(ModRegistry.Blocks.TURTLE_ADVANCED.get(), BlockPos(2, 2, 2))
helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 1))
}
}
/**
* Turtles resist mob explosions
*/
@GameTest
fun Resists_entity_explosions(helper: GameTestHelper) = helper.sequence {
thenExecute { helper.getEntity(EntityType.CREEPER).ignite() }
thenWaitUntil { helper.assertEntityNotPresent(EntityType.CREEPER) }
thenExecute {
helper.assertBlockPresent(ModRegistry.Blocks.TURTLE_ADVANCED.get(), BlockPos(2, 2, 2))
helper.assertBlockPresent(ModRegistry.Blocks.TURTLE_NORMAL.get(), BlockPos(2, 2, 1))
}
}
/**
* Test calling `turtle.drop` into an inventory.
*/
@GameTest
fun Drop_into_chest(helper: GameTestHelper) = helper.sequence {
val turtlePos = BlockPos(2, 2, 2)
val chest = BlockPos(2, 2, 3)
thenOnComputer {
turtle.drop(Optional.of(32)).await()
.assertArrayEquals(true, message = "Could not drop items")
}
thenExecute {
helper.assertContainerExactly(turtlePos, listOf(ItemStack(Blocks.DIRT, 32), ItemStack.EMPTY, ItemStack(Blocks.DIRT, 32)))
helper.assertContainerExactly(chest, listOf(ItemStack(Blocks.DIRT, 48)))
}
}
/**
* Test calling `turtle.drop` into an entity with an inventory
*/
@GameTest
fun Drop_into_entity(helper: GameTestHelper) = helper.sequence {
// When running /test runthis, the previous items pop from the chest. Remove them first!
thenExecute { for (it in helper.getEntities(EntityType.ITEM)) it.discard() }
thenOnComputer {
turtle.drop(Optional.of(32)).await()
.assertArrayEquals(true, message = "Could not drop items")
}
thenExecute {
helper.assertContainerExactly(BlockPos(2, 2, 2), listOf(ItemStack(Blocks.DIRT, 32)))
helper.assertContainerExactly(helper.getEntity(EntityType.CHEST_MINECART), listOf(ItemStack(Blocks.DIRT, 48)))
helper.assertEntityNotPresent(EntityType.ITEM)
}
}
/**
* Test calling `turtle.refuel` on solid fuels (coal, blaze powder)
*/
@GameTest
fun Refuel_basic(helper: GameTestHelper) = helper.sequence {
val turtlePos = BlockPos(2, 2, 2)
// Test refueling from slot 1 with no limit.
thenOnComputer {
assertEquals(0, turtle.fuelLevel)
turtle.refuel(Optional.empty()).await().assertArrayEquals(true)
assertEquals(160, turtle.fuelLevel)
}
thenExecute {
helper.assertContainerExactly(turtlePos, listOf(ItemStack.EMPTY, ItemStack(Items.BLAZE_ROD, 2)))
}
// Test refueling from slot 2 with a limit.
thenOnComputer {
turtle.select(2)
turtle.refuel(Optional.of(1)).await().assertArrayEquals(true)
assertEquals(280, turtle.fuelLevel)
}
thenExecute {
helper.assertContainerExactly(turtlePos, listOf(ItemStack.EMPTY, ItemStack(Items.BLAZE_ROD, 1)))
}
}
/**
* Test calling `turtle.refuel` on non-fuels
*/
@GameTest
fun Refuel_fail(helper: GameTestHelper) = helper.sequence {
val turtlePos = BlockPos(2, 2, 2)
thenOnComputer {
assertEquals(0, turtle.fuelLevel)
turtle.refuel(Optional.empty()).await().assertArrayEquals(false, "Items not combustible")
assertEquals(0, turtle.fuelLevel)
}
thenExecute {
helper.assertContainerExactly(turtlePos, listOf(ItemStack(Items.DIRT, 32)))
}
}
/**
* Test calling `turtle.refuel` with a bucket of lava
*/
@GameTest
fun Refuel_container(helper: GameTestHelper) = helper.sequence {
val turtlePos = BlockPos(2, 2, 2)
// Test refueling from slot 1 with no limit.
thenOnComputer {
assertEquals(0, turtle.fuelLevel)
turtle.refuel(Optional.empty()).await().assertArrayEquals(true)
assertEquals(1000, turtle.fuelLevel)
}
thenExecute {
helper.assertContainerExactly(turtlePos, listOf(ItemStack(Items.BUCKET)))
}
}
/**
* Test moving a turtle forwards preserves the turtle's inventory.
*
* @see [#1276](https://github.com/cc-tweaked/CC-Tweaked/pull/1276)
*/
@GameTest
fun Move_preserves_state(helper: GameTestHelper) = helper.sequence {
thenOnComputer { turtle.forward().await().assertArrayEquals(true, message = "Turtle moved forward") }
thenExecute {
helper.assertContainerExactly(BlockPos(2, 2, 3), listOf(ItemStack(Items.DIRT, 32)))
val turtle = helper.getBlockEntity(BlockPos(2, 2, 3), ModRegistry.BlockEntities.TURTLE_NORMAL.get())
assertEquals(1, turtle.computerID)
assertEquals("turtle_test.move_preserves_state", turtle.label)
assertEquals(79, turtle.access.fuelLevel)
helper.assertEntityNotPresent(EntityType.ITEM)
}
}
/**
* Test turtles are not obstructed by plants and instead replace them.
*/
@GameTest
fun Move_replace(helper: GameTestHelper) = helper.sequence {
thenOnComputer { turtle.forward().await().assertArrayEquals(true, message = "Turtle moved forward") }
thenExecute { helper.assertBlockPresent(ModRegistry.Blocks.TURTLE_NORMAL.get(), BlockPos(2, 2, 3)) }
}
/**
* Test turtles become waterlogged when moving through liquid.
*/
@GameTest
fun Move_water(helper: GameTestHelper) = helper.sequence {
thenOnComputer { turtle.forward().await().assertArrayEquals(true, message = "Turtle moved forward") }
thenExecute {
// Assert we're waterlogged.
helper.assertBlockHas(BlockPos(2, 2, 2), WaterloggableHelpers.WATERLOGGED, true)
}
thenOnComputer { turtle.forward().await().assertArrayEquals(true, message = "Turtle moved forward") }
thenExecute {
// Assert we're no longer waterlogged and we've left a source block.
helper.assertBlockIs(BlockPos(2, 2, 2)) { it.block == Blocks.WATER && it.fluidState.isSource }
helper.assertBlockHas(BlockPos(2, 2, 3), WaterloggableHelpers.WATERLOGGED, false)
}
}
/**
* Test turtles can't move through solid blocks.
*/
@GameTest
fun Move_obstruct(helper: GameTestHelper) = helper.sequence {
thenOnComputer { turtle.forward().await().assertArrayEquals(false, "Movement obstructed") }
thenExecute {
helper.assertBlockPresent(ModRegistry.Blocks.TURTLE_NORMAL.get(), BlockPos(2, 2, 2))
helper.assertBlockPresent(Blocks.DIRT, BlockPos(2, 2, 3))
}
}
/**
* Test a turtle can attack an entity and capture its drops.
*/
@GameTest
fun Attack_entity(helper: GameTestHelper) = helper.sequence {
val turtlePos = BlockPos(2, 2, 2)
thenOnComputer {
turtle.attack(Optional.empty()).await().assertArrayEquals(true, message = "Attacked entity")
}
thenExecute {
helper.assertEntityNotPresent(EntityType.SHEEP)
val count = helper.getBlockEntity(turtlePos, ModRegistry.BlockEntities.TURTLE_NORMAL.get())
.countItem(Items.WHITE_WOOL)
if (count == 0) helper.fail("Expected turtle to have white wool", turtlePos)
}
}
/**
* Test a turtle can be destroyed while performing an action.
*
* @see [#585](https://github.com/cc-tweaked/CC-Tweaked/issues/585)
*/
@GameTest
fun Attack_entity_destroy(helper: GameTestHelper) = helper.sequence {
thenStartComputer { turtle.attack(Optional.empty()) }
thenWaitUntil { helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 2)) }
}
/**
* Ensure a turtle never sees itself as a peripheral.
*
* @see <https://github.com/dan200/ComputerCraft/issues/131>
*/
@GameTest
fun No_ghost_peripheral(helper: GameTestHelper) = helper.sequence {
val events = mutableListOf<String>()
thenOnComputer {
for (i in 0 until 3) {
if ((i % 2) == 0) turtle.up() else turtle.down()
do {
val event = pullEvent()[0] as String
events.add(event)
} while (event != "turtle_response")
}
}
}
/**
* Ensure a turtle attaches and detaches peripherals as it moves.
*/
@GameTest
fun Peripheral_change(helper: GameTestHelper) = helper.sequence {
val testInfo = (helper as GameTestHelperAccessor).testInfo as GameTestInfoAccessor
val events = CopyOnWriteArrayList<Pair<String, String>>()
var running = false
thenStartComputer("listen") {
running = true
while (true) {
val event = pullEvent()
TestHooks.LOG.info("[{}] Got event {} at tick {}", testInfo, event[0], testInfo.`computercraft$getTick`())
if (event[0] == "peripheral" || event[0] == "peripheral_detach") {
events.add((event[0] as String) to (event[1] as String))
}
}
}
thenOnComputer("turtle") {
while (!running) sleep(10.milliseconds)
turtle.forward().await().assertArrayEquals(true, message = "Moved turtle forward")
turtle.back().await().assertArrayEquals(true, message = "Moved turtle forward")
TestHooks.LOG.info("[{}] Finished turtle at {}", testInfo, testInfo.`computercraft$getTick`())
}
thenWaitUntil {
val expected = listOf(
"peripheral_detach" to "right",
"peripheral" to "right",
)
if (events != expected) helper.fail("Expected $expected, but received $events")
}
}
/**
* `turtle.suck` only pulls for the current side.
*/
@GameTest
fun Sided_suck(helper: GameTestHelper) = helper.sequence {
thenOnComputer {
turtle.suckUp(Optional.empty()).await().assertArrayEquals(true)
turtle.getItemDetail(context, Optional.empty(), Optional.empty()).await().assertArrayEquals(
mapOf("name" to "minecraft:iron_ingot", "count" to 8),
)
turtle.suckUp(Optional.empty()).await().assertArrayEquals(false, "No items to take")
}
}
/**
* Render turtles as an item.
*/
@ClientGameTest
fun Render_turtle_items(helper: GameTestHelper) = helper.sequence {
thenExecute { helper.positionAtArmorStand() }
thenScreenshot()
}
/**
* Render turtles as a block entity.
*/
@ClientGameTest
fun Render_turtle_blocks(helper: GameTestHelper) = helper.sequence {
thenExecute { helper.positionAtArmorStand() }
thenScreenshot()
}
}
private val LuaTaskContext.turtle get() = getApi<TurtleAPI>()
private suspend fun LuaTaskContext.getTurtleItemDetail(slot: Int = 1, detailed: Boolean = false): Map<String, *> {
val item = turtle.getItemDetail(context, Optional.of(slot), Optional.of(detailed)).await()
assertThat("Returns details", item, array(instanceOf(Map::class.java)))
@Suppress("UNCHECKED_CAST")
return item!![0] as Map<String, *>
}