Files
HomeAgent/internal/plugin/plugin_test.go

205 lines
5.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package plugin
import (
"testing"
sdk "gitcode.com/JianFeeeee/HomeAgent/internal/sdk"
)
func TestExtractDescription(t *testing.T) {
content := "# Plugin\n\nThis is a test plugin.\nversion: 1.0.0"
desc := extractDescription(content)
if desc != "This is a test plugin." {
t.Errorf("expected 'This is a test plugin.', got %q", desc)
}
}
func TestExtractField(t *testing.T) {
content := "version: 1.0.0\nauthor: test\nio_type: io"
if v := extractField(content, "version"); v != "1.0.0" {
t.Errorf("expected '1.0.0', got %q", v)
}
if v := extractField(content, "author"); v != "test" {
t.Errorf("expected 'test', got %q", v)
}
if v := extractField(content, "io_type"); v != "io" {
t.Errorf("expected 'io', got %q", v)
}
}
func TestExtractFieldCaseInsensitive(t *testing.T) {
content := "Version: 2.0.0"
if v := extractField(content, "version"); v != "2.0.0" {
t.Errorf("expected '2.0.0', got %q", v)
}
}
func TestExtractFieldMissing(t *testing.T) {
if v := extractField("no fields here", "version"); v != "" {
t.Errorf("expected '', got %q", v)
}
}
func TestExtractIOConfigFull(t *testing.T) {
content := `# QQ Plugin
io_type: io
io_input_route: qq
io_output_route: qq
io_output_caps: text,file,image`
cfg := extractIOConfig(content)
if cfg == nil {
t.Fatal("expected IOConfig")
}
if cfg.Type != "io" {
t.Errorf("expected type 'io', got %q", cfg.Type)
}
if cfg.InputRoute != "qq" {
t.Errorf("expected input_route 'qq', got %q", cfg.InputRoute)
}
if cfg.OutputRoute != "qq" {
t.Errorf("expected output_route 'qq', got %q", cfg.OutputRoute)
}
if len(cfg.OutputCaps) != 3 || cfg.OutputCaps[0] != "text" {
t.Errorf("expected caps [text file image], got %v", cfg.OutputCaps)
}
}
func TestExtractIOConfigMinimal(t *testing.T) {
content := `# Plugin
io_type: input`
cfg := extractIOConfig(content)
if cfg == nil {
t.Fatal("expected IOConfig")
}
if cfg.Type != "input" {
t.Errorf("expected 'input', got %q", cfg.Type)
}
if cfg.InputRoute != "" {
t.Errorf("expected empty input_route, got %q", cfg.InputRoute)
}
}
func TestExtractIOConfigNil(t *testing.T) {
cfg := extractIOConfig("# No IO config here")
if cfg != nil {
t.Errorf("expected nil, got %+v", cfg)
}
}
func TestExtractToolDefsBasic(t *testing.T) {
content := `# Plugin
description
## hello_tool
Say hello to someone
- name: The person to greet
## add_numbers
Add two numbers together
- a: First number
- b: Second number`
defs := extractToolDefs(content)
if len(defs) != 2 {
t.Fatalf("expected 2 tools, got %d", len(defs))
}
if defs[0].Name != "hello_tool" {
t.Errorf("expected 'hello_tool', got %q", defs[0].Name)
}
if defs[0].Description != "Say hello to someone" {
t.Errorf("expected 'Say hello to someone', got %q", defs[0].Description)
}
props := defs[0].Parameters["properties"].(map[string]interface{})
if _, ok := props["name"]; !ok {
t.Errorf("expected 'name' parameter")
}
p := props["name"].(map[string]interface{})
if p["description"] != "The person to greet" {
t.Errorf("expected desc 'The person to greet', got %q", p["description"])
}
}
func TestExtractToolDefsToolWithColon(t *testing.T) {
content := `# Plugin
### Tool: my_tool
Do something
- param: Description`
defs := extractToolDefs(content)
if len(defs) != 1 {
t.Fatalf("expected 1 tool, got %d", len(defs))
}
if defs[0].Name != "my_tool" {
t.Errorf("expected 'my_tool', got %q", defs[0].Name)
}
}
func TestExtractToolDefsSkipsNonToolSections(t *testing.T) {
content := `# Plugin
## Usage
This is how to use the plugin
## Examples
Some examples here
## real_tool
This is an actual tool
- param: value`
defs := extractToolDefs(content)
if len(defs) != 1 {
t.Fatalf("expected 1 tool (non-tool sections skipped), got %d", len(defs))
}
if defs[0].Name != "real_tool" {
t.Errorf("expected 'real_tool', got %q", defs[0].Name)
}
}
func TestExtractToolDefsEmpty(t *testing.T) {
defs := extractToolDefs("# Just a title\nNo tools here")
if len(defs) != 0 {
t.Errorf("expected 0 tools, got %d", len(defs))
}
}
func TestExtractToolDefsCodeBlock(t *testing.T) {
content := "# Plugin\n\n## my_tool\nA tool\n- param: desc\n\n```\n## not_a_tool\nThis is inside a code block\n```\n\n## another_tool\nAnother one\n- x: y"
defs := extractToolDefs(content)
if len(defs) != 2 {
t.Fatalf("expected 2 tools (code block skipped), got %d", len(defs))
}
if defs[0].Name != "my_tool" || defs[1].Name != "another_tool" {
t.Errorf("unexpected tool names: %v", defs)
}
}
func TestExtractToolDefsNoParams(t *testing.T) {
content := `# Plugin
## simple_tool
A tool with no parameters`
defs := extractToolDefs(content)
if len(defs) != 1 {
t.Fatalf("expected 1 tool, got %d", len(defs))
}
if defs[0].Name != "simple_tool" {
t.Errorf("expected 'simple_tool', got %q", defs[0].Name)
}
props := defs[0].Parameters["properties"].(map[string]interface{})
if len(props) != 0 {
t.Errorf("expected no params, got %d", len(props))
}
}
func TestPluginManagerInterfaceReloadOne(t *testing.T) {
// 编译期契约Registry 必须实现 PluginManager含 ReloadOne 单插件重载)。
var _ sdk.PluginManager = (*Registry)(nil)
}