comic/odin/tests/phase2_character_emotion.odin
2026-05-22 03:51:50 +02:00

142 lines
6.4 KiB
Odin

package tests
import "core:fmt"
import "core:strings"
import "core:testing"
import "../src/adapters"
import "../src/core"
import "../src/gui"
import "../src/shared"
import "../src/ui"
// ─────────────────────────────────────────────────────────────
// Phase 2: Character Consistency + Emotion Enum + Character Sheets
// ─────────────────────────────────────────────────────────────
@test
core_emotion_enum_roundtrip :: proc(t: ^testing.T) {
emotions := []core.Emotion{.Happy, .Sad, .Angry, .Surprised, .Neutral, .Determined}
names := []string{"happy", "sad", "angry", "surprised", "neutral", "determined"}
for name, i in names {
e := core.parse_emotion(name)
testing.expect(t, e == emotions[i], fmt.tprintf("parse_emotion(%q) should map to correct enum", name))
testing.expect(t, core.emotion_name(emotions[i]) == name, fmt.tprintf("emotion_name should return %q", name))
}
}
@test
core_emotion_parse_fuzzy :: proc(t: ^testing.T) {
testing.expect(t, core.parse_emotion("joyful") == .Happy, "joyful should map to Happy")
testing.expect(t, core.parse_emotion("crying") == .Sad, "crying should map to Sad")
testing.expect(t, core.parse_emotion("furious") == .Angry, "furious should map to Angry")
testing.expect(t, core.parse_emotion("shocked") == .Surprised, "shocked should map to Surprised")
testing.expect(t, core.parse_emotion("determined") == .Determined, "determined should map to Determined")
testing.expect(t, core.parse_emotion("unknown") == .Neutral, "unknown should default to Neutral")
}
@test
core_art_style_keyword_mapping :: proc(t: ^testing.T) {
styles := []string{"manga", "western-comic", "pixel-art", "watercolor", "noir", "chibi", "sketch", "cyberpunk"}
for s in styles {
key := core.parse_art_style_key(s)
keywords := core.get_style_keywords(key)
testing.expect(t, len(keywords) > 0, fmt.tprintf("style %q should have keywords", s))
}
}
@test
core_shot_type_to_image_size :: proc(t: ^testing.T) {
testing.expect(t, core.get_image_size_for_shot_type(.Establishing) == .Landscape_16_9, "establishing should be 16:9")
testing.expect(t, core.get_image_size_for_shot_type(.Wide) == .Landscape_16_9, "wide should be 16:9")
testing.expect(t, core.get_image_size_for_shot_type(.Medium) == .Landscape_4_3, "medium should be 4:3")
testing.expect(t, core.get_image_size_for_shot_type(.Close_Up) == .Portrait_4_3, "close-up should be portrait 4:3")
testing.expect(t, core.get_image_size_for_shot_type(.Extreme_Close_Up) == .Square_HD, "extreme-close-up should be square_hd")
testing.expect(t, core.get_image_size_for_shot_type(.Aerial) == .Landscape_16_9, "aerial should be 16:9")
}
@test
core_sdxl_dimensions :: proc(t: ^testing.T) {
w, h := adapters.dimensions_from_sdxl_size("landscape_16_9")
testing.expect(t, w == 1344 && h == 768, fmt.tprintf("16:9 should be 1344x768, got %dx%d", w, h))
w2, h2 := adapters.dimensions_from_sdxl_size("square_hd")
testing.expect(t, w2 == 1024 && h2 == 1024, fmt.tprintf("square_hd should be 1024x1024, got %dx%d", w2, h2))
}
@test
core_character_sheet_poses_defined :: proc(t: ^testing.T) {
testing.expect(t, len(adapters.CHARACTER_SHEET_POSES) == 4, "should have 4 sheet poses")
testing.expect(t, adapters.CHARACTER_SHEET_POSES[0].name == "front", "first pose should be front")
testing.expect(t, adapters.CHARACTER_SHEET_POSES[3].name == "back", "last pose should be back")
}
@test
gui_action_generate_character_reference_missing_key :: 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
char := core.Character{id = "char_1", name = "Hero", role = .Protagonist, description = "Main character"}
chars: [dynamic]core.Character
append(&chars, char)
controller.state.characters = chars[:]
msg := gui.action_generate_character_reference(&controller, "char_1")
testing.expect(t, strings.has_prefix(msg, "FAL_API_KEY"), "should report missing FAL key")
}
@test
gui_action_generate_character_sheet_missing_key :: 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)
char := core.Character{id = "char_1", name = "Hero", role = .Protagonist, description = "Main character"}
chars: [dynamic]core.Character
append(&chars, char)
controller.state.characters = chars[:]
msg := gui.action_generate_character_sheet(&controller, "char_1")
testing.expect(t, strings.has_prefix(msg, "FAL_API_KEY"), "should report missing FAL key")
}
@test
gui_action_generate_character_reference_not_found :: 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)
msg := gui.action_generate_character_reference(&controller, "nonexistent")
testing.expect(t, strings.has_prefix(msg, "FAL_API_KEY") || msg == "Character not found", "should report missing key or not found")
}
@test
gui_action_generate_character_sheet_not_found :: 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)
msg := gui.action_generate_character_sheet(&controller, "nonexistent")
testing.expect(t, strings.has_prefix(msg, "FAL_API_KEY") || msg == "Character not found", "should report missing key or not found")
}
@test
fal_negative_prompts_defined :: proc(t: ^testing.T) {
testing.expect(t, len(core.NEGATIVE_PROMPT_CHARACTER) > 0, "character negative prompt should be defined")
testing.expect(t, len(core.NEGATIVE_PROMPT_PANEL) > 0, "panel negative prompt should be defined")
testing.expect(t, strings.contains(core.NEGATIVE_PROMPT_PANEL, "text"), "panel negative should include text")
testing.expect(t, strings.contains(core.NEGATIVE_PROMPT_PANEL, "speech bubble"), "panel negative should include speech bubble")
}
@test
fal_quality_modifier_defined :: proc(t: ^testing.T) {
testing.expect(t, len(core.QUALITY_MODIFIER) > 0, "quality modifier should be defined")
testing.expect(t, strings.contains(core.QUALITY_MODIFIER, "high quality"), "should include quality terms")
}