Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/publish-maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
tags:
- "broccolium-*"
- "peripheralium-*"
- "testiarium-*"
- "tweakium-*"

permissions:
Expand All @@ -26,7 +27,7 @@ jobs:
run: |
set -euo pipefail

if [[ ! "$GITHUB_REF_NAME" =~ ^(broccolium|peripheralium|tweakium)-([0-9]+\.[0-9]+)-(.+)$ ]]; then
if [[ ! "$GITHUB_REF_NAME" =~ ^(broccolium|peripheralium|testiarium|tweakium)-([0-9]+\.[0-9]+)-(.+)$ ]]; then
echo "::error::Tag must match <project>-<minecraft-release>-<library-version>"
exit 1
fi
Expand Down
51 changes: 51 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# AGENTS.md

## Project overview

Minecraft 1.20.1 libraries written primarily in Kotlin. The build publishes three libraries for both Forge and Fabric:

- `broccolium`: platform and storage abstractions.
- `tweakium`: ComputerCraft pocket and gameplay utilities; depends on Broccolium.
- `peripheralium`: ComputerCraft peripherals; depends on Tweakium and Broccolium.

Each library has a shared `*-core` module plus `*-forge` and `*-fabric` loader adapters. Keep loader-neutral code and APIs in `*-core`; put Forge or Fabric API calls, entrypoints, mixins, access transformers, and loader metadata in the matching adapter module.

## Layout

- `projects/<library>-core`: common code and shared assets.
- `projects/<library>-forge`: Forge implementation; metadata is in `src/main/resources/META-INF/mods.toml`.
- `projects/<library>-fabric`: Fabric implementation; metadata is in `src/main/resources/fabric.mod.json`.
- `gradle/libs.versions.toml`: dependency and plugin versions.
- `gradle.properties`: Minecraft and library versions.

Shared modules use access wideners. Forge modules use access transformers and may use mixins; Fabric modules may use mixins. Update the relevant loader configuration and metadata when changing either integration boundary.

## Build and test

Use the checked-in Gradle wrapper:

```sh
./gradlew test
./gradlew build
./gradlew :broccolium-core:test
./gradlew :broccolium-forge:test
./gradlew :broccolium-fabric:test
```

Run the smallest affected module test task while iterating, then `./gradlew test` for changes spanning modules or loaders. Tests use JUnit 5 and live under `src/test`; common test fixtures are provided by the Broccolium and Tweakium core modules.

Minecraft client GameTests require a virtual display and an explicit timeout in headless environments:

```sh
timeout --foreground 180s xvfb-run --auto-servernum ./gradlew :testiarium-forge:runClientGameTest --no-daemon
timeout --foreground 180s xvfb-run --auto-servernum ./gradlew :testiarium-fabric:runClientGameTest --no-daemon
```

## Code conventions

- Write Kotlin using the official Kotlin style configured in `gradle.properties`: four-space indentation and trailing commas in multiline declarations.
- Preserve the existing `site.siredvin.<library>` package structure and use Kotlin `object` singletons for mod entrypoints and shared registries where established.
- Use the existing platform abstraction instead of importing Forge or Fabric classes into core code.
- Keep Fabric client-only initialization isolated from common/server code.
- Do not edit `src/generated` resources by hand; change the applicable data generator instead.
- Keep version changes centralized in `gradle.properties` or `gradle/libs.versions.toml`.
7 changes: 7 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Testiarium includes adaptations of these CC:Tweaked `mc-1.20.x` sources at
`6f16cd6b0e4b74afff5462d463bedba65764970e`, licensed under MPL-2.0:

