Skip to content
Closed
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
28 changes: 28 additions & 0 deletions .github/workflows/check_gradle_all.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ on:
pull_request:
types: [ opened, synchronize, reopened ]

permissions:
contents: read
checks: write

jobs:
check_gradle:
name: 🐘 Check Gradle
Expand All @@ -23,5 +27,29 @@ jobs:
- name: 🐘 Setup Gradle
uses: gradle/actions/setup-gradle@v3

- name: 💾 Cache paperweight
uses: actions/cache@v4
with:
path: '**/.gradle/caches/paperweight'
key: paperweight-${{ hashFiles('gradle/libs.versions.toml') }}
restore-keys: |
paperweight-

- name: 🐘 Gradle Check
run: CI=true ./gradlew check --scan

- name: 📊 Publish Test Report
if: always()
uses: mikepenz/action-junit-report@v4
with:
report_paths: '**/build/test-results/test/TEST-*.xml'
require_tests: false
check_name: 'JUnit Test Report'

- name: 🗃️ Upload Test Reports
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-reports
path: '**/build/reports/tests/test/'
retention-days: 7
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ bin/
.gradle
build
run
logs

temp

Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,23 @@ This monorepo will eventually contain all civ projects and development

### Plugins

### Tests
JUnit 5 tests live under `src/test/` in any plugin. They run via `useJUnitPlatform()`
(configured in [`plugins/build.gradle.kts`](plugins/build.gradle.kts)) and execute on
every PR through the [Gradle Check All](.github/workflows/check_gradle_all.yaml) workflow.

To run the suite locally:

```sh
./gradlew check # runs tests for every plugin
./gradlew :plugins:civmodcore-paper:test --rerun-tasks # one plugin
```

civmodcore-paper uses MockBukkit per https://docs.mockbukkit.org/docs/en/user_guide/advanced/paperweight,
which keeps paperweight on `compileOnly` so MockBukkit owns the test
classpath. Trade-off: NMS (`net.minecraft.*`) is not available at test
time, so anything that needs NMS has to live in production code only.

### Containers
A docker compose stack is provided to help test containers built from
this repo. To start the stack, run the following commands:
Expand Down
6 changes: 4 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[versions]
paper = "1.21.8-R0.1-SNAPSHOT"
junit = "5.8.2"
junit = "6.0.3"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

JUnit 5 (Jupiter) and JUnit Platform use different versioning schemes (e.g., Jupiter 5.10.3 and Platform 1.10.3). There is no version 6.0.3 for either, and using a single version reference for both will cause dependency resolution to fail. We should split them into separate version properties.

Suggested change
junit = "6.0.3"
junit-jupiter = "5.10.3"
junit-platform = "1.10.3"

nuotifier = "2.7.2"
velocity = "3.4.0-SNAPSHOT"
configurate = "4.2.0"
Expand Down Expand Up @@ -45,6 +45,8 @@ jsoup = { group = "org.jsoup", name = "jsoup", version = "1.18.3" }

junit-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit" }
junit-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit" }
junit-platform-launcher = { group = "org.junit.platform", name = "junit-platform-launcher", version.ref = "junit" }
mockbukkit = { group = "org.mockbukkit.mockbukkit", name = "mockbukkit-v1.21", version = "4.93.0" }
Comment on lines 46 to +49

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Update the JUnit dependency definitions to use the split version references (junit-jupiter and junit-platform) to avoid resolution errors.

Suggested change
junit-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit" }
junit-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit" }
junit-platform-launcher = { group = "org.junit.platform", name = "junit-platform-launcher", version.ref = "junit" }
mockbukkit = { group = "org.mockbukkit.mockbukkit", name = "mockbukkit-v1.21", version = "4.93.0" }
junit-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit-jupiter" }
junit-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit-jupiter" }
junit-platform-launcher = { group = "org.junit.platform", name = "junit-platform-launcher", version.ref = "junit-platform" }
mockbukkit = { group = "org.mockbukkit.mockbukkit", name = "mockbukkit-v1.21", version = "4.93.0" }


slf4j-api = { group = "org.slf4j", name = "slf4j-api", version = "2.0.17" }

