Skip to content

[Tests] Add unit tests for PlayerManager, ChatResponseManager, ChatResponse, LocalizationManager#37

Open
DiamondDagger590 wants to merge 1 commit into
developfrom
claude/stoic-cori-r6n70t
Open

[Tests] Add unit tests for PlayerManager, ChatResponseManager, ChatResponse, LocalizationManager#37
DiamondDagger590 wants to merge 1 commit into
developfrom
claude/stoic-cori-r6n70t

Conversation

@DiamondDagger590

@DiamondDagger590 DiamondDagger590 commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • PlayerManagerTest: Tests addPlayer(), removePlayer(), hasCorePlayer(), getPlayer(), isPlayerLocked() (locked/unlocked/missing), getAllPlayers() (defensive copy), getAllBukkitPlayers() (present/absent Bukkit player), and UUID replacement behavior (0% → 100% line coverage, 16/16 lines)
  • ChatResponseManagerTest: Tests doesChatterHavePendingResponse(), getPendingResponse(), addPendingResponse() with existing response expiry, removePendingResponse() by UUID and by ChatResponse instance (identity-based matching), multi-UUID isolation, and no-op removal safety (0% → 100% line coverage, 20/20 lines)
  • ChatResponseTest: Tests getChatterUUID() accessor, getResponseWaitTime() delegation, onExpire() callback, and UUID distinctness across instances (0% → 100% line coverage, 4/4 lines)
  • ChatResponseExpireTask: Covered transitively through ChatResponseManager tests — constructor and cancelTask() paths exercised (0% → 33.3% line coverage, 4/12 lines)
  • LocalizationManagerTest: Tests all getLocalizedMessage() overloads (Route, CorePlayer+Route, Audience+Route, with placeholders), all getLocalizedMessages() list overloads, all getLocalizedMessageAsComponent() and getLocalizedMessageAsComponents() overloads, doesAnyLocaleContainRoute(), getLocalizedSection() (player and route-only), registerLanguageFile() (single and multiple docs per locale), getLocaleChain() (client locale priority, no Bukkit player fallback), postProcessResolvedString() hook, locale chain fallback behavior, duplicate locale skipping, and NoLocalizationContainsMessageException for missing routes (0% → 90.3% line coverage, 168/186 lines; remaining 10% are broadcastMessage() which requires Bukkit.getOnlinePlayers() and Bukkit.getConsoleSender() static calls)

Infrastructure change

Added Mockito 5.14.2 as a testImplementation dependency to enable mocking CorePlugin, Bukkit scheduler, YamlDocument, Player, and other framework types.