- projects/common/src/testMod/kotlin/dan200/computercraft/gametest/api/ClientGameTest.kt
- projects/common/src/testMod/kotlin/dan200/computercraft/gametest/api/TestTags.kt
- projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/TestHooks.kt
- projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/TestReporters.kt
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ subprojectShaking {

val setupSubproject = subprojectShaking::setupSubproject
val broccoliumVersion: String by project.extra
val testiariumVersion: String by project.extra

subprojects {
setupSubproject(this)
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ org.gradle.daemon=false
minecraftVersion=1.21.1
# Mod Properties
broccoliumVersion = 1.4.6
testiariumVersion = 0.1.0
tweakiumVersion = 1.4.6
peripheraliumVersion = 1.4.6
projectGroup = site.siredvin
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ fabric-config = {module = "fuzs.forgeconfigapiport:forgeconfigapiport-fabric", v
fabric-junit = { module = "net.fabricmc:fabric-loader-junit", version.ref = "fabric-loader" }
cc-tweaked-fabric-api = {module = "cc.tweaked:cc-tweaked-1.21.1-fabric-api", version.ref = "cc-tweaked"}
cc-tweaked-fabric = {module = "cc.tweaked:cc-tweaked-1.21.1-fabric", version.ref = "cc-tweaked"}
modmenu = {module = "com.terraformersmc:modmenu", version.ref="modmenu"}
modmenu = {module = "maven.modrinth:modmenu", version.ref="modmenu"}
teamreborn-energy = {module = "teamreborn:energy", version.ref = "teamreborn-energy"}

# Forge mod dependencies
Expand Down
2 changes: 2 additions & 0 deletions openspec/changes/add-tweakium-peripheral-tests/.openspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-07-14
80 changes: 80 additions & 0 deletions openspec/changes/add-tweakium-peripheral-tests/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
## Context

Tweakium's Creative Filler is its concrete block peripheral, but its Lua-facing behavior is untested in a loaded Minecraft and CC:Tweaked environment. Testiarium supplies explicit GameTest registration, loader adapters, tags, structures, and JUnit XML reporting, but its optional CC:Tweaked adapter only verifies that the public API loads.

CC:Tweaked's testmod has 109 annotated tests across component, computer, CraftOS, disk, disk drive, inventory, modem, monitor, pocket computer, printer, printout, recipe, relay, speaker, turtle, and loot behavior. Its reusable framework comprises server/client runners, managed computers, Lua fixtures, typed assertions, fixture import/export, commands, mixins, and loader hooks. This change provides functional parity for those facilities, not a copy of CC:Tweaked's own 109 product behavior tests. Tweakium is the first consumer and validates the resulting Lua peripheral workflow.

Testiarium core is a complete CC:Tweaked-independent Minecraft GameTest engine. The optional `site.siredvin.testiarium.cct` package is a cohesive extension of that engine, not a minimal adapter or a consumer-local test utility. It carries every CC:Tweaked-dependent type and implementation required to write tests in the style of CC:Tweaked's own suite.

## Goals / Non-Goals

**Goals:**

- Run the same Creative Filler peripheral GameTests against Forge and Fabric 1.20.1.
- Provide reusable generic server and client GameTest helpers equivalent to CC:Tweaked's testmod facilities.
- Provide an optional CC:Tweaked harness for Kotlin computer actions, Lua execution, peripheral/component assertions, and testmod commands.
- Verify a fixture-provided computer can discover the Creative Filler and fill a compatible target storage from Lua.
- Cover invalid mode, missing target, incompatible target, and unknown resource errors as Lua failures.
- Produce loader-specific JUnit XML reports through Testiarium's normal GameTest runs.

**Non-Goals:**

- Test unrelated Tweakium modules, pocket or turtle upgrades, or every storage backend.
- Add Testiarium or CC:Tweaked as a published Tweakium runtime dependency.
- Generalize CC:Tweaked internals into Testiarium's base API or support arbitrary external computer implementations.
- Copy CC:Tweaked's product-specific test classes, registries, loot data, upgrades, or component behavior into Testiarium.

## Decisions

### Make Testiarium core the complete Minecraft GameTest engine

Core owns all functionality that can operate without CC:Tweaked: registration, tags, server lifecycle, reporting, fail-fast sequence behavior, world assertions, SNBT fixture workflow, import/export tooling, deterministic client execution, screenshots, and loader hooks. It exposes these features as consumer APIs rather than keeping them as Testiarium-internal test utilities.

Moving generic logic into the CC:Tweaked package is rejected because it would make ordinary Minecraft GameTest consumers depend on a CC:Tweaked installation.

### Add `site.siredvin.testiarium.cct` as the full CC:Tweaked testing package

The `site.siredvin.testiarium.cct` package extends core with every CC:Tweaked-dependent facility required by the upstream test style: managed computers, Kotlin computer actions, Lua test-file execution, completion reporting, component/peripheral assertions, CC fixture support, and testmod commands. The package may use CC:Tweaked internals because it is optional and version-specific; it will retain MPL-2.0 notices and provenance for adapted source.

Copying CC:Tweaked's own product test cases, registries, or fixture data is rejected. Directly calling peripheral methods with mocks is rejected because it does not validate the Lua contract.

### Port reusable server, fixture, and assertion facilities

Testiarium core will add fail-fast sequences and typed helpers for block entities, containers, entities, block state, items, and recipes. Its testmod tooling will load consumer SNBT fixtures, support import/export commands for test resources, and preserve compact fixtures by restoring omitted air blocks at load time. CC:Tweaked peripheral and computer-specific assertions live exclusively in `site.siredvin.testiarium.cct`.

Testiarium's testmod owns the required version-sensitive mixins and registers `/testiarium import`, `/testiarium export`, `/testiarium regen-structures`, and `/testiarium marker`, adapted from CC:Tweaked's `cctest` workflow. The generic commands import/export configured fixture resources and regenerate every registered structure. CCT-specific computer-file import/export and fixture computer creation live below `/testiarium cct`, preserving the core package's CC-free boundary.

Reimplementing each consumer's assertions and fixture handling is rejected because it would duplicate the same version-sensitive GameTest behavior across every testmod.

### Add an opt-in client GameTest runner

Testiarium will provide a client-only runner that creates a deterministic test world, executes registered client tests on the client thread, waits for rendering to stabilize, supports player/menu assertions and screenshots, writes JUnit XML, and terminates with the test result. Client hooks and mixins remain loader- and environment-isolated.

Making client behavior part of the normal dedicated-server test path is rejected because it would require client classes and rendering initialization on servers.

### Add isolated Tweakium testmod source sets and fixtures

Put shared GameTest cases, Lua test files, and SNBT structure fixtures in Tweakium testmod sources, with Forge and Fabric entrypoints that use Testiarium's loader adapters. Each fixture will place and label a computer alongside the Creative Filler, its network connection, and an inventory target. Loader builds will add Testiarium and the matching CC:Tweaked runtime only to testmod/GameTest configurations.

Reusing Testiarium's own adapter testmod was rejected because it only proves CC:Tweaked's public API is available, not Tweakium's peripheral behavior. Duplicating the framework setup was rejected because Testiarium already owns registration and reporting.

### Test the Creative Filler from Lua

The test will enqueue the labeled fixture computer and execute a Lua file that discovers the Creative Filler and calls its exposed method. Kotlin GameTest assertions will check the target inventory after Lua reports success. The Lua test will assert errors for invalid requests so failures surface through Testiarium's GameTest and JUnit reporting.

Direct unit tests of `FillerStrategy` were rejected because they bypass block exposure, loader storage lookup, and CC:Tweaked peripheral integration.

### Follow Testiarium's existing GameTest report contract

The new Forge and Fabric GameTest launch configurations will enable the Tweakium test namespace, set the shared structure and report paths, enable assertions, and write a JUnit XML report under each module's build directory. Testiarium core initializes generic lifecycle and fixture services; `site.siredvin.testiarium.cct` initializes computer and Lua services before tests run. Tweakium supplies named SNBT fixtures instead of relying on the empty template.

Custom reporting or Gradle test-task integration was rejected because the GameTest process and Testiarium reporter already expose CI-compatible results.

## Risks / Trade-offs

- [CC:Tweaked test internals change independently] -> Adapt only the harness components required by the consumer API, preserve MPL-2.0 provenance, and keep them isolated from Testiarium's base artifacts.
- [Client test runs are graphics-driver dependent] -> Use deterministic client setup and explicit render-idle checks; retain opt-in execution and screenshots as diagnostics.
- [Structure import/export is version-sensitive] -> Keep commands and mixins in testmod sources and validate compact SNBT fixtures on both loaders.
- [Fixture import or managed computers fail to become idle] -> Surface Lua completion and failures through the test API and make the GameTest wait for the managed computer result.
- [Test runtime dependencies leak into publication] -> Restrict Testiarium and CC:Tweaked dependencies to testmod configurations and verify normal production builds remain unchanged.
- [Structure fixtures are loader-sensitive] -> Use a shared SNBT fixture with only common block states and validate it on both loaders.
27 changes: 27 additions & 0 deletions openspec/changes/add-tweakium-peripheral-tests/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Why

Tweakium exposes ComputerCraft peripheral behavior but has no automated in-game coverage for it. Testiarium provides only part of CC:Tweaked's GameTest framework, so consumers cannot reproduce its computer, Lua, fixture, assertion, client-render, or testmod workflow coverage.

## What Changes

- Put the complete loader-neutral Minecraft GameTest engine in Testiarium core: registration, lifecycle, structures, assertions, fixtures, commands, client runner, screenshots, reporting, and Forge/Fabric runs.
- Add `site.siredvin.testiarium.cct` as Testiarium's optional CC:Tweaked package, with functional parity for CC:Tweaked computer, Lua, peripheral, component, and testmod features.
- Add a Tweakium testmod that uses the harness with a per-test SNBT structure containing the computer, Creative Filler, network, and target inventory.
- Exercise the Creative Filler from Lua, including successful item transfer and invalid-target failures.
- Configure the loader GameTest runs to include Tweakium, Testiarium, and the matching CC:Tweaked runtime and emit JUnit XML reports.

## Capabilities

### New Capabilities
- `tweakium-peripheral-gametesting`: Automated Forge and Fabric integration coverage for Tweakium ComputerCraft peripherals.
- `gametest-assertion-helpers`: Reusable GameTest sequencing and world-state assertions.
- `gametest-structure-tooling`: Consumer fixture loading, import, export, and compact structure support.
- `client-gametest-runner`: Opt-in deterministic client GameTest execution and screenshot assertions.

### Modified Capabilities

- `optional-cct-peripheral-testing`: Reusable CC:Tweaked computer and Lua GameTest support.

## Impact

Affected modules: Testiarium core, its `site.siredvin.testiarium.cct` optional package, loader integration, mixins, commands, and run configurations, plus `tweakium-core`, `tweakium-forge`, and `tweakium-fabric` testmods and Gradle configurations. The test-only runtime gains Testiarium and CC:Tweaked; published Tweakium APIs and runtime dependencies remain unchanged.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## ADDED Requirements

### Requirement: Opt-in client GameTest execution
Testiarium SHALL provide an opt-in Forge and Fabric client GameTest runner that initializes a deterministic test world, executes registered client tests on the client thread, writes JUnit XML results, and exits with a status that reflects test success or failure.

#### Scenario: Run client tests successfully
- **WHEN** a developer launches the configured client GameTest run
- **THEN** Testiarium executes the registered client tests and writes a passing JUnit XML report before exit

#### Scenario: Report a client test failure
- **WHEN** a client test assertion fails
- **THEN** the runner records the failure in JUnit XML and exits unsuccessfully

### Requirement: Client interaction and rendering assertions
The client runner SHALL provide client-thread actions, render-idle waiting, player reset and positioning, open-menu assertions, and screenshot capture for registered client tests. Client-only classes and hooks MUST NOT load on dedicated servers.

#### Scenario: Capture a stable screenshot
- **WHEN** a client test waits for rendering to become idle and requests a screenshot
- **THEN** Testiarium captures the rendered test state at the configured output location

#### Scenario: Start a dedicated server
- **WHEN** a dedicated server loads Testiarium
- **THEN** client runner classes and client-only mixins are not initialized
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## ADDED Requirements

### Requirement: Server GameTest sequence and assertion helpers
Testiarium SHALL provide reusable server-side GameTest sequence operations that fail the owning test for action errors and helpers to assert block state, block entities, containers, entities, item stacks, and recipe results within a fixture.

#### Scenario: Assert a fixture container
- **WHEN** a consumer asserts a fixture container's expected item stacks
- **THEN** a mismatch fails the GameTest with the fixture position and expected and actual contents

#### Scenario: Fail a sequence action
- **WHEN** a consumer sequence action throws an assertion or runtime error
- **THEN** the owning GameTest fails rather than crashing the server process

### Requirement: CC-free generic API
Generic assertion and sequence helpers SHALL NOT reference CC:Tweaked classes or internals.

#### Scenario: Use generic helpers without CC:Tweaked
- **WHEN** a testmod without CC:Tweaked uses Testiarium's generic assertion helpers
- **THEN** it compiles and runs without CC:Tweaked installed
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## ADDED Requirements

### Requirement: Consumer SNBT fixture workflow
Testiarium SHALL load consumer-provided named SNBT GameTest fixtures and provide test-only tooling to import fixture resources, export a fixture, and regenerate configured structures. Compact fixtures with omitted air blocks MUST load with their intended air volume restored.

The Testiarium testmod SHALL own the required version-sensitive mixins and register `/testiarium import`, `/testiarium export`, `/testiarium regen-structures`, and `/testiarium marker`. The import and export operations SHALL synchronize the configured consumer fixture source; `regen-structures` SHALL re-import and export every registered GameTest structure; and `marker` SHALL mark the nearest test fixture position.

#### Scenario: Load a compact named fixture
- **WHEN** a consumer GameTest names a compact SNBT fixture
- **THEN** the GameTest loads the fixture with omitted positions treated as air

#### Scenario: Export a fixture
- **WHEN** a developer invokes the configured fixture export operation for a named test area
- **THEN** Testiarium writes the fixture to the configured consumer structure source

### Requirement: Test-only fixture operations
Fixture commands and version-sensitive mixins SHALL be isolated to Testiarium testmod execution and MUST NOT affect normal mod runtime behavior.

#### Scenario: Run a normal production server
- **WHEN** a production server loads a mod that depends on Testiarium's published artifacts
- **THEN** test fixture commands and structure hooks are not registered
Loading
Loading