Expand All @@ -54,7 +56,7 @@ discordsrv-paper = { group = "com.discordsrv", name = "discordsrv", version = "1
jda = { group = "net.dv8tion", name = "JDA", version = "6.2.1"}

[bundles]
junit = ["junit-api", "junit-engine"]
junit = ["junit-api", "junit-engine", "junit-platform-launcher"]
nuvotifier = ["nuvotifier-api", "nuvotifier-bukkit"]
evenmorefish = ["evenmorefish-api", "evenmorefish-paper"]
discordsrv = ["discordsrv-paper", "jda"]
Expand Down
4 changes: 4 additions & 0 deletions plugins/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ subprojects {
enabled = false
}

tasks.withType<Test> {
useJUnitPlatform()
}

configure<PublishingExtension> {
val githubActor = System.getenv("GITHUB_ACTOR")
val githubToken = System.getenv("GITHUB_TOKEN")
Expand Down
7 changes: 7 additions & 0 deletions plugins/civmodcore-paper/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,11 @@ dependencies {
compileOnly(libs.fastutil)

testImplementation(libs.bundles.junit)
testImplementation(libs.mockbukkit)
testImplementation("io.papermc.paper:paper-api:${libs.versions.paper.get()}")
}

// https://docs.mockbukkit.org/docs/en/user_guide/advanced/paperweight
paperweight {
addServerDependencyTo = configurations.named(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME).map { setOf(it) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,104 +4,63 @@
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockbukkit.mockbukkit.MockBukkit;
import vg.civcraft.mc.civmodcore.chat.ChatUtils;
import vg.civcraft.mc.civmodcore.inventory.items.ItemUtils;

public class ItemMetaTests {

private static final ItemStack TEMPLATE_ITEM = new ItemStack(Material.STICK);
private ItemStack templateItem;

// TODO: Who knows.
// /**
// * Tests whether a basic string display name can match with a component.
// */
// @Test
// public void testBasicDisplayNameEquality() {
// // Setup
// final var formerItem = NullUtils.isNotNull(NBTSerialization.processItem(TEMPLATE_ITEM, (nbt) -> {
// final var display = new NBTCompound();
// display.setString("Name", "Hello!");
// nbt.setCompound("display-name", display);
// }));
// final var latterItem = TEMPLATE_ITEM.clone();
// ItemUtils.setComponentDisplayName(latterItem, Component.text("Hello!"));
// // Check
// System.out.println(formerItem);
// System.out.println(latterItem);
// Assertions.assertTrue(ChatUtils.areComponentsEqual(
// ItemUtils.getComponentDisplayName(formerItem),
// ItemUtils.getComponentDisplayName(latterItem)));
// }
@BeforeEach
public void setUp() {
MockBukkit.mock();
templateItem = new ItemStack(Material.STICK);
}

// TODO: Who knows.
// /**
// * Tests whether a json primitive display name can match with a component.
// */
// @Test
// public void testBasicJsonPrimitiveDisplayNameEquality() {
// // Setup
// final var formerItem = NullUtils.isNotNull(NBTSerialization.processItem(TEMPLATE_ITEM, (nbt) -> {
// final var display = new NBTCompound();
// display.setString("Name", "\"Hello!\"");
// nbt.setCompound("display", display);
// }));
// final var latterItem = TEMPLATE_ITEM.clone();
// ItemUtils.handleItemMeta(latterItem, (ItemMeta meta) -> {
// meta.displayName(Component.text("Hello!"));
// return true;
// });
// // Check
// System.out.println(formerItem);
// System.out.println(latterItem);
// Assertions.assertTrue(ChatUtils.areComponentsEqual(
// ItemUtils.getComponentDisplayName(formerItem),
// ItemUtils.getComponentDisplayName(latterItem)));
// }
@AfterEach
public void tearDown() {
MockBukkit.unmock();
}

/**
* How do different API methods of setting the display name fare?
*/
@Test
@SuppressWarnings("deprecation")
public void testAdvancedDisplayNameEquality() {
// Setup
final var formerItem = TEMPLATE_ITEM.clone();
final var formerItem = templateItem.clone();
ItemUtils.handleItemMeta(formerItem, (ItemMeta meta) -> {
meta.setDisplayName("Hello!");
return true;
});
final var latterItem = TEMPLATE_ITEM.clone();
final var latterItem = templateItem.clone();
ItemUtils.handleItemMeta(latterItem, (ItemMeta meta) -> {
meta.displayName(Component.text("Hello!"));
return true;
});
// Check
Assertions.assertTrue(ChatUtils.areComponentsEqual(
ItemUtils.getComponentDisplayName(formerItem),
ItemUtils.getComponentDisplayName(latterItem)));
Assertions.assertTrue(ItemUtils.areItemsSimilar(formerItem, latterItem));
}

/**
* Tests whether {@link ChatUtils#isBaseComponent(Component)} works.
*/
@Test
@Disabled("Paper's switch to native Component display names removed the legacy/Adventure split this assertion relied on")
@SuppressWarnings("deprecation")
public void testBaseComponent() {
// Setup
final var formerItem = TEMPLATE_ITEM.clone();
final var formerItem = templateItem.clone();
ItemUtils.handleItemMeta(formerItem, (ItemMeta meta) -> {
meta.setDisplayName("Hello!");
return true;
});
final var latterItem = TEMPLATE_ITEM.clone();
final var latterItem = templateItem.clone();
ItemUtils.handleItemMeta(latterItem, (ItemMeta meta) -> {
meta.displayName(Component.text("Hello!"));
return true;
});
// Check
Assertions.assertTrue(ChatUtils.isBaseComponent(
ItemUtils.getComponentDisplayName(formerItem)));
Assertions.assertFalse(ChatUtils.isBaseComponent(
Expand Down

This file was deleted.

9 changes: 9 additions & 0 deletions plugins/exilepearl-paper/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,13 @@ dependencies {
compileOnly(project(":plugins:randomspawn-paper"))

compileOnly(files("../../ansible/src/paper-plugins/BreweryX-3.6.0.jar"))

testImplementation(libs.bundles.junit)
testImplementation(project(":plugins:civmodcore-paper"))
testImplementation(project(":plugins:combattagplus-paper"))
testImplementation("org.mockito:mockito-core:5.11.0")
}

tasks.test {
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ private List<String> generateLoreInternal(ExilePearl pearl, int health, boolean
lore.add(parse(""));

lore.add(parse("<a>Health: <n>%s/%s", health, config.getPearlHealthMaxValue()));
String unit = config.getPearlHealthDecayHumanInterval();
int decayPerHumanInterval = PearlDecayMath.decayPerHumanInterval(
config.getPearlHealthDecayHumanIntervalMin(),
config.getPearlHealthDecayIntervalMin(),
config.getPearlHealthDecayAmount());
int intervalsRemaining = PearlDecayMath.intervalsRemaining(health, decayPerHumanInterval);
if (intervalsRemaining > 0 && pearl.isActive()) {
lore.add(parse("<a>Time remaining: <n>%d %s", intervalsRemaining, unit));
}
Set<RepairMaterial> repair = config.getRepairMaterials(pearl.getPearlType());
if (repair != null) {
for (RepairMaterial rep : repair) {
Expand All @@ -92,9 +101,8 @@ private List<String> generateLoreInternal(ExilePearl pearl, int health, boolean
if (rep.getStack().hasItemMeta() && rep.getStack().getItemMeta().hasDisplayName()) {
item = rep.getStack().getItemMeta().getDisplayName();
}
int damagesPerHumanInterval = (config.getPearlHealthDecayHumanIntervalMin() / config.getPearlHealthDecayIntervalMin()) * config.getPearlHealthDecayAmount(); // intervals in a human interval * damage per
int repairsPerHumanInterval = (int) Math.ceil(damagesPerHumanInterval / amountPerItem);
lore.add(parse("<a>Cost per %s using %s:<n> %s", config.getPearlHealthDecayHumanInterval(), item, Integer.toString(repairsPerHumanInterval)));
int repairsPerHumanInterval = (int) Math.ceil(decayPerHumanInterval / amountPerItem);
lore.add(parse("<a>Cost per %s using %s:<n> %s", unit, item, Integer.toString(repairsPerHumanInterval)));
}
}

Expand Down
Loading
Loading