package tests import "core:fmt" import "core:strings" import "core:testing" import "../src/core" import "../src/adapters" import "../src/gui" import "../src/ui" // ───────────────────────────────────────────────────────────── // Phase 6: Appearance Count + Streaming + Bubble Editing // ───────────────────────────────────────────────────────────── // ── Appearance Count Tests ── @test core_count_appearances_basic :: proc(t: ^testing.T) { script := core.Comic_Script{ title = "Test Comic", synopsis = "A test comic", characters = []core.Character{ {id = "hero", name = "Hero", role = .Protagonist}, {id = "villain", name = "Villain", role = .Antagonist}, {id = "sidekick", name = "Sidekick", role = .Supporting}, }, pages = []core.Page{ { page_number = 1, panels = []core.Panel{ {panel_id = "p1", characters_present = []string{"hero"}}, {panel_id = "p2", characters_present = []string{"hero", "villain"}}, }, }, { page_number = 2, panels = []core.Panel{ {panel_id = "p3", characters_present = []string{"hero", "sidekick"}}, {panel_id = "p4", characters_present = []string{"villain"}}, {panel_id = "p5", characters_present = []string{"hero", "villain", "sidekick"}}, }, }, }, } core.count_character_appearances(&script) testing.expect(t, script.characters[0].appearance_count == 4, fmt.tprintf("hero should appear 4 times, got %d", script.characters[0].appearance_count)) testing.expect(t, script.characters[1].appearance_count == 3, fmt.tprintf("villain should appear 3 times, got %d", script.characters[1].appearance_count)) testing.expect(t, script.characters[2].appearance_count == 2, fmt.tprintf("sidekick should appear 2 times, got %d", script.characters[2].appearance_count)) } @test core_count_appearances_first_panel :: proc(t: ^testing.T) { script := core.Comic_Script{ title = "Test", synopsis = "Test", characters = []core.Character{ {id = "a", name = "A", role = .Protagonist}, {id = "b", name = "B", role = .Supporting}, }, pages = []core.Page{ { page_number = 1, panels = []core.Panel{ {panel_id = "panel_001", characters_present = []string{"a"}}, {panel_id = "panel_002", characters_present = []string{"a", "b"}}, }, }, }, } core.count_character_appearances(&script) testing.expect(t, script.characters[0].first_appearance_panel == "panel_001", fmt.tprintf("A first panel should be panel_001, got %q", script.characters[0].first_appearance_panel)) testing.expect(t, script.characters[1].first_appearance_panel == "panel_002", fmt.tprintf("B first panel should be panel_002, got %q", script.characters[1].first_appearance_panel)) } @test core_count_appearances_zero :: proc(t: ^testing.T) { script := core.Comic_Script{ title = "Test", synopsis = "Test", characters = []core.Character{ {id = "unused", name = "Unused", role = .Extra}, }, pages = []core.Page{ { page_number = 1, panels = []core.Panel{ {panel_id = "p1", characters_present = []string{"other"}}, }, }, }, } core.count_character_appearances(&script) testing.expect(t, script.characters[0].appearance_count == 0, "unused character should have 0 appearances") testing.expect(t, len(script.characters[0].first_appearance_panel) == 0, "unused character should have no first panel") } @test core_count_appearances_empty_script :: proc(t: ^testing.T) { script := core.Comic_Script{ title = "Empty", synopsis = "Empty", characters = []core.Character{}, pages = []core.Page{}, } core.count_character_appearances(&script) testing.expect(t, len(script.characters) == 0, "should have no characters") } // ── Bubble Text Editing Tests ── @test core_update_bubble_text :: proc(t: ^testing.T) { bubble := core.Speech_Bubble{ id = "bubble_1", panel_id = "panel_1", text = "Hello world", speaker_id = "char_1", } updated := core.update_bubble_text(bubble, "New text") testing.expect(t, updated.text == "New text", fmt.tprintf("text should be updated, got %q", updated.text)) testing.expect(t, updated.id == "bubble_1", "id should be preserved") testing.expect(t, updated.panel_id == "panel_1", "panel_id should be preserved") } @test gui_action_update_bubble_text :: proc(t: ^testing.T) { state := core.new_initial_state() defer core.dispose_state(&state) controller := ui.new_controller(state) defer ui.dispose_job_manager(&controller.jobs) // Add a character and panel with dialogue char := core.Character{id = "char_1", name = "Hero", role = .Protagonist} chars: [dynamic]core.Character append(&chars, char) controller.state.characters = chars[:] defer delete(chars) panel := core.Panel{ panel_id = "panel_1", panel_number = 1, dialogue = []core.Dialogue{ {speaker_id = "char_1", text = "Original text", emotion = .Neutral}, }, } // Generate bubbles for the panel bubbles := core.auto_place_panel_bubbles(panel, 800, 600) defer delete(bubbles) controller.state.speech_bubbles = make(map[string][]core.Speech_Bubble) controller.state.speech_bubbles["panel_1"] = bubbles // Update bubble text if len(bubbles) > 0 { bubble_id := bubbles[0].id msg := gui.action_update_bubble_text(&controller, bubble_id, "Updated dialogue") testing.expect(t, strings.contains(msg, "updated"), fmt.tprintf("should update bubble text, got %q", msg)) } } // ── Bubble Position Tests ── @test core_bubble_position_update :: proc(t: ^testing.T) { bubble := core.Speech_Bubble{ id = "b1", panel_id = "p1", text = "Test", position = core.Position{x = 0.1, y = 0.1}, } updated := core.update_bubble_position(bubble, 0.5, 0.5) testing.expect(t, updated.position.x == 0.5, "x should be 0.5") testing.expect(t, updated.position.y == 0.5, "y should be 0.5") } @test core_bubble_reset_position :: proc(t: ^testing.T) { bubble := core.Speech_Bubble{ id = "b1", panel_id = "p1", text = "Test", position = core.Position{x = 0.9, y = 0.9}, } reset := core.reset_bubble_position(bubble) testing.expect(t, reset.position.x == 0.0, "reset x should be 0") testing.expect(t, reset.position.y == 0.0, "reset y should be 0") } // ── Integration: Full Pipeline with Appearance Count ── @test core_normalize_and_count_appearances :: proc(t: ^testing.T) { script := core.Comic_Script{ title = "Test", synopsis = "Test", characters = []core.Character{ {id = "hero", name = "Hero", role = .Protagonist}, {id = "villain", name = "Villain", role = .Antagonist}, }, pages = []core.Page{ { panels = []core.Panel{ {characters_present = []string{"hero"}}, {characters_present = []string{"hero", "villain"}}, {characters_present = []string{"villain"}}, }, }, }, } normalized := core.normalize_script(script) core.count_character_appearances(&normalized) testing.expect(t, normalized.characters[0].appearance_count == 2, "hero should appear twice") testing.expect(t, normalized.characters[1].appearance_count == 2, "villain should appear twice") }