内置工具迁移到 internal/tools/builtin 子包,测试移至父包
This commit is contained in:
+2
-1
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
"myaibot/internal/config"
|
"myaibot/internal/config"
|
||||||
"myaibot/internal/tools"
|
"myaibot/internal/tools"
|
||||||
|
"myaibot/internal/tools/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -21,7 +22,7 @@ const (
|
|||||||
maxToolRounds = 5
|
maxToolRounds = 5
|
||||||
)
|
)
|
||||||
|
|
||||||
var toolRegistry = tools.NewRegistry(tools.TimeTool{}, tools.CalculatorTool{}, tools.RandomTool{})
|
var toolRegistry = tools.NewRegistry(builtin.TimeTool{}, builtin.CalculatorTool{}, builtin.RandomTool{})
|
||||||
|
|
||||||
type Bot struct {
|
type Bot struct {
|
||||||
clients map[string]*openai.Client
|
clients map[string]*openai.Client
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package tools
|
package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package tools
|
package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package tools
|
package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package tools_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"myaibot/internal/tools/builtin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCalculator(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
expr string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"四则运算", "(12 + 3) * 4", "60"},
|
||||||
|
{"幂运算", "2^10", "1024"},
|
||||||
|
{"浮点", "7 / 2", "3.5"},
|
||||||
|
{"小数精度", "1 / 3", "0.33333333"},
|
||||||
|
{"布尔", "2 > 1", "true"},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
args, _ := json.Marshal(map[string]string{"expression": c.expr})
|
||||||
|
got, err := builtin.CalculatorTool{}.Execute(args)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Execute 出错: %v", err)
|
||||||
|
}
|
||||||
|
if got != c.want {
|
||||||
|
t.Errorf("Execute(%q) = %q, want %q", c.expr, got, c.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCalculatorInvalid(t *testing.T) {
|
||||||
|
args, _ := json.Marshal(map[string]string{"expression": "1 +"})
|
||||||
|
if _, err := (builtin.CalculatorTool{}).Execute(args); err == nil {
|
||||||
|
t.Error("非法表达式应返回错误")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRandom(t *testing.T) {
|
||||||
|
args, _ := json.Marshal(map[string]any{"min": 1, "max": 10})
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
out, err := builtin.RandomTool{}.Execute(args)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Execute 出错: %v", err)
|
||||||
|
}
|
||||||
|
var v int
|
||||||
|
if err := json.Unmarshal([]byte(out), &v); err != nil {
|
||||||
|
t.Fatalf("结果 %q 解析失败: %v", out, err)
|
||||||
|
}
|
||||||
|
if v < 1 || v > 10 {
|
||||||
|
t.Fatalf("结果 %q 不在 [1,10] 内", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bad, _ := json.Marshal(map[string]any{"min": 10, "max": 1})
|
||||||
|
if _, err := (builtin.RandomTool{}).Execute(bad); err == nil {
|
||||||
|
t.Error("min>max 应返回错误")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimeTool(t *testing.T) {
|
||||||
|
out, err := builtin.TimeTool{}.Execute(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Execute 出错: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(out, "20") {
|
||||||
|
t.Errorf("时间输出异常: %q", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,93 +2,59 @@ package tools
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCalculator(t *testing.T) {
|
type stubTool struct{}
|
||||||
cases := []struct {
|
|
||||||
name string
|
func (stubTool) Name() string { return "stub" }
|
||||||
expr string
|
func (stubTool) Description() string { return "测试桩工具" }
|
||||||
want string
|
func (stubTool) Parameters() map[string]any {
|
||||||
}{
|
return map[string]any{"type": "object"}
|
||||||
{"四则运算", "(12 + 3) * 4", "60"},
|
|
||||||
{"幂运算", "2^10", "1024"},
|
|
||||||
{"浮点", "7 / 2", "3.5"},
|
|
||||||
{"小数精度", "1 / 3", "0.33333333"},
|
|
||||||
{"布尔", "2 > 1", "true"},
|
|
||||||
}
|
|
||||||
for _, c := range cases {
|
|
||||||
t.Run(c.name, func(t *testing.T) {
|
|
||||||
args, _ := json.Marshal(map[string]string{"expression": c.expr})
|
|
||||||
got, err := CalculatorTool{}.Execute(args)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Execute 出错: %v", err)
|
|
||||||
}
|
|
||||||
if got != c.want {
|
|
||||||
t.Errorf("Execute(%q) = %q, want %q", c.expr, got, c.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
func (stubTool) Execute(args json.RawMessage) (string, error) {
|
||||||
|
return fmt.Sprintf("stub:%s", args), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCalculatorInvalid(t *testing.T) {
|
type stubTool2 struct{}
|
||||||
args, _ := json.Marshal(map[string]string{"expression": "1 +"})
|
|
||||||
if _, err := (CalculatorTool{}).Execute(args); err == nil {
|
|
||||||
t.Error("非法表达式应返回错误")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRandom(t *testing.T) {
|
func (stubTool2) Name() string { return "stub2" }
|
||||||
args, _ := json.Marshal(map[string]any{"min": 1, "max": 10})
|
func (stubTool2) Description() string { return "测试桩工具2" }
|
||||||
for i := 0; i < 100; i++ {
|
func (stubTool2) Parameters() map[string]any {
|
||||||
out, err := RandomTool{}.Execute(args)
|
return map[string]any{"type": "object"}
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Execute 出错: %v", err)
|
|
||||||
}
|
|
||||||
var v int
|
|
||||||
if err := json.Unmarshal([]byte(out), &v); err != nil {
|
|
||||||
t.Fatalf("结果 %q 解析失败: %v", out, err)
|
|
||||||
}
|
|
||||||
if v < 1 || v > 10 {
|
|
||||||
t.Fatalf("结果 %q 不在 [1,10] 内", out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bad, _ := json.Marshal(map[string]any{"min": 10, "max": 1})
|
|
||||||
if _, err := (RandomTool{}).Execute(bad); err == nil {
|
|
||||||
t.Error("min>max 应返回错误")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTimeTool(t *testing.T) {
|
|
||||||
out, err := TimeTool{}.Execute(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Execute 出错: %v", err)
|
|
||||||
}
|
|
||||||
if !strings.Contains(out, "20") {
|
|
||||||
t.Errorf("时间输出异常: %q", out)
|
|
||||||
}
|
}
|
||||||
|
func (stubTool2) Execute(args json.RawMessage) (string, error) {
|
||||||
|
return "stub2", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRegistry(t *testing.T) {
|
func TestRegistry(t *testing.T) {
|
||||||
r := NewRegistry(TimeTool{}, CalculatorTool{}, RandomTool{})
|
r := NewRegistry(stubTool{}, stubTool2{})
|
||||||
if _, ok := r.Get("get_current_time"); !ok {
|
if _, ok := r.Get("stub"); !ok {
|
||||||
t.Error("get_current_time 未注册")
|
t.Error("stub 未注册")
|
||||||
}
|
}
|
||||||
if _, ok := r.Get("nonexistent"); ok {
|
if _, ok := r.Get("nonexistent"); ok {
|
||||||
t.Error("未知工具不应存在")
|
t.Error("未知工具不应存在")
|
||||||
}
|
}
|
||||||
if len(r.ParamList()) != 3 {
|
if len(r.ParamList()) != 2 {
|
||||||
t.Errorf("ParamList 数量 = %d, want 3", len(r.ParamList()))
|
t.Errorf("ParamList 数量 = %d, want 2", len(r.ParamList()))
|
||||||
}
|
}
|
||||||
if _, err := r.Execute("nonexistent", nil); err == nil {
|
if _, err := r.Execute("nonexistent", nil); err == nil {
|
||||||
t.Error("执行未知工具应返回错误")
|
t.Error("执行未知工具应返回错误")
|
||||||
}
|
}
|
||||||
list := r.List()
|
out, err := r.Execute("stub", json.RawMessage(`{"a":1}`))
|
||||||
if len(list) != 3 {
|
if err != nil {
|
||||||
t.Fatalf("List 数量 = %d, want 3", len(list))
|
t.Fatalf("Execute 出错: %v", err)
|
||||||
}
|
}
|
||||||
wantOrder := []string{"calculate", "get_current_time", "random_number"}
|
if out != `stub:{"a":1}` {
|
||||||
|
t.Errorf("Execute 输出 = %q", out)
|
||||||
|
}
|
||||||
|
list := r.List()
|
||||||
|
if len(list) != 2 {
|
||||||
|
t.Fatalf("List 数量 = %d, want 2", len(list))
|
||||||
|
}
|
||||||
|
wantOrder := []string{"stub", "stub2"}
|
||||||
for i, want := range wantOrder {
|
for i, want := range wantOrder {
|
||||||
if !strings.HasPrefix(list[i], want+" - ") {
|
if !strings.HasPrefix(list[i], want+" - ") {
|
||||||
t.Errorf("List[%d] = %q, want 前缀 %q", i, list[i], want+" - ")
|
t.Errorf("List[%d] = %q, want 前缀 %q", i, list[i], want+" - ")
|
||||||
|
|||||||
Reference in New Issue
Block a user