Adds an optional `imagen generate` post-step that opens a sibling tmux window running tmux-img --hold <path>. - internal/preview: Mode (auto|on|off), Resolve, and a Spawner that shells out to tmux new-window. Typed errors for missing tmux, missing tmux-img, and "preview forced on outside $TMUX". - cmd/imagen/generate: --preview / --no-preview flags plus $IMAGEN_PREVIEW. Resolution chain: config -> env -> flag. auto requires both stdout-is-tty and $TMUX. Failures are warnings - the image is already on disk. - internal/config: output.preview field, validated to auto|on|off, threaded into the sample. - Tests for ParseMode, Resolve, Spawn argv (incl. shell quoting of paths with apostrophes), missing-binary errors, and the CLI resolution table. - Docs (usage + architecture) updated. /imagine SKILL.md edit lives in dotfiles - deferred to coordinate with #4.
105 lines
2.6 KiB
Go
105 lines
2.6 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestLoadAndValidate(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "imagen.yaml")
|
|
if err := os.WriteFile(path, []byte(Sample), 0o644); err != nil {
|
|
t.Fatalf("write sample: %v", err)
|
|
}
|
|
cfg, err := Load(path)
|
|
if err != nil {
|
|
t.Fatalf("Load: %v", err)
|
|
}
|
|
if cfg.DefaultBackend != "flux-schnell-local" {
|
|
t.Errorf("default = %q", cfg.DefaultBackend)
|
|
}
|
|
mock, ok := cfg.Backends["mock"]
|
|
if !ok {
|
|
t.Fatalf("mock backend missing")
|
|
}
|
|
if mock.Type != "mock" {
|
|
t.Errorf("mock type = %q", mock.Type)
|
|
}
|
|
flux, ok := cfg.Backends["flux-schnell-local"]
|
|
if !ok {
|
|
t.Fatalf("flux backend missing")
|
|
}
|
|
if flux.Type != "comfyui" {
|
|
t.Errorf("flux type = %q", flux.Type)
|
|
}
|
|
if flux.Raw["base_url"] != "http://mrock:8188" {
|
|
t.Errorf("flux base_url = %v", flux.Raw["base_url"])
|
|
}
|
|
if flux.Raw["model"] != "flux1-schnell.safetensors" {
|
|
t.Errorf("flux model = %v", flux.Raw["model"])
|
|
}
|
|
}
|
|
|
|
func TestValidateRejectsUnknownDefault(t *testing.T) {
|
|
c := &Config{
|
|
DefaultBackend: "ghost",
|
|
Backends: map[string]BackendSpec{"real": {Type: "mock"}},
|
|
}
|
|
if err := c.Validate(); err == nil {
|
|
t.Errorf("expected error for unknown default_backend")
|
|
}
|
|
}
|
|
|
|
func TestValidateRejectsMissingType(t *testing.T) {
|
|
c := &Config{
|
|
Backends: map[string]BackendSpec{"x": {}},
|
|
}
|
|
if err := c.Validate(); err == nil {
|
|
t.Errorf("expected error for missing type")
|
|
}
|
|
}
|
|
|
|
func TestValidatePreviewMode(t *testing.T) {
|
|
for _, mode := range []string{"", "auto", "on", "off"} {
|
|
c := &Config{Output: OutputConfig{Preview: mode}}
|
|
if err := c.Validate(); err != nil {
|
|
t.Errorf("preview=%q: unexpected error %v", mode, err)
|
|
}
|
|
}
|
|
bad := &Config{Output: OutputConfig{Preview: "yes"}}
|
|
if err := bad.Validate(); err == nil {
|
|
t.Errorf("expected error for invalid preview value")
|
|
}
|
|
}
|
|
|
|
func TestSampleParsesPreviewAuto(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "imagen.yaml")
|
|
if err := os.WriteFile(path, []byte(Sample), 0o644); err != nil {
|
|
t.Fatalf("write sample: %v", err)
|
|
}
|
|
cfg, err := Load(path)
|
|
if err != nil {
|
|
t.Fatalf("Load: %v", err)
|
|
}
|
|
if cfg.Output.Preview != "auto" {
|
|
t.Errorf("Output.Preview = %q, want auto", cfg.Output.Preview)
|
|
}
|
|
}
|
|
|
|
func TestExpandPath(t *testing.T) {
|
|
home, _ := os.UserHomeDir()
|
|
cases := map[string]string{
|
|
"": "",
|
|
"/abs/path": "/abs/path",
|
|
"~": home,
|
|
"~/foo/bar": filepath.Join(home, "foo/bar"),
|
|
}
|
|
for in, want := range cases {
|
|
if got := ExpandPath(in); got != want {
|
|
t.Errorf("ExpandPath(%q) = %q, want %q", in, got, want)
|
|
}
|
|
}
|
|
}
|