104 lines
3.9 KiB
Odin
104 lines
3.9 KiB
Odin
package tests
|
|
|
|
import "core:testing"
|
|
import "../src/adapters"
|
|
import "../src/core"
|
|
import "../src/shared"
|
|
|
|
deepseek_calls: int
|
|
|
|
phase2_deepseek_transport :: proc(cfg: shared.Config, request_json: string) -> (string, int, shared.App_Error) {
|
|
_ = cfg
|
|
_ = request_json
|
|
deepseek_calls += 1
|
|
if deepseek_calls == 1 {
|
|
return "", 429, shared.ok()
|
|
}
|
|
return "{\"choices\":[{\"message\":{\"content\":\"{\\\"title\\\":\\\"Test\\\",\\\"synopsis\\\":\\\"A hero rises\\\",\\\"characters\\\":[{\\\"id\\\":\\\"char_001\\\",\\\"name\\\":\\\"Hero\\\",\\\"role\\\":\\\"protagonist\\\",\\\"description\\\":\\\"Determined\\\",\\\"firstAppearancePanel\\\":\\\"panel_001_001\\\"}],\\\"pages\\\":[{\\\"pageNumber\\\":1,\\\"layoutType\\\":\\\"grid\\\",\\\"panels\\\":[{\\\"panelId\\\":\\\"panel_001_001\\\",\\\"panelNumber\\\":1,\\\"shotType\\\":\\\"medium\\\",\\\"description\\\":\\\"Hero stands\\\",\\\"charactersPresent\\\":[\\\"char_001\\\"],\\\"dialogue\\\":[{\\\"speakerId\\\":\\\"char_001\\\",\\\"text\\\":\\\"Let's go!\\\",\\\"bubbleType\\\":\\\"normal\\\",\\\"emotion\\\":\\\"determined\\\"}],\\\"caption\\\":\\\"\\\",\\\"soundEffects\\\":[],\\\"transitionFromPrevious\\\":\\\"none\\\"}]}]}\"}}]}", 200, shared.ok()
|
|
}
|
|
|
|
fal_calls: int
|
|
|
|
phase2_fal_transport :: proc(cfg: shared.Config, endpoint, prompt: string, seed: i64) -> (string, int, shared.App_Error) {
|
|
_ = cfg
|
|
_ = endpoint
|
|
_ = prompt
|
|
_ = seed
|
|
fal_calls += 1
|
|
if fal_calls == 1 {
|
|
return "", 0, shared.network_error("temporary network issue")
|
|
}
|
|
return "https://example.com/image.png", 200, shared.ok()
|
|
}
|
|
|
|
@test
|
|
deepseek_retries_then_succeeds :: proc(t: ^testing.T) {
|
|
deepseek_calls = 0
|
|
|
|
cfg := shared.Config{
|
|
deepseek_api_key = "test-key",
|
|
deepseek_base_url = "https://api.deepseek.com",
|
|
}
|
|
client := adapters.new_deepseek_client()
|
|
client.transport = phase2_deepseek_transport
|
|
client.max_retries = 3
|
|
|
|
opts := adapters.Generate_Script_Options{
|
|
story_idea = "A hero rises",
|
|
genre = "action",
|
|
art_style = "manga",
|
|
num_pages = 4,
|
|
audience = "general",
|
|
}
|
|
|
|
script, err := adapters.generate_comic_script(client, cfg, opts)
|
|
defer core.dispose_script_owned(&script)
|
|
testing.expect(t, shared.is_ok(err), "deepseek request should eventually succeed")
|
|
testing.expect(t, deepseek_calls == 2, "expected one retry before success")
|
|
testing.expect(t, len(script.pages) > 0, "generated script should contain pages")
|
|
}
|
|
|
|
@test
|
|
fal_queue_enforces_cap :: proc(t: ^testing.T) {
|
|
q := adapters.new_fal_queue(1)
|
|
|
|
first := adapters.try_acquire_slot(&q)
|
|
second := adapters.try_acquire_slot(&q)
|
|
adapters.release_slot(&q)
|
|
third := adapters.try_acquire_slot(&q)
|
|
|
|
testing.expect(t, first, "first slot acquisition should succeed")
|
|
testing.expect(t, !second, "second slot acquisition should fail when saturated")
|
|
testing.expect(t, third, "slot acquisition should succeed after release")
|
|
}
|
|
|
|
@test
|
|
fal_panel_generation_retries_network_error :: proc(t: ^testing.T) {
|
|
fal_calls = 0
|
|
|
|
cfg := shared.Config{fal_api_key = "test-key"}
|
|
q := adapters.new_fal_queue(2)
|
|
client := adapters.new_fal_client(&q)
|
|
client.transport = phase2_fal_transport
|
|
client.max_retries = 3
|
|
|
|
panel := core.Panel{panel_id = "panel_1", panel_number = 1, description = "Hero jumps over a gap"}
|
|
img, err := adapters.generate_panel_image(client, cfg, panel, nil, "manga", "proj_1")
|
|
defer delete(img.prompt)
|
|
|
|
testing.expect(t, shared.is_ok(err), "fal panel generation should eventually succeed")
|
|
testing.expect(t, fal_calls == 2, "expected one retry for network error")
|
|
testing.expect(t, len(img.url) > 0, "image url should be set")
|
|
}
|
|
|
|
@test
|
|
fal_typed_response_parsing :: proc(t: ^testing.T) {
|
|
body := "{\"images\":[{\"url\":\"https://example.com/a.png\",\"width\":1024,\"height\":1024}]}"
|
|
resp, err := adapters.fal_parse_response_body(body)
|
|
defer adapters.dispose_fal_response(&resp)
|
|
|
|
testing.expect(t, shared.is_ok(err), "typed parse should succeed")
|
|
testing.expect(t, len(resp.images) == 1, "expected one image")
|
|
testing.expect(t, resp.images[0].url == "https://example.com/a.png", "expected parsed URL")
|
|
}
|