返回 DeepSeek-Reasonix
outputstyle_test.go
根目录 / internal / outputstyle / outputstyle_test.go
1 package outputstyle
2
3 import (
4 "os"
5 "path/filepath"
6 "strings"
7 "testing"
8
9 fileencoding "reasonix/internal/fileutil/encoding"
10 )
11
12 func TestResolveBuiltin(t *testing.T) {
13 st, ok := Resolve("explanatory", nil)
14 if !ok {
15 t.Fatal("explanatory built-in should resolve")
16 }
17 if !st.Builtin || !st.KeepCoding || strings.TrimSpace(st.Body) == "" {
18 t.Errorf("unexpected built-in shape: %+v", st)
19 }
20 // Case-insensitive.
21 if _, ok := Resolve("LEARNING", nil); !ok {
22 t.Error("resolve should be case-insensitive")
23 }
24 }
25
26 func TestResolveDefaultIsNone(t *testing.T) {
27 for _, name := range []string{"", " ", "default"} {
28 if _, ok := Resolve(name, nil); ok {
29 t.Errorf("Resolve(%q) should be no-style", name)
30 }
31 }
32 }
33
34 func TestApply(t *testing.T) {
35 append1 := Apply("BASE", OutputStyle{Body: "X", KeepCoding: true})
36 if append1 != "BASE\n\nX" {
37 t.Errorf("keep-coding append = %q", append1)
38 }
39 replace := Apply("BASE", OutputStyle{Body: "X", KeepCoding: false})
40 if replace != "X" {
41 t.Errorf("replace = %q, want X", replace)
42 }
43 if got := Apply("BASE", OutputStyle{Body: " "}); got != "BASE" {
44 t.Errorf("empty body should leave base untouched, got %q", got)
45 }
46 }
47
48 func TestListIncludesBuiltinsSorted(t *testing.T) {
49 got := List(nil)
50 if len(got) < 3 {
51 t.Fatalf("expected at least the 3 built-ins, got %d", len(got))
52 }
53 for i := 1; i < len(got); i++ {
54 if got[i-1].Name > got[i].Name {
55 t.Errorf("not sorted by name: %q before %q", got[i-1].Name, got[i].Name)
56 }
57 }
58 }
59
60 func TestCustomFileOverridesBuiltinAndParses(t *testing.T) {
61 dir := t.TempDir()
62 // Override the built-in "explanatory" with a custom replace-style file.
63 md := "---\ndescription: my persona\nkeep-coding-instructions: false\n---\nYou are a pirate. Answer in pirate speak.\n"
64 if err := os.WriteFile(filepath.Join(dir, "explanatory.md"), []byte(md), 0o644); err != nil {
65 t.Fatal(err)
66 }
67
68 st, ok := Resolve("explanatory", []string{dir})
69 if !ok {
70 t.Fatal("custom explanatory should resolve")
71 }
72 if st.Builtin {
73 t.Error("custom file should override the built-in (Builtin=false)")
74 }
75 if st.KeepCoding {
76 t.Error("keep-coding-instructions: false should disable KeepCoding")
77 }
78 if st.Description != "my persona" || !strings.Contains(st.Body, "pirate") {
79 t.Errorf("frontmatter/body not parsed: %+v", st)
80 }
81 if got := Apply("CODING PROMPT", st); got != st.Body {
82 t.Errorf("a replace-style should drop the base prompt, got %q", got)
83 }
84 }
85
86 func TestResolveDecodesGB18030CustomFile(t *testing.T) {
87 dir := t.TempDir()
88 body := "---\nname: concise-cn\ndescription: 中文风格\n---\n请用中文简洁回答。"
89 if err := os.WriteFile(filepath.Join(dir, "concise-cn.md"), fileencoding.Encode(body, fileencoding.GB18030), 0o644); err != nil {
90 t.Fatal(err)
91 }
92
93 st, ok := Resolve("concise-cn", []string{dir})
94 if !ok {
95 t.Fatal("custom style should resolve")
96 }
97 if st.Description != "中文风格" || st.Body != "请用中文简洁回答。" {
98 t.Fatalf("decoded style = %+v", st)
99 }
100 }
101
102 func TestParseFileNameFromFilename(t *testing.T) {
103 dir := t.TempDir()
104 if err := os.WriteFile(filepath.Join(dir, "snappy.md"), []byte("Be snappy."), 0o644); err != nil {
105 t.Fatal(err)
106 }
107 st, ok := Resolve("snappy", []string{dir})
108 if !ok || st.Name != "snappy" || !st.KeepCoding { // default keep-coding when unspecified
109 t.Errorf("filename-derived style wrong: %+v ok=%v", st, ok)
110 }
111 }
112
112 lines GO