Files
notarius/internal/framework/promptfs/prompt_fs_test.go

188 lines
7.1 KiB
Go

package promptfs
import (
"io/fs"
"strings"
"testing"
"testing/fstest"
)
func TestModulePromptFSCombinesModuleAndSharedPrompts(t *testing.T) {
sharedFS := fstest.MapFS{
"shared/system.md": {Data: []byte("system")},
"shared/reference.md": {Data: []byte("reference")},
"nested/transcript.md": {Data: []byte("transcript")},
}
fsys, err := ModulePromptFS("module.test", fstest.MapFS{
"assets/prompts/module.test.yaml": {Data: []byte("id: module.test")},
"assets/prompts/task.md": {Data: []byte("task")},
}, []ModulePromptFile{
{Name: "module.test.yaml", Path: "assets/prompts/module.test.yaml"},
{Name: "task.md", Path: "assets/prompts/task.md"},
},
SharedPromptFile{Name: "system.md", FS: sharedFS, Path: "shared/system.md"},
SharedPromptFile{Name: "reference.md", FS: sharedFS, Path: "shared/reference.md"},
SharedPromptFile{Name: "transcript.md", FS: sharedFS, Path: "nested/transcript.md"},
)
if err != nil {
t.Fatalf("ModulePromptFS() error = %v, want nil", err)
}
tests := map[string]string{
"assets/prompts/module.test/module.test.yaml": "id: module.test",
"assets/prompts/module.test/task.md": "task",
"assets/prompts/module.test/sharedassets/system.md": "system",
"assets/prompts/module.test/sharedassets/reference.md": "reference",
"assets/prompts/module.test/sharedassets/transcript.md": "transcript",
}
for path, want := range tests {
data, err := fs.ReadFile(fsys, path)
if err != nil {
t.Fatalf("ReadFile(%q) error = %v, want nil", path, err)
}
if string(data) != want {
t.Fatalf("ReadFile(%q) = %q, want %q", path, data, want)
}
}
entries, err := fs.ReadDir(fsys, ".")
if err != nil {
t.Fatalf("ReadDir(.) error = %v, want nil", err)
}
if len(entries) != 1 || entries[0].Name() != "assets" || !entries[0].IsDir() {
t.Fatalf("ReadDir(.) = %#v, want assets directory", entries)
}
entries, err = fs.ReadDir(fsys, "assets/prompts/module.test/sharedassets")
if err != nil {
t.Fatalf("ReadDir(sharedassets) error = %v, want nil", err)
}
if len(entries) != 3 || entries[0].Name() != "reference.md" || entries[1].Name() != "system.md" || entries[2].Name() != "transcript.md" {
t.Fatalf("ReadDir(sharedassets) = %#v, want sorted shared prompt entries", entries)
}
}
func TestModulePromptFSRejectsMissingModuleFile(t *testing.T) {
_, err := ModulePromptFS("module.test", fstest.MapFS{}, []ModulePromptFile{
{Name: "task.md", Path: "assets/prompts/task.md"},
})
if err == nil || !strings.Contains(err.Error(), "read module prompt asset assets/prompts/task.md") {
t.Fatalf("ModulePromptFS() error = %v, want missing module asset context", err)
}
}
func TestModulePromptFSRejectsMissingSharedFile(t *testing.T) {
_, err := ModulePromptFS("module.test", fstest.MapFS{
"assets/prompts/task.md": {Data: []byte("task")},
}, []ModulePromptFile{
{Name: "task.md", Path: "assets/prompts/task.md"},
}, SharedPromptFile{Name: "system.md", FS: fstest.MapFS{}, Path: "shared/system.md"})
if err == nil || !strings.Contains(err.Error(), "read shared prompt asset shared/system.md") {
t.Fatalf("ModulePromptFS() error = %v, want missing shared asset context", err)
}
}
func TestModulePromptFSRejectsNestedVirtualFileName(t *testing.T) {
_, err := ModulePromptFS("module.test", fstest.MapFS{
"assets/prompts/task.md": {Data: []byte("task")},
}, []ModulePromptFile{
{Name: "nested/task.md", Path: "assets/prompts/task.md"},
})
if err == nil || !strings.Contains(err.Error(), "must not contain path separators") {
t.Fatalf("ModulePromptFS() error = %v, want nested file name error", err)
}
}
func TestModulePromptFSRejectsNestedSharedFileName(t *testing.T) {
_, err := ModulePromptFS("module.test", fstest.MapFS{
"assets/prompts/task.md": {Data: []byte("task")},
}, []ModulePromptFile{
{Name: "task.md", Path: "assets/prompts/task.md"},
}, SharedPromptFile{Name: "nested/system.md", FS: fstest.MapFS{}, Path: "shared/system.md"})
if err == nil || !strings.Contains(err.Error(), "shared prompt file name") || !strings.Contains(err.Error(), "must not contain path separators") {
t.Fatalf("ModulePromptFS() error = %v, want nested shared file name error", err)
}
}
func TestModulePromptFSRejectsDuplicateNormalizedDestinations(t *testing.T) {
for _, test := range []struct {
name string
call func() error
want string
}{
{
name: "module",
call: func() error {
_, err := ModulePromptFS("module.test", fstest.MapFS{
"assets/prompts/first.md": {Data: []byte("first")},
"assets/prompts/second.md": {Data: []byte("second")},
}, []ModulePromptFile{
{Name: "task.md", Path: "assets/prompts/first.md"},
{Name: " task.md ", Path: "assets/prompts/second.md"},
})
return err
},
want: `duplicate module prompt destination "assets/prompts/module.test/task.md"`,
},
{
name: "sharedassets",
call: func() error {
shared := fstest.MapFS{
"shared/first.md": {Data: []byte("first")},
"shared/second.md": {Data: []byte("second")},
}
_, err := ModulePromptFS("module.test", fstest.MapFS{}, nil,
SharedPromptFile{Name: "task.md", FS: shared, Path: "shared/first.md"},
SharedPromptFile{Name: " task.md ", FS: shared, Path: "shared/second.md"},
)
return err
},
want: `duplicate sharedassets prompt destination "assets/prompts/module.test/sharedassets/task.md"`,
},
} {
t.Run(test.name, func(t *testing.T) {
if err := test.call(); err == nil || err.Error() != test.want {
t.Fatalf("ModulePromptFS() error = %v, want %q", err, test.want)
}
})
}
}
func TestModulePromptFSAllowsMatchingModuleAndSharedBasenames(t *testing.T) {
fsys, err := ModulePromptFS("module.test", fstest.MapFS{
"assets/prompts/system.md": {Data: []byte("module")},
}, []ModulePromptFile{{Name: "system.md", Path: "assets/prompts/system.md"}},
SharedPromptFile{Name: "system.md", FS: fstest.MapFS{"shared/system.md": {Data: []byte("shared")}}, Path: "shared/system.md"},
)
if err != nil {
t.Fatal(err)
}
for name, want := range map[string]string{
"assets/prompts/module.test/system.md": "module",
"assets/prompts/module.test/sharedassets/system.md": "shared",
} {
data, err := fs.ReadFile(fsys, name)
if err != nil || string(data) != want {
t.Fatalf("ReadFile(%q) = %q, %v; want %q", name, data, err, want)
}
}
}
func TestModulePromptFSRejectsInvalidModuleDir(t *testing.T) {
_, err := ModulePromptFS(".", fstest.MapFS{}, nil)
if err == nil || !strings.Contains(err.Error(), "module prompt directory") {
t.Fatalf("ModulePromptFS() error = %v, want module directory context", err)
}
}
func TestModulePromptFSRejectsNilFilesystems(t *testing.T) {
_, err := ModulePromptFS("module.test", nil, nil)
if err == nil || !strings.Contains(err.Error(), "module prompt filesystem must not be nil") {
t.Fatalf("ModulePromptFS() error = %v, want nil module filesystem error", err)
}
_, err = ModulePromptFS("module.test", fstest.MapFS{}, nil, SharedPromptFile{Name: "system.md", Path: "shared/system.md"})
if err == nil || !strings.Contains(err.Error(), "shared prompt file \"system.md\" filesystem must not be nil") {
t.Fatalf("ModulePromptFS() error = %v, want nil shared filesystem error", err)
}
}