First step of the model-agnostic image-generation framework. Lands the
plumbing other components (skill, ComfyUI/Replicate adapters, agents)
will plug into:
- internal/backend: Backend interface (Request/Result), thread-safe
Registry with init-time Register, plus a Mock reference adapter that
emits a deterministic gradient PNG for smoke tests.
- internal/config: YAML loader for ~/.config/imagen.yaml. Framework owns
default_backend + output settings + a per-backend block; each adapter
owns the schema below its own block via BackendSpec.Raw.
- internal/output: filename templating ({date}/{time}/{slug}/{seed}/
{backend}/{ext}), JSON metadata sidecar, --output override path.
- internal/prompt: embedded styles.yaml, style-preset suffix application.
- internal/server: 501 stub — HTTP surface lands in a follow-up issue.
- cmd/imagen: generate / backends / config (init|validate|path) / serve
/ version subcommands. Stdlib-only flag parsing with a small helper to
honour positional prompt args ahead of flags (matches the issue spec).
- Tests for output (slug, naming template, sidecar), backend (mock PNG
validity + determinism, registry build + duplicate panic), config
(round-trip + validation), prompt (style apply + unknown-style error).
- CLAUDE.md, README.md, docs/architecture.md, docs/usage.md, Makefile.
Acceptance criteria from #211:
1. go build ./... — clean
2. imagen backends — lists registered backends, exits 0
3. imagen generate "test prompt" --backend mock --output /tmp/x.png —
writes a 1024x1024 PNG plus an x.png.json sidecar
4. imagen config init | imagen config validate — round-trips cleanly
5. CLAUDE.md "Adding a new adapter" — six-step recipe
51 lines
1.1 KiB
Go
51 lines
1.1 KiB
Go
package prompt
|
|
|
|
import "testing"
|
|
|
|
func TestApplyKnownStyle(t *testing.T) {
|
|
got, err := Apply("a cat", "photo")
|
|
if err != nil {
|
|
t.Fatalf("Apply: %v", err)
|
|
}
|
|
want := "a cat, photorealistic, sharp focus, natural lighting"
|
|
if got != want {
|
|
t.Errorf("got %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestApplyEmptyStylePassThrough(t *testing.T) {
|
|
got, err := Apply("a cat", "")
|
|
if err != nil || got != "a cat" {
|
|
t.Errorf("got (%q,%v)", got, err)
|
|
}
|
|
}
|
|
|
|
func TestApplyUnknownStyleErrors(t *testing.T) {
|
|
if _, err := Apply("a cat", "nonsense"); err == nil {
|
|
t.Errorf("expected error for unknown style")
|
|
}
|
|
}
|
|
|
|
func TestApplyToEmptyPromptUsesPresetOnly(t *testing.T) {
|
|
got, err := Apply("", "photo")
|
|
if err != nil {
|
|
t.Fatalf("Apply: %v", err)
|
|
}
|
|
if got == "" || got[0] == ',' {
|
|
t.Errorf("unexpected output %q", got)
|
|
}
|
|
}
|
|
|
|
func TestStylesContainsAllExpected(t *testing.T) {
|
|
want := []string{"blog-header", "diagram", "illustration", "photo", "sketch"}
|
|
got := Styles()
|
|
if len(got) != len(want) {
|
|
t.Fatalf("Styles() = %v, want %v", got, want)
|
|
}
|
|
for i, w := range want {
|
|
if got[i] != w {
|
|
t.Errorf("Styles()[%d] = %q, want %q", i, got[i], w)
|
|
}
|
|
}
|
|
}
|