Skip to content

Rearranging Deck Testing

mariadeniseanda edited this page Sep 15, 2026 · 1 revision

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.

Rearrange: CardPlayService.rearrangeHand and BattleDeck.setHandInstances

flowchart TD
    A["rearrangeHand(newHand)"] --> B{"newHand == null?"}
    B -- yes --> C["throw IllegalArgumentException"]
    B -- no --> D["filter out on-cooldown instances"]
    D --> E{"playableSelection == current hand?"}
    E -- yes --> F["return false, no-op"]
    E -- no --> G{"canAfford && spendEnergy?"}
    G -- no --> H["throw IllegalStateException"]
    G -- yes --> I["battleDeck.setHandInstances(playableSelection)"]
    I --> J{"threw?"}
    J -- yes --> K["restoreEnergy, rethrow"]
    J -- no --> L["return true"]

    M["setHandInstances(newHand)"] --> N{"newHand == null?"}
    N -- yes --> O["throw IllegalArgumentException"]
    N -- no --> P["for each instance in newHand"]
    P --> Q{"instance available in hand/drawPile?"}
    Q -- no --> R["throw IllegalArgumentException"]
    Q -- yes --> S["move to resolved hand"]
    S --> P
    P -- done --> T["commit: hand = resolved, rest reshuffled into drawPile"]
Loading
Branch Covered by Outcome tested
filter: instance on cooldown shouldAllowSelectingAnInstanceOnCooldownWithoutMovingItOrItsSiblingCard discarded pick is excluded from the physical hand, left untouched
filter: instance not on cooldown shouldRearrangeHandToExactSelectedInstancesAndChargeOneEnergy playable pick moves into the hand
playableSelection == current hand → true (no-op) shouldNotChargeEnergyWhenRearrangedHandMatchesCurrentHand returns false, no energy spent
→ false (genuine change) shouldRearrangeHandToExactSelectedInstancesAndChargeOneEnergy returns true, 1 energy spent
canAfford && spendEnergy → false (can't afford) (not tested) no test constructs a low/zero-energy EnergyComponent and attempts a genuine rearrange, this path (and the IllegalStateException) is unverified
setHandInstances throws → rollback (not tested) no test forces setHandInstances to throw mid-rearrangeHand to verify restoreEnergy actually runs; the rollback branch exists in code but isn't exercised
newHand == null (both methods) (not tested) defensive guards, not exercised by name
instance not available (setHandInstances) shouldRejectSettingHandToAnInstanceOnCooldownInDiscard, shouldRejectSettingHandToAnUnknownInstance rejects a discarded instance and a wholly foreign instance respectively
instance available shouldSetHandToExactChosenInstances, shouldLeaveDiscardPileUntouchedWhenSettingHand accepts and commits the selection

Measured coverage: BattleDeck 86/99 lines (87%), 38/44 branches (86%), 22/25 methods (88%); CardPlayService 101/114 lines (89%), 60/88 branches (68%) across the whole class (the rearrange-specific branches are more fully covered than that number suggests, it's diluted by the unrelated card-play code in the same class).

Table of Contents

Home

Game Engine

Getting Started

Entities and Components

Service Locator

Loading Resources

Logging

Unit Testing

Debug Terminal

Input Handling

UI

Animations

Audio

AI

Physics

Game Screens and Areas

Terrain

Concurrency & Threading

Settings

Encounters
Tutorials and Contextual Help (Team 2)
Cards (Team 6)
Story (Team 6)
Level design, battle system, turn order, spawn (Team 3)
Cards, Save/Load & Bestiary (Team 5)
Rewards and Battle Settlement (Team 7)

Troubleshooting

MacOS Setup Guide

Clone this wiki locally