Ctrl K
ComunidadGuías…

internal/autogen/categoryroots_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package autogen

import (
	"os"
	"path/filepath"
	"regexp"
	"slices"
	"testing"
)

// Platform-neutral half: order, blank-dropping, and exact-duplicate collapse.
// Whether a *differently cased* root is a duplicate depends on the filesystem,
// so that lives in categoryroots_{windows,posix}_test.go.
func TestSettings_RootList_orderAndDedup(t *testing.T) {
	s := Settings{
		ModelsRoot: `/srv/Models`,
		CategoryRoots: map[string]string{
			"image":      `/srv/Image`,
			"tts":        ``,            // blank dropped
			"transcribe": `/srv/Models`, // exact dup of ModelsRoot
		},
	}
	got := s.RootList()
	want := []string{`/srv/Models`, `/srv/Image`}
	if len(got) != len(want) {
		t.Fatalf("RootList = %v, want %v", got, want)
	}
	for i := range want {
		if got[i] != want[i] {
			t.Fatalf("RootList[%d] = %q, want %q (full %v)", i, got[i], want[i], got)
		}
	}
}

func TestUpsertSidecarRoot_setAndClear(t *testing.T) {
	dir := t.TempDir()
	gen := filepath.Join(dir, "generate.yaml")
	if err := os.WriteFile(gen, []byte("settings:\n  modelsRoot: E:/Models\n"), 0o644); err != nil {
		t.Fatal(err)
	}

	if _, err := UpsertSidecarRoot(gen, "image", `E:\Image`); err != nil {
		t.Fatal(err)
	}
	roots, err := LoadSidecarCategoryRoots(gen)
	if err != nil {
		t.Fatal(err)
	}
	if roots["image"] != `E:\Image` {
		t.Fatalf("after set: roots = %v", roots)
	}

	// It must surface through the merged generate file too.
	gf, err := LoadGenerateFile(gen, "")
	if err != nil {
		t.Fatal(err)
	}
	if gf.Settings.CategoryRoots["image"] != `E:\Image` {
		t.Fatalf("merged settings missing root: %v", gf.Settings.CategoryRoots)
	}

	// Clearing (path "") removes the key.
	if _, err := UpsertSidecarRoot(gen, "image", ""); err != nil {
		t.Fatal(err)
	}
	roots, _ = LoadSidecarCategoryRoots(gen)
	if _, ok := roots["image"]; ok {
		t.Fatalf("after clear: key still present: %v", roots)
	}
}

// Every UI tab must be walkable. The Models tab renders its folder picker on
// all of them, so a category absent from CategoryOrder is a root the user can
// set and see and that is then never scanned.
func TestSettings_RootList_coversEveryUICategory(t *testing.T) {
	roots := map[string]string{}
	for _, c := range CategoryOrder {
		roots[c] = `/srv/` + c
	}
	s := Settings{ModelsRoot: `/srv/Models`, CategoryRoots: roots}
	got := s.RootList()
	if len(got) != len(CategoryOrder)+1 {
		t.Fatalf("RootList = %v, want %d entries", got, len(CategoryOrder)+1)
	}
	for i, c := range CategoryOrder {
		if want := `/srv/` + c; got[i+1] != want {
			t.Errorf("RootList[%d] = %q, want %q", i+1, got[i+1], want)
		}
	}
}

// CategoryOrder is the server-side mirror of MODEL_CATEGORIES in the dashboard;
// the pick endpoint rejects anything not in it, so a new UI tab that forgets to
// add itself here would 400 instead of working. Read the real file so the two
// lists cannot drift silently.
func TestCategoryOrder_matchesUITabs(t *testing.T) {
	const uiFile = "../../ui-svelte/src/lib/modelUtils.ts"
	src, err := os.ReadFile(uiFile)
	if err != nil {
		t.Skipf("ui sources unavailable: %v", err)
	}
	block := regexp.MustCompile(`(?s)MODEL_CATEGORIES[^=]*=\s*\[(.*?)\]`).FindSubmatch(src)
	if block == nil {
		t.Fatalf("could not find MODEL_CATEGORIES in %s", uiFile)
	}
	var ui []string
	for _, m := range regexp.MustCompile(`id:\s*"([^"]+)"`).FindAllSubmatch(block[1], -1) {
		ui = append(ui, string(m[1]))
	}
	if len(ui) == 0 {
		t.Fatalf("parsed no category ids from %s", uiFile)
	}
	if !slices.Equal(ui, CategoryOrder) {
		t.Fatalf("CategoryOrder = %v, UI MODEL_CATEGORIES = %v (keep them in sync)", CategoryOrder, ui)
	}
}

func TestIsCategory(t *testing.T) {
	for _, c := range CategoryOrder {
		if !IsCategory(c) {
			t.Errorf("IsCategory(%q) = false, want true", c)
		}
	}
	for _, c := range []string{"", "LLM", "audio", "../etc"} {
		if IsCategory(c) {
			t.Errorf("IsCategory(%q) = true, want false", c)
		}
	}
}