Files
Felix-Ayush 2479884dea feat(plugins): add zero plugins info command (#773)
* feat(plugins): add zero plugins info command

Add plugins info to inspect manifest state, extension counts, and
lockfile source/hash with optional hash drift detection.

* fix(plugins): derive lock dir from plugin install path for info

Remove LockDir from InfoOptions and read the lockfile from
filepath.Dir(plugin.PluginDir) so lock metadata matches the resolved
plugin location. Consolidate duplicate lock hash output lines.
2026-07-22 08:14:00 +08:00

70 lines
1.8 KiB
Go

package plugins
import (
"os"
"path/filepath"
"testing"
)
func TestInfoReturnsLockMetadataAndHashDrift(t *testing.T) {
dir := t.TempDir()
userRoot := filepath.Join(dir, "user")
pluginDir := filepath.Join(userRoot, "zero.demo")
writePluginManifest(t, pluginDir, map[string]any{
"schemaVersion": 1,
"id": "zero.demo",
"name": "Demo",
"version": "1.0.0",
"enabled": true,
"tools": []any{},
})
hash, err := hashTree(pluginDir)
if err != nil {
t.Fatal(err)
}
if err := writeLock(userRoot, map[string]LockEntry{
"zero.demo": {Source: "./demo-src", Hash: hash},
}); err != nil {
t.Fatal(err)
}
info, err := Info(InfoOptions{
LoadOptions: LoadOptions{Roots: []Root{{Source: SourceUser, Path: userRoot}}},
}, "zero.demo")
if err != nil {
t.Fatalf("Info: %v", err)
}
if info.Plugin.ID != "zero.demo" || !info.Plugin.Enabled {
t.Fatalf("plugin = %#v", info.Plugin)
}
if info.LockSource != "./demo-src" || info.LockHash != hash {
t.Fatalf("lock metadata = %#v, want source ./demo-src hash %s", info, hash)
}
if info.HashDrift {
t.Fatal("expected no hash drift before manifest edit")
}
if err := os.WriteFile(filepath.Join(pluginDir, "plugin.json"), []byte(`{"schemaVersion":1,"id":"zero.demo","name":"Demo","version":"1.0.0","enabled":true}`+"\n"), 0o644); err != nil {
t.Fatal(err)
}
info, err = Info(InfoOptions{
LoadOptions: LoadOptions{Roots: []Root{{Source: SourceUser, Path: userRoot}}},
}, "zero.demo")
if err != nil {
t.Fatalf("Info after edit: %v", err)
}
if !info.HashDrift {
t.Fatal("expected hash drift after manifest edit")
}
}
func TestInfoMissingPlugin(t *testing.T) {
_, err := Info(InfoOptions{
LoadOptions: LoadOptions{Roots: []Root{{Source: SourceUser, Path: t.TempDir()}}},
}, "missing")
if err == nil {
t.Fatal("expected missing plugin error")
}
}