Overview
This test plan covers the dialogue and video cutscene systems (Cutscenes and Dialogue):
- The dialogue flow โ
DialogueRunner (typewriter reveal, line advance, skip) and the DialogueScript data it plays.
- Cutscene scripts and the mp4 player โ
CutsceneScript and Mp4VideoPlayer (pure-Java JCodec decoding).
- The
NarrativeManagerComponent, which answers the startDialogue / startCutscene events, freezes the world, locks the player's controls, handles once-only and busy rules, fires timed events and always sends the matching *Finished event.
- Input capture โ
NarrativeInputComponent (advance, ESC, swallowed gameplay keys, and handing input to the debug terminal while it is open).
- The world freeze in
EntityService (setFrozen), which is separate from the inventory's toggleUpdate pause.
- Script loading from
configs/dialogues and configs/cutscenes, including that every dialogue and cutscene used by a Interactable NPC has a file.
- The two debug-terminal entry points,
dialogue and cutscene.
A dialogue and a cutscene are deliberately different things. A dialogue is UI on top of the running scene; a cutscene takes over the whole screen. Both freeze the world and lock the player, each under its own owner so one cannot release the other's freeze. They are tested together here because the manager runs both.
Testing is split into automated unit tests (what the code must do) and manual gameplay tests (what the player must see). Every behaviour in the automated plan is enforced by a test in the repository โ the test class is named above each table.
Test Environment
- Unit testing: JUnit 5 and Mockito, run headlessly with the engine's
GameExtension. OpenGL is mocked, so the manager is tested against fake DialogueView and CutsceneView implementations and the clock is driven by hand (update(float)) rather than by sleeping. Mp4VideoPlayerTest decodes the real demo video.
- Game testing: Desktop application.
- Movement:
WASD โ Interact: E โ Advance dialogue: SPACE / ENTER / left click โ Leave dialogue / skip cutscene: ESC โ Debug terminal: F1
- Terminal commands:
dialogue demo # play configs/dialogues/demo.json
cutscene demovideo # play configs/cutscenes/demovideo.json (assets/videos/demo.mp4)
File names may be given with or without .json and may contain letters, digits, _, - and .. The terminal stays open if the file is not found.
- Shipped content:
demo dialogue (three speakers: Wandering Spirit, You, Travelling Merchant), merchant_greeting and spirit_greeting dialogues, and demovideo plus the three NPC cutscenes (merchant_opens_shop, spirit_reveals_dungeons, guardian_awakens), which currently all play the demo video as a placeholder.
- Tuned values as shipped: the typewriter reveals 45 characters per second; the dialogue box is 82% of the screen width (max 1100 px) along the bottom; a video that produces no frame within 5 s is abandoned.
Run the automated tests with:
cd source
./gradlew :core:test
Coverage is written to source/core/build/reports/jacoco/test/html/index.html by:
cd source
./gradlew :core:jacocoTestReport
Coverage
Last verified run: 8 Oct 2026 on branch chaubenn/cutscene-dialogue-ui (525cc0d, PR #231) โ 2002 tests, 0 failures project-wide, of which 59 tests across 7 classes cover dialogue and cutscenes.

Reference: SonarCloud project overview ยท SonarCloud analysis of PR #231 (0 open issues at the time of writing)
The badges above are project-wide. The figures below are the cutscene and dialogue code only, from a local JaCoCo run of the revision above (this feature was not yet on main, so SonarCloud's per-file figures are not used).
Per-file coverage
| File |
Lines |
Line coverage |
Branch coverage |
Method coverage |
components/cutscene/NarrativeManagerComponent.java |
156 |
89.1% |
70.7% |
90.6% |
components/cutscene/DialogueRunner.java |
47 |
93.6% |
65.6% |
100.0% |
components/cutscene/DialogueScript.java |
39 |
100.0% |
80.0% |
100.0% |
components/cutscene/CutsceneScript.java |
26 |
96.2% |
75.0% |
85.7% |
components/cutscene/CutsceneEvents.java |
10 |
40.0% |
โ |
40.0% |
components/cutscene/ScriptNames.java |
8 |
75.0% |
85.7% |
75.0% |
components/cutscene/NarrativeInputComponent.java |
22 |
95.5% |
100.0% |
83.3% |
components/cutscene/Mp4VideoPlayer.java |
91 |
93.4% |
77.5% |
100.0% |
ui/terminal/commands/DialogueCommand.java |
13 |
100.0% |
80.0% |
100.0% |
ui/terminal/commands/CutsceneCommand.java |
13 |
100.0% |
87.5% |
100.0% |
components/cutscene/DialogueDisplay.java |
163 |
0.0% |
0.0% |
0.0% |
components/cutscene/CutscenePlayer.java |
91 |
0.0% |
0.0% |
0.0% |
components/cutscene/TypewriterText.java |
52 |
0.0% |
0.0% |
0.0% |
components/cutscene/PortraitActor.java |
24 |
0.0% |
0.0% |
0.0% |
entities/factories/NarrativeFactory.java |
12 |
0.0% |
โ |
0.0% |
EntityService.java (new: setFrozen, isFrozen, shouldUpdate) |
11 |
100.0% |
91.7% |
100.0% |
Aggregate across the 10 logic classes (everything above the four UI classes and the factory; JaCoCo, source/core/build/reports/jacoco/test/html/index.html):
| Counter |
Covered |
Missed |
Coverage |
| Instructions |
1650 |
123 |
93.1% |
| Branches |
174 |
55 |
76.0% |
| Lines |
389 |
36 |
91.5% |
| Methods |
91 |
9 |
91.0% |
| Classes |
15 |
0 |
100.0% |
Aggregate across all 15 classes, including the four classes that draw with OpenGL and NarrativeFactory:
| Counter |
Covered |
Missed |
Coverage |
| Instructions |
1650 |
1621 |
50.4% |
| Branches |
174 |
201 |
46.4% |
| Lines |
389 |
378 |
50.7% |
| Methods |
91 |
58 |
61.1% |
| Classes |
15 |
7 |
68.2% |
The logic is at about 91% line coverage; the overall figure is lower only because DialogueDisplay, CutscenePlayer, TypewriterText, PortraitActor and NarrativeFactory need a real OpenGL context and are covered by the manual plan below. The uncovered lines in the logic classes are listed under Known coverage gaps.
Tests per class
| Test class |
Tests |
NarrativeManagerComponentTest |
23 |
NarrativeInputComponentTest |
9 |
DialogueRunnerTest |
7 |
ScriptLoadingTest |
6 |
EntityServiceFreezeTest |
5 |
NarrativeCommandsTest |
5 |
Mp4VideoPlayerTest |
4 |
| Total |
59 |
Automated Unit Test Plan
Dialogue
DialogueRunnerTest
The runner holds no UI or libGDX state, so the whole line flow โ typewriter, finish-the-line, next line, finish โ is tested directly.
| Test |
Purpose |
Expected Result |
startShowsFirstLineWithNothingRevealed |
Start a two-line dialogue. |
Line 0 is announced to the listener with no characters revealed yet, and its speaker resolves to the named speaker. |
textIsTypedOutOverTime |
Step time by exactly two characters' worth, then a full second. |
Two characters show first, then the whole line; the line then reads as complete. |
advanceFirstCompletesTheLineThenMovesOn |
Press advance mid-line, then again. |
The first press reveals the rest of the line without moving on; the second moves to line 1. |
advancingPastTheLastLineFinishesOnce |
Advance through every line and past the end. |
onFinished fires exactly once, and further advances do nothing. |
skipAllFinishesImmediately |
Skip from the first line. |
Only the first line was ever shown, and the dialogue finishes at once โ this is what ESC uses. |
emptyScriptFinishesOnStart |
Start a script with no lines. |
It finishes immediately without showing anything. |
unknownSpeakerAndMissingTextAreTolerated |
Show a line whose speaker is not defined and whose text is null. |
No speaker, empty text, and the line reads as already complete โ no exception. |
Cutscenes and the Narrative Manager
NarrativeManagerComponentTest
The manager owns the freeze, the control lock, the busy and once-only rules and the events. These tests run it against fake views and a real EntityService and PlayerActions, and hold the "always release, always report finished" guarantee in place.
| Test |
Purpose |
Expected Result |
dialogueFreezesWorldLocksControlsAndReleasesWhenFinished |
Play a dialogue, then finish it. |
While open the world is frozen, controls are locked and dialogueStarted has fired; on finish both are released, the view is closed and dialogueFinished fires. |
lineShownEventsAndCuesAreForwarded |
Show two lines, the second flagged "cue": true. |
dialogueLineShown fires per line with its index, and dialogueCutsceneCue fires only for the flagged line. |
startDialogueEventPlaysTheDialogueAndMissingFilesStillFinish |
Send startDialogue for an id with no file. |
Nothing is shown, but dialogueFinished is still sent so a waiting NPC is released; the world is never frozen. |
scriptEventPlaysAScriptBuiltInCode |
Send startDialogueScript with a script built in code. |
The view is shown that exact script. |
secondDialogueIsIgnoredWhileOneIsOpen |
Request a second dialogue while one is open. |
Ignored: the first stays on screen and no events are sent. |
emptyDialogueFinishesWithoutFreezing |
Play a script with no lines. |
dialogueFinished is sent straight away and the game never freezes. |
onceOnlyDialoguePlaysOncePerSession |
Play a once dialogue twice, then reset. |
The second play sends dialogueFinished without showing it or freezing; after resetPlayed() it plays again. |
aFollowUpCanStartFromInsideTheFinishedEvent |
Start a cutscene from a dialogueFinished listener. |
The cutscene starts and the world is frozen again โ state is cleared before the event, which is how an NPC chains dialogue into a cutscene. |
leavingADialogueEndsItEarlyAndReleasesTheGame |
Leave (ESC) an open dialogue. |
dialogueSkipped then dialogueFinished, the freeze and lock are released, and the dialogue is no longer active. |
aSkippedDialogueCanBePlayedAgainFromTheStart |
Skip a dialogue, then play it again. |
It starts again from the beginning. |
leaveClosesTheDialogueBeforeTheCutscene |
Leave while a dialogue and a cutscene are both open. |
The first leave closes only the dialogue; the second skips the cutscene. |
leaveWithNothingPlayingDoesNothing |
Leave with nothing open. |
Returns false and sends no events. |
advanceGoesToTheDialogue |
Advance while a dialogue is open. |
The dialogue view is asked to advance. |
cutsceneFreezesWorldLocksControlsAndReleasesWhenFinished |
Play a cutscene, then finish it. |
Frozen and locked while playing; released on finish with cutsceneStarted then cutsceneFinished. |
cutsceneThatFinishesImmediatelyDoesNotLeaveTheGameFrozen |
Use a view that reports finished from inside play() (e.g. a video that cannot be decoded). |
The freeze and lock are released and no cutscene is left active. |
secondCutsceneIsIgnoredWhileOneIsPlaying |
Request a second cutscene mid-play. |
Ignored; the first keeps playing. |
onceOnlyCutscenePlaysOncePerSession |
Play a once cutscene twice. |
The second sends cutsceneFinished immediately and plays nothing. |
skippableCutsceneCanBeSkipped |
Advance during a skippable cutscene. |
cutsceneSkipped then cutsceneFinished, and the game is released. |
nonSkippableCutsceneSwallowsTheKeyButKeepsPlaying |
Advance during a cutscene with skippable: false. |
The key is consumed but the cutscene keeps playing. |
timedEventsFireInOrderAtTheirTimes |
Schedule events at 4 s and 1 s, then step time. |
They fire in time order at their times, with their argument (or none), and never twice. |
timedEventsStopFiringOnceTheCutsceneEnds |
Finish a cutscene before an event's time. |
The event never fires. |
dialogueAndCutsceneReleaseTheirOwnFreezeIndependently |
Open both, finish the cutscene, then the dialogue. |
The game stays frozen and locked until the second one ends. |
disposeNeverLeavesTheGameFrozen |
Dispose the manager with both open. |
The freeze and the control lock are released. |
Input
NarrativeInputComponentTest
The handler sits above the player and terminal input so nothing can be played behind a dialogue, but it must step aside for the terminal and must never unbalance the player's key bookkeeping.
| Test |
Purpose |
Expected Result |
ignoresEverythingWhileNothingIsPlaying |
Send keys and a click with no dialogue or cutscene. |
Nothing is consumed or advanced. |
spaceEnterAndLeftClickAdvance |
Press SPACE, ENTER and left click during a dialogue. |
All three are consumed and advance it. |
rightClickIsSwallowedWithoutAdvancing |
Right-click during a dialogue. |
Consumed, but does not advance. |
escapeLeavesTheDialogueOrSkipsTheCutscene |
Press ESC while something is playing. |
Consumed, and the manager is asked to leave. |
gameplayKeysAreSwallowedAndF1StillOpensTheTerminal |
Press W, J and F1 during a dialogue. |
W and J are consumed and do nothing; F1 passes through so the terminal still opens. |
typingInTheTerminalDoesNotAdvanceTheDialogue |
With the terminal open, send SPACE, ENTER, ESC, a letter and a click. |
None are consumed, so the terminal gets them and the dialogue neither advances nor closes. This is the regression behind PR #231's reported bug. |
inputIsHandledAgainOnceTheTerminalCloses |
Close the terminal and press SPACE. |
The dialogue advances again. |
keyUpIsOnlySwallowedForKeysPressedDuringTheNarrative |
Hold D before the dialogue, press W during it, release both. |
Releasing D reaches the player; releasing W is swallowed โ so the player's walk direction stays balanced. |
keyUpOfAKeySwallowedBeforeTheTerminalOpenedIsStillSwallowed |
Press W during a dialogue, open the terminal, release W. |
The release is still swallowed, because the player never saw the press. |
Script Files
ScriptLoadingTest
These load the real shipped JSON, so a broken or missing script fails the build rather than a player.
| Test |
Purpose |
Expected Result |
demoDialogueLoadsWithSpeakersAndLines |
Load demo. |
It has lines, every line's speaker is defined, every line has text, and every speaker's portrait atlas exists. |
jsonExtensionIsAccepted |
Load demo.json and demovideo.json. |
Both load. |
demoCutsceneLoadsAndPointsAtARealVideo |
Load demovideo. |
It is skippable and its video path exists in the assets. |
missingOrUnsafeNamesReturnNull |
Load nope, null, blank, ../configs/rooms and sub/dir. |
All return null โ a name can never escape the scripts folder. |
everyDialogueAndCutsceneUsedByAFriendlyNpcHasAScript |
Read friendlyNpcs.json and load each NPC's dialogue and cutscene id. |
Every one exists, so an NPC can never hang waiting on a missing script. |
builderMethodsAccumulate |
Chain speaker/line and ofVideo(...).at(...). |
Each call appends rather than replaces. |
Video
Mp4VideoPlayerTest
| Test |
Purpose |
Expected Result |
rgbBytesAreConvertedToOpaqueRgba |
Convert a 2ร1 picture of known values. |
JCodec's signed RGB bytes (value โ 128) become the expected opaque RGBA bytes. |
onlyTheRequestedWindowIsCopied |
Convert the top row and the bottom row of a 2ร2 picture. |
Only the requested window is copied โ this is how the decoder's macroblock padding (e.g. 368 decoded rows for a 360-row video) is cut off. |
demoVideoDecodesFramesAndFinishes |
Decode the real videos/demo.mp4, stepping time until it ends. |
No failure, the whole video plays out, at least one frame is shown, and the texture is the true 640ร360. |
notAnMp4IsRejected |
Open a JSON file as a video. |
The constructor throws rather than starting a decoder. |
World Freeze
EntityServiceFreezeTest
| Test |
Purpose |
Expected Result |
everythingUpdatesWhenNothingIsFrozen |
Update with no freeze. |
Every entity updates. |
freezeStopsEveryoneExceptOptedInEntities |
Freeze, then update. |
Only entities that called setUpdatesWhilePaused(true) (the HUD and the narrative entity) update. |
freezeIsReleasedOnlyWhenEveryOwnerHasReleased |
Two owners freeze; release one twice, then the other. |
Still frozen until both have released. |
freezeIsIndependentOfTheInventoryPause |
Open the inventory pause (toggleUpdate), then freeze and unfreeze. |
The inventory pause is neither cleared nor changed by the freeze. |
uiComponentsDoNotCountAsOptedIn |
Freeze with an enemy that owns a UIComponent (e.g. a health bar). |
The enemy is still frozen โ unlike the inventory pause, a freeze is not bypassed by UI components. |
Terminal Commands
NarrativeCommandsTest
| Test |
Purpose |
Expected Result |
dialogueCommandPlaysTheNamedFile |
Run dialogue demo. |
The demo script is sent to the player. |
dialogueCommandAcceptsAJsonExtension |
Run dialogue demo.json. |
Same script plays. |
dialogueCommandRejectsMissingFilesAndBadArguments |
Run with an unknown file, no arguments, an extra argument and a null player. |
All return false (so the terminal stays open) and nothing plays. |
cutsceneCommandPlaysTheNamedFile |
Run cutscene demovideo. |
The demovideo script is sent, pointing at videos/demo.mp4. |
cutsceneCommandRejectsMissingFilesAndBadArguments |
Run with an unknown file, no arguments and a null player. |
All return false and nothing plays. |
Manual Gameplay Test Plan
Setup for every test below: run the game (cd source && ./gradlew :desktop:run), start a run and open the debug terminal (F1). Tests that need enemies must be done in a dungeon room (walk to a bookshelf in the hub and press E); the hub has none. dialogue demo and cutscene demovideo can be run from anywhere.
Dialogue box
| Test |
Steps |
Expected Result |
| Layout |
Run dialogue demo. |
A parchment box sits along the bottom with the text on the left and, on the right, a framed portrait with a name plate beneath it. |
| Above the HUD |
Look at the run timer at the bottom left while the box is open. |
The box is drawn over the HUD, never behind it. |
| Typewriter |
Watch the first line appear. |
Text types out at a steady pace; words do not jump to the next line half way through typing. |
| Continue hint |
Wait for the line to finish typing. |
A small bouncing arrow appears at the bottom right of the text box. |
| Finish then advance |
Press SPACE mid-line, then again. |
The first press shows the rest of the line; the second moves to the next line. |
| Speakers change |
Advance through the whole demo dialogue. |
The portrait and name change per line (Wandering Spirit, You, Travelling Merchant), and each portrait is animated. |
| Wrapping |
Read the longest line. |
It wraps inside the text panel without overflowing the box. |
| Ends cleanly |
Advance past the last line. |
The box disappears and the player can move again. |
| Resize |
Resize or maximise the window while the box is open. |
The box stays anchored to the bottom and rescales. |
Input
| Test |
Steps |
Expected Result |
| Other advance keys |
Advance lines using ENTER and a left click. |
Both advance; a right click does nothing. |
| Gameplay is inert |
During a dialogue press W A S D, J, K, I, TAB, Q, 1โ3. |
Nothing happens: the player does not move or attack and the inventory does not open. |
| Held key |
Hold D, run dialogue demo, release D during it, then finish. |
The player does not drift after the dialogue ends. |
| ESC leaves |
Press ESC mid-dialogue. |
The dialogue closes at once and controls return. |
| Restart after ESC |
At the Travelling Merchant press E, ESC mid-dialogue, then press E again. |
The dialogue starts again from the first line. |
| Terminal does not advance |
During a dialogue press F1, type spell (including the space). |
The text appears in the terminal and the dialogue stays on its current line. |
| Terminal closes |
Press F1 again, then SPACE. |
The terminal closes and SPACE advances the dialogue again. |
World freeze
| Test |
Steps |
Expected Result |
| Enemies stop |
In a dungeon room with moving enemies run dialogue demo. |
Every enemy stops where it is, projectiles and traps freeze and sprite animations stop. |
| Resume in place |
Finish the dialogue. |
Enemies carry on from exactly where they were. |
| No damage |
Run the dialogue with enemies next to the player. |
The player takes no damage while it is open. |
| Player locked |
Try to move, dash and attack during a dialogue. |
The player does nothing. |
| Run timer |
Note the run timer, open a dialogue for ~10 s, close it. |
The timer did not advance while the dialogue was open. |
| Inventory pause unchanged |
Close all dialogues, then press I. |
The inventory opens and pauses the game as before. |
| Prompt hidden |
Walk up to an NPC (so "Press E" shows), start a dialogue. |
The prompt disappears while the dialogue is open. |
Video cutscene
| Test |
Steps |
Expected Result |
| Plays full screen |
Run cutscene demovideo. |
The mp4 plays full screen over the game, correct colours and aspect ratio with black bars where the shape differs, for about 4 s. |
| Returns to the game |
Let it finish. |
The game is visible again, unfrozen, with controls back. |
| Skip |
Run it and press SPACE, then again with ESC, then with a click. |
Each skips at once and returns to the game. |
| World frozen |
Run it in a dungeon room. |
Enemies and the run timer are frozen for the whole video. |
| No audio |
Listen while it plays. |
Silent โ video only. |
| Resize |
Resize the window during playback. |
The picture keeps its aspect ratio. |
| Busy |
Run cutscene demovideo again while it is playing. |
Ignored; the first keeps playing. |
| Undecodable video |
Copy any text file to source/core/assets/videos/bad.mp4, create configs/cutscenes/bad.json containing { "video": "videos/bad.mp4" }, then run cutscene bad. |
The cutscene ends immediately, the game is not left frozen, and an error is logged. |
Terminal commands
| Test |
Steps |
Expected Result |
| Valid names |
Run dialogue demo and dialogue demo.json. |
Both play and the terminal closes. |
| Missing file |
Run dialogue nope and cutscene nope. |
Nothing plays and the terminal stays open. |
| Bad arguments |
Run dialogue with no argument, and dialogue demo extra. |
Rejected; the terminal stays open. |
| Allowed characters |
Type _, - and . into the terminal. |
They appear in the entered text. |
Interactable NPCs
| Test |
Steps |
Expected Result |
| Merchant |
In the hub press E next to the Travelling Merchant. |
The two-line merchant_greeting dialogue plays, then the cutscene, then controls return. |
| Repeatable |
Press E at the merchant again. |
The interaction plays again. |
| Spirit is once-only |
Complete the Wandering Spirit's interaction, then press E again. |
"The spirit has nothing more to say." and nothing plays. |
| Guardian is gated |
Approach the Sealed Guardian before the Spirit. |
"The guardian will not stir. Perhaps the spirit knows why." |
| Guardian unlocks |
Talk to the Spirit, run room clear, return to the guardian. |
The prompt becomes "Wake"; the cutscene plays with no dialogue. |
E during a dialogue |
Press E repeatedly during an NPC dialogue. |
It does not restart or stack the interaction. |
| ESC mid NPC dialogue |
At the merchant press ESC during the dialogue. |
The dialogue closes; the NPC's cutscene then plays (and can itself be skipped with ESC); afterwards the NPC can be talked to again. |
Combined
| Test |
Steps |
Expected Result |
| Video over a dialogue |
While a dialogue is open, run cutscene demovideo from the terminal. |
The video plays and the dialogue box stays on top of it. The first ESC closes the dialogue, the second skips the video, and the game stays frozen until both have ended. |
| Back to back |
Run dialogue demo, finish it, then run cutscene demovideo. |
Each freezes and releases cleanly; the player can move afterwards. |
Known Coverage Gaps
Everything uncovered in the logic classes is listed here. Nothing below is a known defect; each is either untestable without OpenGL or a branch that no shipped content reaches.
| Location |
Uncovered |
Why |
DialogueDisplay, CutscenePlayer, TypewriterText, PortraitActor |
The whole classes (0%) |
They create scene2d actors, textures and the stage, which need a real OpenGL context; GameExtension mocks GL. Covered by the manual plan above. The behaviour the manager needs from them is defined by the DialogueView / CutsceneView interfaces and tested through fakes. |
NarrativeFactory |
The whole class |
Pure wiring of the narrative entity; it creates the UI components above. Exercised every time the game starts. |
NarrativeManagerComponent.playCutscene(String) |
The load-by-id path, including the "missing file still sends cutsceneFinished" branch |
The dialogue version of this rule is tested (startDialogueEventPlaysTheDialogueAndMissingFilesStillFinish) but the cutscene twin is not. |
NarrativeManagerComponent.playDialogue(String) |
The "file found" branch |
Tests reach a real file only through DialogueCommand, which sends the already-loaded script. |
NarrativeManagerComponent.update() (no argument) |
The frame hook |
Tests drive the package-private update(float) directly. |
NarrativeManagerComponent.hold(...) |
Clearing the "Press E" prompt |
The test player has no InteractionPromptDisplay; checked manually under "Prompt hidden". |
CutsceneEvents.playDialogue(Entity, String) / playCutscene(Entity, String) |
The two one-line helpers and the private constructor |
The script-object helpers and the underlying events are covered. |
NarrativeInputComponent.touchUp |
Releasing a mouse button that was swallowed |
touchDown is covered. |
Mp4VideoPlayer decoder thread |
The catch blocks for a decode failure or interruption |
Only a valid video and a non-mp4 file are tested; a file that fails part-way through is not. |
CutsceneScript.TimedEvent() |
The no-argument constructor |
Only used by the JSON reader. A throwaway test confirmed an events list in a cutscene file parses correctly, but no shipped file has one, so it is not in the suite. |
ScriptNames |
The private constructor and the "no Gdx.files" branch |
Defensive guards. |
Early returns in DialogueRunner and NarrativeManagerComponent |
A few if (...) return; guards (starting or finishing a dialogue twice, a blank timed-event name, a null script, skipping with nothing open) |
Defensive; no shipped content reaches them. |
Areas Not Covered by Automated Tests
- Visual correctness. Nothing asserts a pixel. Whether the box looks right, whether the typewriter wraps cleanly, whether the portrait scales sensibly and whether the nine-patch borders line up is judged manually.
MainGameScreen wiring of the freeze. Skipping physics, room logic and the run timer, and zeroing the time scale, while frozen has no automated test; it is only checked by the world-freeze manual tests.
- Wall-clock timers. The freeze zeroes the shared game time scale, but timers that read the system clock or build their own
GameTime (for example some cooldown and effect deadlines) keep running while a dialogue is open, so they can already have expired when the game resumes.
- Video variety. Only the baseline H.264 demo clip is decoded in tests. Other profiles, large or high-resolution videos and long videos depend on JCodec and the player's machine; performance is judged manually. There is no audio.
- The real terminal input chain. The terminal-open guard is unit tested with a stand-in for the terminal; the end-to-end behaviour (
F1, typing spell , SPACE) was verified in the running game and is in the manual plan.
- NPC event contract. The sequencing of dialogue and cutscene around an NPC (
NpcInteractionSequence, NpcInteractorComponent) belongs to the Interactable NPCs tests and is not repeated here; this plan only checks that every NPC's scripts exist.
- Content quality. Placeholder cutscenes, writing and tone are not tested. The NPC cutscenes currently reuse the demo video.
Related pages