summaryrefslogtreecommitdiff
path: root/internal/comic
diff options
context:
space:
mode:
Diffstat (limited to 'internal/comic')
-rw-r--r--internal/comic/artist.go2
-rw-r--r--internal/comic/comic_test.go71
-rw-r--r--internal/comic/runner.go3
3 files changed, 75 insertions, 1 deletions
diff --git a/internal/comic/artist.go b/internal/comic/artist.go
index 7ccf084..e1717d3 100644
--- a/internal/comic/artist.go
+++ b/internal/comic/artist.go
@@ -218,7 +218,7 @@ func (a *Artist) generatePromptImage(ctx context.Context, prompt, outputFile str
if err != nil {
return fmt.Errorf("render manual prompt: %w", err)
}
- return a.generateWithRetryAndValidation(ctx, renderedPrompt, outputFile, "manual prompt image", nil, nil)
+ return a.generateWithRetryAndValidation(ctx, renderedPrompt, outputFile, "manual prompt image", nil, validateImagePromptLeakageFn)
}
type imageOutputValidator func(context.Context, string, string, string) error
diff --git a/internal/comic/comic_test.go b/internal/comic/comic_test.go
index 866df64..65343e6 100644
--- a/internal/comic/comic_test.go
+++ b/internal/comic/comic_test.go
@@ -373,6 +373,12 @@ func TestDrawComicPagesReturnsErrorWhenRenderFails(t *testing.T) {
func TestArtistAndRunnerEndToEndWithFakes(t *testing.T) {
t.Parallel()
+ originalSleep := sleep
+ sleep = func(time.Duration) {}
+ t.Cleanup(func() {
+ sleep = originalSleep
+ })
+
originalLeakValidation := validateImagePromptLeakageFn
validateImagePromptLeakageFn = func(context.Context, string, string, string) error { return nil }
t.Cleanup(func() {
@@ -471,6 +477,50 @@ func TestRunnerRunPromptWritesSingleAsset(t *testing.T) {
}
}
+func TestRunnerRunPromptValidatesImageOutput(t *testing.T) {
+ originalLeakValidation := validateImagePromptLeakageFn
+ defer func() {
+ validateImagePromptLeakageFn = originalLeakValidation
+ }()
+
+ var calls int
+ var gotLabel string
+ var gotScript string
+ validateImagePromptLeakageFn = func(_ context.Context, outputFile, label, script string) error {
+ calls++
+ if outputFile == "" {
+ t.Fatal("validator received empty output file")
+ }
+ gotLabel = label
+ gotScript = script
+ return nil
+ }
+
+ tmpDir := t.TempDir()
+ runner := NewRunner(&RunnerConfig{
+ ImageProvider: fakeImageProvider{t: t},
+ Prompts: fakePromptRenderer{},
+ OutputDir: tmpDir,
+ Slug: "manual-robot",
+ UltraRealistic: boolPtr(false),
+ PageMaxRetries: 1,
+ PageRetryBase: time.Second,
+ })
+
+ if err := runner.RunPrompt(context.Background(), "a robot reading a newspaper"); err != nil {
+ t.Fatalf("RunPrompt() error = %v", err)
+ }
+ if calls != 1 {
+ t.Fatalf("validator calls = %d, want 1", calls)
+ }
+ if gotLabel != "manual prompt image" {
+ t.Fatalf("validator label = %q, want %q", gotLabel, "manual prompt image")
+ }
+ if gotScript == "" {
+ t.Fatal("validator script was empty")
+ }
+}
+
func TestRunnerRunPromptRejectsEmptyPrompt(t *testing.T) {
t.Parallel()
@@ -486,6 +536,27 @@ func TestRunnerRunPromptRejectsEmptyPrompt(t *testing.T) {
}
}
+func TestRunnerRunPromptReturnsErrorWhenPromptRendererMissing(t *testing.T) {
+ runner := NewRunner(&RunnerConfig{
+ ImageProvider: fakeImageProvider{t: t},
+ OutputDir: t.TempDir(),
+ Slug: "manual-robot",
+ UltraRealistic: boolPtr(false),
+ PageMaxRetries: 1,
+ PageRetryBase: time.Second,
+ })
+
+ defer func() {
+ if r := recover(); r != nil {
+ t.Fatalf("RunPrompt() panicked: %v", r)
+ }
+ }()
+
+ if err := runner.RunPrompt(context.Background(), "a robot reading a newspaper"); err == nil {
+ t.Fatal("RunPrompt() error = nil, want readiness failure")
+ }
+}
+
func TestRunnerRunPromptAppliesStyleThemeAndUltraContext(t *testing.T) {
t.Parallel()
diff --git a/internal/comic/runner.go b/internal/comic/runner.go
index a9411ef..a5d89e6 100644
--- a/internal/comic/runner.go
+++ b/internal/comic/runner.go
@@ -200,6 +200,9 @@ func (r *Runner) RunPrompt(ctx context.Context, prompt string) error {
if r.artist == nil {
return fmt.Errorf("runner providers are not configured")
}
+ if err := r.artist.ready(); err != nil {
+ return err
+ }
if ctx == nil {
ctx = context.Background()
}