返回 DeepSeek-Reasonix
collect_v1_test.go
根目录 / internal / capdiag / collect_v1_test.go
1 package capdiag_test
2
3 import (
4 "encoding/json"
5 "path/filepath"
6 "strings"
7 "testing"
8
9 "reasonix/internal/capdiag"
10 "reasonix/internal/pluginpkg"
11 )
12
13 // TestPluginPackageV1FieldsAreReported pins the Manifest v1 additions to the
14 // plugins report: prompts/themes counts and the runtime flag, in both the
15 // JSON payload and the text renderer.
16 func TestPluginPackageV1FieldsAreReported(t *testing.T) {
17 root := t.TempDir()
18 home := t.TempDir()
19 reasonixHome := filepath.Join(home, ".reasonix")
20 t.Setenv("HOME", home)
21 t.Setenv("REASONIX_HOME", reasonixHome)
22
23 pluginRoot := filepath.Join(reasonixHome, "plugins", "demo")
24 write(t, filepath.Join(pluginRoot, pluginpkg.NativeManifest), `{
25 "apiVersion": "reasonix.io/plugin/v1",
26 "name": "demo",
27 "contributes": {
28 "prompts": ["prompts"],
29 "themes": ["themes/*.reasonix-theme"]
30 },
31 "runtime": {"command": "${REASONIX_PLUGIN_ROOT}/bin/demo", "intercepts": ["input.receive"]}
32 }`)
33 write(t, filepath.Join(pluginRoot, "prompts", "plan.md"), "---\ndescription: plan\n---\nPlan $ARGUMENTS\n")
34 write(t, filepath.Join(pluginRoot, "themes", "neon.reasonix-theme"), "theme bytes")
35 write(t, filepath.Join(pluginRoot, "bin", "demo"), "#!/bin/sh\n")
36 if err := pluginpkg.Upsert(reasonixHome, pluginpkg.InstalledPlugin{
37 Name: "demo", Root: "plugins/demo", ManifestKind: "reasonix", Enabled: true,
38 }); err != nil {
39 t.Fatal(err)
40 }
41
42 r := capdiag.Collect(capdiag.Options{
43 Root: root, HomeDir: home, ReasonixHomeDir: reasonixHome,
44 })
45 if len(r.Plugins.Packages) != 1 {
46 t.Fatalf("plugin packages = %+v, want demo", r.Plugins.Packages)
47 }
48 pkg := r.Plugins.Packages[0]
49 if pkg.Prompts != 1 || pkg.Themes != 1 || !pkg.Runtime {
50 t.Fatalf("package v1 fields = prompts:%d themes:%d runtime:%v, want 1/1/true", pkg.Prompts, pkg.Themes, pkg.Runtime)
51 }
52 if r.SchemaVersion != 1 {
53 t.Fatalf("SchemaVersion = %d, want the unchanged schema v1", r.SchemaVersion)
54 }
55 text := capdiag.RenderText(r)
56 for _, want := range []string{"prompts=1", "themes=1", "FULL TRUST"} {
57 if !strings.Contains(text, want) {
58 t.Fatalf("text report missing %q:\n%s", want, text)
59 }
60 }
61
62 raw, err := json.Marshal(pkg)
63 if err != nil {
64 t.Fatal(err)
65 }
66 for _, key := range []string{`"prompts":1`, `"themes":1`, `"runtime":true`} {
67 if !strings.Contains(string(raw), key) {
68 t.Fatalf("package JSON missing %s: %s", key, raw)
69 }
70 }
71 }
72
73 // TestPluginPackageLegacyOmitsV1Fields pins the omitempty contract: legacy
74 // packages produce no new JSON keys, so schema v1 consumers see no change.
75 func TestPluginPackageLegacyOmitsV1Fields(t *testing.T) {
76 root := t.TempDir()
77 home := t.TempDir()
78 reasonixHome := filepath.Join(home, ".reasonix")
79 t.Setenv("HOME", home)
80 t.Setenv("REASONIX_HOME", reasonixHome)
81
82 pluginRoot := filepath.Join(reasonixHome, "plugins", "legacy")
83 write(t, filepath.Join(pluginRoot, pluginpkg.NativeManifest), `{"name":"legacy","skills":["skills"]}`)
84 write(t, filepath.Join(pluginRoot, "skills", "s", "SKILL.md"), "---\ndescription: s\n---\nS\n")
85 if err := pluginpkg.Upsert(reasonixHome, pluginpkg.InstalledPlugin{
86 Name: "legacy", Root: "plugins/legacy", ManifestKind: "reasonix", Enabled: true,
87 }); err != nil {
88 t.Fatal(err)
89 }
90
91 r := capdiag.Collect(capdiag.Options{
92 Root: root, HomeDir: home, ReasonixHomeDir: reasonixHome,
93 })
94 if len(r.Plugins.Packages) != 1 {
95 t.Fatalf("plugin packages = %+v, want legacy", r.Plugins.Packages)
96 }
97 raw, err := json.Marshal(r.Plugins.Packages[0])
98 if err != nil {
99 t.Fatal(err)
100 }
101 for _, key := range []string{`"prompts"`, `"themes"`, `"runtime"`} {
102 if strings.Contains(string(raw), key) {
103 t.Fatalf("legacy package JSON should omit %s: %s", key, raw)
104 }
105 }
106 }
107
107 lines GO