Classes covered (avoiding PR #27#36 overlap)

PR #27 covers GetItemRequest, StatisticEntry, ReloadableContent, ReloadableContentManager, StartupProfile. PR #28 covers Methods, PlayerSettingRegistry, ReloadableContent subtypes. PR #29 covers Mutexable, ParseError, EvaluationException, exception classes. PR #30 covers RegistryAccess, StatisticModifyEvent, PostStatisticModifyEvent, Transaction. PR #31 covers database events, GUI events, SQLiteDatabaseDriver, DatabaseDriver, ManagerKey/PluginHookKey constants. PR #32 covers player events, CorePlayer, Credentials, ConnectionDetails, CorePlayerOfflineException. PR #33 covers PlayerStatisticData, ReloadableParser, ItemPluginType, ChainPlayerContextFilter. PR #34 covers BatchTransaction, FailSafeTransaction, ItemBuilderConfigurationKeys, RegistryKeyImpl. PR #35 covers BootstrapContext, IllegalSlotAssignmentException, TableVersionHistoryDAO, MutexDAO. PR #36 covers PlayerSettingDAO, GuiManager, GetItemResponseState, exception classes. This PR targets entirely different classes with no overlap.

Coverage impact

4 classes brought from 0% to 100%, 1 brought from 0% to 90.3%, 1 improved from 0% to 33.3%. Overall project coverage: 31.9% → 38.5% (+6.6pp, 268 new lines covered).

Test plan

  • All 700 tests pass via ./gradlew test
  • JaCoCo coverage report confirms expected coverage on all targeted classes
  • No existing tests broken by these additions
  • No production code changes — test-only PR (plus Mockito dependency addition)

https://claude.ai/code/session_01VdgvpNjKTBC7y2EPrn3bi5


Generated by Claude Code

Summary by CodeRabbit

  • Tests
    • Added comprehensive unit test suites for core functionality including chat response management, localization handling, and player management.
    • Enhanced testing framework by integrating Mockito for improved mock object support in unit tests.
    • Introduced test helper classes and fixtures to ensure thorough validation of core component behavior and interactions.

…LocalizationManager

- PlayerManager: 0% → 100% (16/16 lines) — add/remove/get/lock/getAllPlayers/getAllBukkitPlayers
- ChatResponseManager: 0% → 100% (20/20 lines) — pending response lifecycle, replacement expiry
- ChatResponse: 0% → 100% (4/4 lines) — UUID accessor and abstract contract
- ChatResponseExpireTask: 0% → 33.3% (4/12 lines, covered transitively)
- LocalizationManager: 0% → 90.3% (168/186 lines) — locale chain resolution, fallback,
  string/list/section/component variants, placeholders, postProcessResolvedString hook,
  audience resolution via PlayerManager
- Added Mockito 5.14.2 as testImplementation dependency

Overall project coverage: 31.9% → 38.5% (+6.6pp, 268 new lines covered)

https://claude.ai/code/session_01VdgvpNjKTBC7y2EPrn3bi5
@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds Mockito as a test dependency in build.gradle.kts and introduces four new JUnit 5 test classes: ChatResponseTest, ChatResponseManagerTest, PlayerManagerTest, and LocalizationManagerTest. Each test file uses inner test-double subclasses and Mockito mocks to exercise the respective manager's behavior end-to-end.

Changes

Unit Test Coverage

Layer / File(s) Summary
Mockito test dependency
build.gradle.kts
Adds mockitoVersion and testImplementation("org.mockito:mockito-core:$mockitoVersion") to the build.
ChatResponse and ChatResponseManager tests
src/test/java/com/diamonddagger590/mccore/chat/ChatResponseTest.java, src/test/java/com/diamonddagger590/mccore/chat/ChatResponseManagerTest.java
ChatResponseTest verifies UUID retrieval, wait-time, expiration, and instance distinctness via a TestChatResponse subclass. ChatResponseManagerTest uses Mockito static mocking of Bukkit scheduler/server to cover pending-response checks, Optional retrieval, replacement/expiry semantics, and removal by UUID or instance.
PlayerManager tests
src/test/java/com/diamonddagger590/mccore/player/PlayerManagerTest.java
Verifies add/replace-by-UUID, hasCorePlayer, getPlayer, removePlayer, isPlayerLocked, getAllPlayers (including defensive-copy), and getAllBukkitPlayers using a TestCorePlayer stub controlling lock state and optional Bukkit player.
LocalizationManager tests
src/test/java/com/diamonddagger590/mccore/localization/LocalizationManagerTest.java
Covers locale file registration, string/list/component resolution by route/player/audience, placeholder substitution, doesAnyLocaleContainRoute, getLocalizedSection, post-processing, locale-chain ordering (client-locale priority), and unsupported-locale fallback using TestCorePlayer and TestLocalizationManager doubles.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.96% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding comprehensive unit tests for four core classes (PlayerManager, ChatResponseManager, ChatResponse, and LocalizationManager), which is clearly the primary focus of the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/stoic-cori-r6n70t

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown

Testing Review

I'll systematically apply every checklist item to the diff.


Checklist Evaluation

Coverage Completeness

The diff adds three test files covering ChatResponseManager, ChatResponse, and PlayerManager, plus a LocalizationManager test. I need to verify coverage of all non-trivial public methods and edge cases.

ChatResponseManager — The expiry timer logic (the BukkitTask runnable that ticks through pending responses and calls onExpire() when time has elapsed) is never exercised. addPendingResponse schedules a timer; no test advances time and verifies that the timer callback actually expires responses.

LocalizationManagergetLocalizedMessage(Audience, Route, Map) with a stored CorePlayer whose Bukkit player has a locale not covered by any registered doc is not tested (i.e., the audience-path fallback through the full locale chain for a known player). More importantly, the getLocalizedMessages overloads with placeholders (Map variants for Audience and CorePlayer) have no tests at all.

PlayerManagergetPlayer(Player) (the Bukkit Player overload, if present) and any PlayerManager method that interacts with events or lifecycle hooks are not covered. This is minor if those overloads don't exist in the production class, but worth confirming.

ChatResponseTestonResponse is called in TestChatResponse.onResponse() but no test calls response.onResponse(event) and then asserts getLastEvent(). The infrastructure to verify onResponse dispatch is built but unused.

TimeProvider Usage

ChatResponseManagerTest.setUp() correctly mocks TimeProvider and injects a fixed Instant. However, the timer runnable itself is never invoked in any test, so the TimeProvider mock is set up but never meaningfully exercised. The expiry path that reads timeProvider.now() is untested.

No test modifies global TimeProvider state, so no @AfterEach reset is needed — that is fine.

MockBukkit Usage

ChatResponseManagerTest uses mockStatic(Bukkit.class) for Bukkit.getScheduler() and Bukkit.getServer(). MockBukkit is not used. That is structurally acceptable per the McCore framework rules (no MockBukkit.mock() / unmock() calls needed when Mockito static mocking suffices). The static mock is closed in @AfterEach, so no leak.

However: mockStatic on Bukkit is a broad, fragile approach. ChatResponseManagerTest calls zero real Bukkit APIs — it is purely testing a Java map with scheduler interaction. The Bukkit.getServer() mock stub is set up but never asserted against. This is overhead that obscures what is actually being tested.

Bukkit-Dependent vs. Pure-Java Separation

LocalizationManagerTest mocks Player.locale() (a Bukkit API call) to drive locale resolution. PlayerManagerTest mocks Player for getAllBukkitPlayers. Both tests do not set up MockBukkit — they use Mockito mocks of Bukkit classes. This is the correct pattern per the rules.

ChatResponseManagerTest sets up Bukkit static mocking but the tests exercise zero Bukkit behavior (the scheduler task is stubbed to return a task ID but the runnable is never run). The Bukkit dependency is purely incidental setup noise for the constructor — but this is a structural issue, not a style preference. The expiry logic mixing pure-map operations with Bukkit scheduler calls means the non-trivial logic path (timer tick → expiry) is entirely untested.

Framework Test Quality

removePendingResponse_byUUID_noErrorWhenNoPending and removePendingResponse_byChatResponse_noErrorWhenNoPending have no assertions — they only verify no exception is thrown. This is an implicit "does not throw" check, but there is no explicit assertDoesNotThrow wrapper, making the test's intent invisible to the reader and technically assertion-free per the checklist rule.

ChatResponseTest.onExpire_tracksExpiration uses assertEquals(true, response.isExpired()) — this should be assertTrue, but that is a style note, not a structural one.

All test methods have @DisplayName annotations. ✓

Naming convention (givenContext_whenAction_thenOutcome) is inconsistently followed in ChatResponseManagerTest — several methods use methodName_returnsX_whenY ordering. This is a naming structural issue.

Shared Fixtures

RegistryResetExtension is referenced in LocalizationManagerTest (imported from com.diamonddagger590.mccore.testing) but is not shown in the diff. If it lives in src/test/java/ rather than src/testFixtures/java/, it cannot be consumed by downstream repos (McRPG). This needs verification.


Findings

CONCERN: Timer expiry logic in ChatResponseManager is completely untested — the Runnable passed to scheduler.runTaskTimer is never captured and invoked.
WHY: The core behavioral contract of ChatResponseManager is that pending responses expire after getResponseWaitTime() seconds. No test advances the mock clock (via TimeProvider) and triggers the scheduled runnable, so onExpire() being called by the timer is never verified. This is the only non-trivial logic in the class and it has zero coverage.
WHERE: ChatResponseManagerTest / ChatResponseManager (production)


CONCERN: Two test methods have no assertions and no assertDoesNotThrow.
WHY: removePendingResponse_byUUID_noErrorWhenNoPending and removePendingResponse_byChatResponse_noErrorWhenNoPending contain only a method call with no assertion. A test with no assertion cannot fail on incorrect behavior — it passes even if the method throws a swallowed exception or corrupts internal state silently.
WHERE: ChatResponseManagerTest.removePendingResponse_byUUID_noErrorWhenNoPending / ChatResponseManagerTest.removePendingResponse_byChatResponse_noErrorWhenNoPending


CONCERN: onResponse dispatch is never asserted in ChatResponseTest despite the test infrastructure being present.
WHY: TestChatResponse stores lastEvent from onResponse(PlayerChatEvent) and exposes getLastEvent(), but no test method calls response.onResponse(mockEvent) and then asserts getLastEvent() equals the event. The dispatch contract of the abstract method is unverified.
WHERE: ChatResponseTest / ChatResponse.onResponse


CONCERN: getLocalizedMessages overloads with placeholder substitution (Map variants for CorePlayer and Audience) have no tests.
WHY: LocalizationManagerTest covers getLocalizedMessages(Route), getLocalizedMessages(player, Route), and getLocalizedMessages(Audience, Route) but omits the corresponding Map<String,String> overloads for player and audience. Placeholder substitution on list messages is only tested for the no-audience path.
WHERE: LocalizationManagerTest / LocalizationManager.getLocalizedMessages(CorePlayer, Route, Map) and LocalizationManager.getLocalizedMessages(Audience, Route, Map)


CONCERN: RegistryResetExtension is used but not shown in src/testFixtures/java/ — if it resides in src/test/java/, downstream consumers cannot use it.
WHY: LocalizationManagerTest imports com.diamonddagger590.mccore.testing.RegistryResetExtension. Shared test infrastructure must live in src/testFixtures/java/ to be available to dependent projects (e.g., McRPG). If it is in src/test/java/, it is invisible to consumers.
WHERE: LocalizationManagerTest (import) / src/testFixtures/java/com/diamonddagger590/mccore/testing/RegistryResetExtension.java (expected location)


CONCERN: ChatResponseManagerTest sets up Bukkit.getServer() mock but never uses it, and the static Bukkit mock covers the entire Bukkit class for every test method even though only getScheduler() is needed at construction.
WHY: Unnecessarily broad static mocking makes tests fragile — any production code path that calls an unstubbed Bukkit static method will return null silently. The mock should be scoped to only Bukkit::getScheduler. Additionally, Bukkit.getServer() being stubbed but never called is dead setup that misleads readers about what the tests exercise.
WHERE: ChatResponseManagerTest.setUp() / ChatResponseManager constructor


CONCERN: Test method names in ChatResponseManagerTest do not follow givenContext_whenAction_thenOutcome — they use methodName_outcome_condition ordering.
WHY: The required convention is givenContext_whenAction_thenOutcome. Methods like doesChatterHavePendingResponse_returnsFalse_whenNoPending invert the when/then ordering and omit the given prefix, violating the structural naming rule across the entire file.
WHERE: ChatResponseManagerTest (all test method names)


Summary

Production files changed: build.gradle.kts, ChatResponseManager (indirectly — new tests expose its behavior), LocalizationManager (indirectly), PlayerManager (indirectly)

Test files present: ChatResponseManagerTest.java, ChatResponseTest.java, LocalizationManagerTest.java, PlayerManagerTest.java

Coverage gaps:

  • Timer expiry runnable in ChatResponseManager (critical — untested entirely)
  • ChatResponse.onResponse dispatch (infrastructure built, never asserted)
  • getLocalizedMessages(CorePlayer, Route, Map) and getLocalizedMessages(Audience, Route, Map) overloads
  • Two assertion-free test methods that cannot detect regressions
  • RegistryResetExtension fixture placement unverified for testFixtures scope

@github-actions

Copy link
Copy Markdown

Security Review

No security concerns found.

The diff contains exclusively test infrastructure: new JUnit/Mockito test classes for ChatResponseManager, ChatResponse, LocalizationManager, and PlayerManager, plus a Mockito dependency addition in build.gradle.kts. No production source files are modified.

Checklist sweep:

  • SQL Injection in DAO Methods — No DAO code added or modified.
  • DDL Injection in UpdateTableFunction — No UpdateTableFunction implementations added or modified.
  • MiniMessage InjectionLocalizationManagerTest calls when(mockPlugin.getMiniMessage()).thenReturn(MiniMessage.miniMessage()) and the test messages ("Hello world", "Hi <name>", etc.) are all string literals defined in the test itself — no player-supplied input reaches deserialize().
  • ChatResponse / ChatResponseManager Safety — The TestChatResponse stubs in both test files have no-op onResponse() bodies and never pass chat content to MiniMessage or command execution; chat content is not consumed in a security-sensitive way.
  • onClick() Return Value Safety — No Slot.onClick() implementations present.
  • Framework Permission Gating — No new framework operations affecting player state are introduced.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@build.gradle.kts`:
- Around line 68-69: Update the mockitoVersion variable in build.gradle.kts from
"5.14.2" to "5.23.0" to address known issues with the current version including
initialization failures with inline Byte Buddy mock maker on Java 17+ and
superclass constructor mocking problems. The mockitoVersion variable on line 68
should be changed to the new version string, which will automatically apply to
the testImplementation dependency on line 69 that uses this variable.

In `@src/test/java/com/diamonddagger590/mccore/chat/ChatResponseManagerTest.java`:
- Around line 65-85: Replace the Mockito mocking approach in the setUp() method
with MockBukkit. Remove the mockStatic(Bukkit.class) call and the manual Mockito
mocks for BukkitScheduler and Server. Instead, call MockBukkit.mock() at the
beginning of setUp() to initialize the MockBukkit environment, which will
provide real implementations like ServerMock that integrate properly with Bukkit
singletons. Update the lines that were creating BukkitScheduler and Server mocks
to instead retrieve them from the MockBukkit environment (e.g., using
MockBukkit.getSchedulerMock() or similar accessor methods from the MockBukkit
API). Additionally, add a new `@AfterEach` method that calls MockBukkit.unmock()
to properly clean up the MockBukkit state after each test.

In `@src/test/java/com/diamonddagger590/mccore/chat/ChatResponseTest.java`:
- Around line 73-79: In the onExpire_tracksExpiration() test method, replace the
assertEquals(true, response.isExpired()) assertion with the more idiomatic
assertTrue(response.isExpired()). This provides clearer intent and is the
preferred pattern for testing boolean conditions in JUnit tests.

In
`@src/test/java/com/diamonddagger590/mccore/localization/LocalizationManagerTest.java`:
- Around line 135-140: Replace all instances of `mock(Player.class)` with
MockBukkit's `PlayerMock` implementation throughout the test file, including in
the createPlayerWithLocale method and at all other locations mentioned (lines
318, 341, 359, 428, etc.). When creating PlayerMock instances, use MockBukkit's
API to set the locale instead of Mockito's when() syntax, following the coding
guideline to use real MockBukkit implementations rather than Mockito mocks for
Bukkit classes where MockBukkit provides an implementation.

In `@src/test/java/com/diamonddagger590/mccore/player/PlayerManagerTest.java`:
- Around line 161-173: The test method
`getAllBukkitPlayers_returnsEmpty_whenNoBukkitPlayers` uses Mockito's `mock()`
to create test instances, but per coding guidelines, MockBukkit's real
implementations should be used instead of Mockito mocks for Bukkit classes.
Replace the Mockito mock approach with MockBukkit's PlayerMock when creating any
Bukkit Player instances in this test to ensure consistency with the codebase
standards.
- Around line 145-159: In the
getAllBukkitPlayers_returnsBukkitPlayers_whenPresent method, replace the Mockito
mock(Player.class) with MockBukkit's PlayerMock implementation. Instead of
creating a mocked Player object, instantiate a new PlayerMock object to ensure
consistency with the framework's test patterns and coding guidelines that
require using MockBukkit's real implementations for Bukkit classes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6bab201b-765d-47b6-9826-ada7759e4995

📥 Commits

Reviewing files that changed from the base of the PR and between 6a8d9ea and 646bb2d.

📒 Files selected for processing (5)
  • build.gradle.kts
  • src/test/java/com/diamonddagger590/mccore/chat/ChatResponseManagerTest.java
  • src/test/java/com/diamonddagger590/mccore/chat/ChatResponseTest.java
  • src/test/java/com/diamonddagger590/mccore/localization/LocalizationManagerTest.java
  • src/test/java/com/diamonddagger590/mccore/player/PlayerManagerTest.java

Comment thread build.gradle.kts
Comment on lines +68 to +69
val mockitoVersion = "5.14.2"
testImplementation("org.mockito:mockito-core:$mockitoVersion")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

What is the latest stable version of Mockito and are there any known issues with version 5.14.2?

💡 Result:

As of June 14, 2026, the latest stable version of Mockito is 5.23.0 [1][2]. Regarding version 5.14.2, there are several known issues and reported behaviors: * Initialization Failures: Users have reported issues initializing the inline Byte Buddy mock maker in certain environments (e.g., Java 17), often resulting in a MockitoInitializationException [3]. This is frequently related to outdated Byte Buddy versions or agent attachment mechanisms in newer JDKs [3]. * Superclass Constructor Mocking: There have been reports that mocking the construction of a superclass does not behave as expected in version 5.14.2 compared to earlier versions [4]. * Self-Attaching Warnings: Users may encounter warnings regarding Mockito self-attaching to enable the inline mock maker [5]. While this is a known behavior of the inline mock maker, it has prompted discussions about better configuration practices to avoid build failures in future JDK releases [5]. * Initial Release Delay: Shortly after its initial tagging, there was a temporary issue where version 5.14.2 was not correctly published to the Maven Central repository, which was subsequently resolved [6][7]. Given that 5.14.2 was released in October 2024 [1][6], it is highly recommended to upgrade to the latest stable release (5.23.0) to benefit from numerous bug fixes, improvements, and compatibility updates [8][9].

Citations:


Update Mockito to version 5.23.0 from 5.14.2.

Version 5.14.2 is outdated and has known issues including initialization failures with the inline Byte Buddy mock maker (particularly on Java 17+), superclass constructor mocking problems, and self-attaching warnings. The latest stable release 5.23.0 includes bug fixes and compatibility improvements.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build.gradle.kts` around lines 68 - 69, Update the mockitoVersion variable in
build.gradle.kts from "5.14.2" to "5.23.0" to address known issues with the
current version including initialization failures with inline Byte Buddy mock
maker on Java 17+ and superclass constructor mocking problems. The
mockitoVersion variable on line 68 should be changed to the new version string,
which will automatically apply to the testImplementation dependency on line 69
that uses this variable.

Comment on lines +65 to +85
@BeforeEach
void setUp() {
mockPlugin = mock(CorePlugin.class);
TimeProvider timeProvider = mock(TimeProvider.class);
when(timeProvider.now()).thenReturn(Instant.ofEpochMilli(1000));
when(mockPlugin.getTimeProvider()).thenReturn(timeProvider);

BukkitScheduler scheduler = mock(BukkitScheduler.class);
BukkitTask task = mock(BukkitTask.class);
when(task.getTaskId()).thenReturn(1);
when(scheduler.runTaskTimer(any(), any(Runnable.class), anyLong(), anyLong())).thenReturn(task);
when(scheduler.runTask(any(), any(Runnable.class))).thenReturn(task);

bukkitMock = mockStatic(Bukkit.class);
bukkitMock.when(Bukkit::getScheduler).thenReturn(scheduler);

Server server = mock(Server.class);
bukkitMock.when(Bukkit::getServer).thenReturn(server);

manager = new ChatResponseManager(mockPlugin);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚖️ Poor tradeoff

Consider using MockBukkit instead of Mockito for Bukkit classes.

The test mocks BukkitScheduler (line 72) and Server (line 81) using Mockito, and uses mockStatic for the Bukkit singleton. As per coding guidelines, MockBukkit provides real implementations (e.g., ServerMock) that should be preferred over Mockito mocks. Consider using MockBukkit.mock() in @BeforeEach and MockBukkit.unmock() in @AfterEach instead of static mocking.

As per coding guidelines: "Do not use Mockito to mock a Bukkit class where MockBukkit already provides a real implementation (e.g., PlayerMock, ServerMock) — use the real MockBukkit implementation instead".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/com/diamonddagger590/mccore/chat/ChatResponseManagerTest.java`
around lines 65 - 85, Replace the Mockito mocking approach in the setUp() method
with MockBukkit. Remove the mockStatic(Bukkit.class) call and the manual Mockito
mocks for BukkitScheduler and Server. Instead, call MockBukkit.mock() at the
beginning of setUp() to initialize the MockBukkit environment, which will
provide real implementations like ServerMock that integrate properly with Bukkit
singletons. Update the lines that were creating BukkitScheduler and Server mocks
to instead retrieve them from the MockBukkit environment (e.g., using
MockBukkit.getSchedulerMock() or similar accessor methods from the MockBukkit
API). Additionally, add a new `@AfterEach` method that calls MockBukkit.unmock()
to properly clean up the MockBukkit state after each test.

Source: Coding guidelines

Comment on lines +73 to +79
@Test
@DisplayName("Given a response, when onExpire called, then expiration is tracked")
void onExpire_tracksExpiration() {
TestChatResponse response = new TestChatResponse(UUID.randomUUID(), 30);
response.onExpire();
assertEquals(true, response.isExpired());
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Prefer assertTrue over assertEquals(true, ...).

Line 78 uses assertEquals(true, response.isExpired()) which is less idiomatic than assertTrue(response.isExpired()).

♻️ Suggested improvement
-        assertEquals(true, response.isExpired());
+        assertTrue(response.isExpired());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/com/diamonddagger590/mccore/chat/ChatResponseTest.java` around
lines 73 - 79, In the onExpire_tracksExpiration() test method, replace the
assertEquals(true, response.isExpired()) assertion with the more idiomatic
assertTrue(response.isExpired()). This provides clearer intent and is the
preferred pattern for testing boolean conditions in JUnit tests.

Comment on lines +135 to +140
private TestCorePlayer createPlayerWithLocale(Locale locale) {
UUID uuid = UUID.randomUUID();
Player bukkitPlayer = mock(Player.class);
when(bukkitPlayer.locale()).thenReturn(locale);
return new TestCorePlayer(uuid, mockPlugin, bukkitPlayer);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Use MockBukkit's PlayerMock instead of Mockito mock.

Line 137 mocks Player using Mockito. This pattern is repeated throughout the test file (lines 318, 341, 359, 428, etc.). According to coding guidelines, use MockBukkit's PlayerMock implementation instead for all Player instances.

♻️ Suggested improvement

Replace all mock(Player.class) calls with MockBukkit's PlayerMock:

-        Player bukkitPlayer = mock(Player.class);
-        when(bukkitPlayer.locale()).thenReturn(locale);
+        Player bukkitPlayer = new be.seeseemelk.mockbukkit.entity.PlayerMock(/* server, name, uuid */);
+        // PlayerMock has setLocale() or similar method to configure locale

Apply this pattern to all Player mock creation sites in the test file.

As per coding guidelines: "Do not use Mockito to mock a Bukkit class where MockBukkit already provides a real implementation (e.g., PlayerMock, ServerMock) — use the real MockBukkit implementation instead".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/diamonddagger590/mccore/localization/LocalizationManagerTest.java`
around lines 135 - 140, Replace all instances of `mock(Player.class)` with
MockBukkit's `PlayerMock` implementation throughout the test file, including in
the createPlayerWithLocale method and at all other locations mentioned (lines
318, 341, 359, 428, etc.). When creating PlayerMock instances, use MockBukkit's
API to set the locale instead of Mockito's when() syntax, following the coding
guideline to use real MockBukkit implementations rather than Mockito mocks for
Bukkit classes where MockBukkit provides an implementation.

Source: Coding guidelines

Comment on lines +145 to +159
@DisplayName("Given players with Bukkit player available, when getAllBukkitPlayers, then returns bukkit players")
void getAllBukkitPlayers_returnsBukkitPlayers_whenPresent() {
UUID uuid = UUID.randomUUID();
Player bukkitPlayer = mock(Player.class);

TestCorePlayer corePlayer = mock(TestCorePlayer.class);
when(corePlayer.getAsBukkitPlayer()).thenReturn(Optional.of(bukkitPlayer));
when(corePlayer.getUUID()).thenReturn(uuid);

manager.addPlayer(corePlayer);

Set<Player> result = manager.getAllBukkitPlayers();
assertEquals(1, result.size());
assertTrue(result.contains(bukkitPlayer));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Use MockBukkit's PlayerMock instead of Mockito mock.

Line 148 mocks Player using Mockito, but the coding guidelines require using MockBukkit's PlayerMock implementation instead. This ensures test fidelity and consistency with the framework's test patterns.

♻️ Suggested improvement
-        Player bukkitPlayer = mock(Player.class);
+        Player bukkitPlayer = new be.seeseemelk.mockbukkit.entity.PlayerMock(/* appropriate constructor args */);

As per coding guidelines: "Do not use Mockito to mock a Bukkit class where MockBukkit already provides a real implementation (e.g., PlayerMock, ServerMock) — use the real MockBukkit implementation instead".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/com/diamonddagger590/mccore/player/PlayerManagerTest.java`
around lines 145 - 159, In the
getAllBukkitPlayers_returnsBukkitPlayers_whenPresent method, replace the Mockito
mock(Player.class) with MockBukkit's PlayerMock implementation. Instead of
creating a mocked Player object, instantiate a new PlayerMock object to ensure
consistency with the framework's test patterns and coding guidelines that
require using MockBukkit's real implementations for Bukkit classes.

Source: Coding guidelines

Comment on lines +161 to +173
@Test
@DisplayName("Given players without Bukkit player, when getAllBukkitPlayers, then returns empty set")
void getAllBukkitPlayers_returnsEmpty_whenNoBukkitPlayers() {
UUID uuid = UUID.randomUUID();

TestCorePlayer corePlayer = mock(TestCorePlayer.class);
when(corePlayer.getAsBukkitPlayer()).thenReturn(Optional.empty());
when(corePlayer.getUUID()).thenReturn(uuid);

manager.addPlayer(corePlayer);

assertTrue(manager.getAllBukkitPlayers().isEmpty());
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Use MockBukkit's PlayerMock instead of Mockito mock.

Line 166 also mocks Player using Mockito. Use MockBukkit's PlayerMock for consistency with the coding guidelines.

As per coding guidelines: "Do not use Mockito to mock a Bukkit class where MockBukkit already provides a real implementation (e.g., PlayerMock, ServerMock) — use the real MockBukkit implementation instead".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/com/diamonddagger590/mccore/player/PlayerManagerTest.java`
around lines 161 - 173, The test method
`getAllBukkitPlayers_returnsEmpty_whenNoBukkitPlayers` uses Mockito's `mock()`
to create test instances, but per coding guidelines, MockBukkit's real
implementations should be used instead of Mockito mocks for Bukkit classes.
Replace the Mockito mock approach with MockBukkit's PlayerMock when creating any
Bukkit Player instances in this test to ensure consistency with the codebase
standards.

Source: Coding guidelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants