Card Cool Down Testing - UQcsse3200/2026-studio-3 GitHub Wiki

Methodology

Tests were designed against each method's control flow graph (CFG): for every if/loop condition in the methods under test, at least one test was written to exercise each outcome (true and false, or "found" and "not found"). Coverage numbers below are JaCoCo branch coverage, gathered from a fresh ./gradlew :core:test :core:jacocoTestReport run. Branch coverage is the relevant metric here since the logic in both features is almost entirely decision-driven (guards, membership checks, loop termination) rather than long straight-line computation.

Cooldown: CardCooldownTracker

flowchart TD
    A["trackDiscard(instance, rounds)"] --> B{"rounds > 0?"}
    B -- yes --> C["add Entry(instance, rounds)"]
    B -- no --> D["do nothing"]

    E["tickRoundAndRetrieve()"] --> F{"more entries?"}
    F -- no --> G["return retrieved"]
    F -- yes --> H["roundsRemaining--"]
    H --> I{"roundsRemaining <= 0?"}
    I -- no --> F
    I -- yes --> J{"retrieveInstanceFromDiscard succeeds?"}
    J -- yes --> K["add cardId to retrieved, remove entry"]
    J -- no --> L["remove entry only"]
    K --> F
    L --> F

    M["isOnCooldown(instance)"] --> N{"any entry.instance.equals(instance)?"}
    N -- yes --> O["return true"]
    N -- no --> P["return false"]
Branch Covered by Outcome tested
rounds > 0 → true shouldTrackCooldownPerInstanceNotPerCardId entry gets tracked
rounds > 0 → false (not directly tested) never reached via the public API: CardPlayService always calls trackDiscard with CardCooldown.roundsFor(card), which is always ≥ 1 by construction. A defensive guard, not a live code path.
roundsRemaining <= 0 → false (still counting) shouldOnlyRetrieveTheSpecificInstanceOnCooldown (first tick of a 2-round cooldown returns empty) tick decrements without retrieving
roundsRemaining <= 0 → true both cooldown tests retrieval fires once the count reaches zero
retrieveInstanceFromDiscard succeeds both cooldown tests normal retrieval path
retrieveInstanceFromDiscard fails (not tested) would require the instance to have left the discard pile through some other path between trackDiscard and the tick; not currently reachable in normal play
isOnCooldown match / no match shouldTrackCooldownPerInstanceNotPerCardId asserts true for the discarded instance, false for its still-in-hand duplicate

Measured coverage: CardCooldownTracker 24/25 lines (96%), 11/14 branches (78%), 4/4 methods (100%). The two uncovered branches are the rounds > 0 → false guard and the retrieveInstanceFromDiscard failure path, both defensive and not reachable through the code paths CardPlayService actually exercises.