1+ package codemode
2+
3+ import (
4+ "context"
5+ "encoding/json"
6+ "reflect"
7+ "testing"
8+
9+ "github.com/stretchr/testify/assert"
10+ "github.com/stretchr/testify/require"
11+
12+ "github.com/docker/cagent/pkg/tools"
13+ )
14+
15+ func TestCallTool_StringOutput (t * testing.T ) {
16+ tool := tools.Tool {
17+ Function : & tools.FunctionDefinition {
18+ Name : "string_tool" ,
19+ OutputSchema : tools .ToOutputSchemaSchemaMust (reflect .TypeFor [string ]()),
20+ },
21+ Handler : func (ctx context.Context , toolCall tools.ToolCall ) (* tools.ToolCallResult , error ) {
22+ return & tools.ToolCallResult {Output : "hello world" }, nil
23+ },
24+ }
25+
26+ callFunc := callTool (context .Background (), tool )
27+ result , err := callFunc (map [string ]any {})
28+
29+ require .NoError (t , err )
30+ assert .Equal (t , "hello world" , result )
31+ assert .IsType (t , "" , result ) // Should be string type
32+ }
33+
34+ func TestCallTool_ArrayOutput (t * testing.T ) {
35+ tool := tools.Tool {
36+ Function : & tools.FunctionDefinition {
37+ Name : "array_tool" ,
38+ OutputSchema : tools .ToOutputSchemaSchemaMust (reflect .TypeFor [[]string ]()),
39+ },
40+ Handler : func (ctx context.Context , toolCall tools.ToolCall ) (* tools.ToolCallResult , error ) {
41+ data := []string {"file1.txt" , "file2.txt" }
42+ jsonData , _ := json .Marshal (data )
43+ return & tools.ToolCallResult {Output : string (jsonData )}, nil
44+ },
45+ }
46+
47+ callFunc := callTool (context .Background (), tool )
48+ result , err := callFunc (map [string ]any {})
49+
50+ require .NoError (t , err )
51+ assert .IsType (t , []any {}, result ) // Should be parsed as array
52+
53+ // Convert result to []any and check contents
54+ resultArray := result .([]any )
55+ assert .Len (t , resultArray , 2 )
56+ assert .Equal (t , "file1.txt" , resultArray [0 ])
57+ assert .Equal (t , "file2.txt" , resultArray [1 ])
58+ }
59+
60+ func TestCallTool_ObjectOutput (t * testing.T ) {
61+ type FileInfo struct {
62+ Name string `json:"name"`
63+ Size int64 `json:"size"`
64+ }
65+
66+ tool := tools.Tool {
67+ Function : & tools.FunctionDefinition {
68+ Name : "object_tool" ,
69+ OutputSchema : tools .ToOutputSchemaSchemaMust (reflect .TypeFor [FileInfo ]()),
70+ },
71+ Handler : func (ctx context.Context , toolCall tools.ToolCall ) (* tools.ToolCallResult , error ) {
72+ data := FileInfo {Name : "test.txt" , Size : 1024 }
73+ jsonData , _ := json .Marshal (data )
74+ return & tools.ToolCallResult {Output : string (jsonData )}, nil
75+ },
76+ }
77+
78+ callFunc := callTool (context .Background (), tool )
79+ result , err := callFunc (map [string ]any {})
80+
81+ require .NoError (t , err )
82+ assert .IsType (t , map [string ]any {}, result ) // Should be parsed as object
83+
84+ // Convert result to map and check contents
85+ resultMap := result .(map [string ]any )
86+ assert .Equal (t , "test.txt" , resultMap ["name" ])
87+ assert .Equal (t , float64 (1024 ), resultMap ["size" ]) // JSON numbers become float64
88+ }
89+
90+ func TestCallTool_NoSchema (t * testing.T ) {
91+ tool := tools.Tool {
92+ Function : & tools.FunctionDefinition {
93+ Name : "no_schema_tool" ,
94+ OutputSchema : nil ,
95+ },
96+ Handler : func (ctx context.Context , toolCall tools.ToolCall ) (* tools.ToolCallResult , error ) {
97+ return & tools.ToolCallResult {Output : "raw output" }, nil
98+ },
99+ }
100+
101+ callFunc := callTool (context .Background (), tool )
102+ result , err := callFunc (map [string ]any {})
103+
104+ require .NoError (t , err )
105+ assert .Equal (t , "raw output" , result )
106+ assert .IsType (t , "" , result ) // Should remain as string
107+ }
108+
109+ func TestCallTool_InvalidJSON (t * testing.T ) {
110+ tool := tools.Tool {
111+ Function : & tools.FunctionDefinition {
112+ Name : "invalid_json_tool" ,
113+ OutputSchema : tools .ToOutputSchemaSchemaMust (reflect .TypeFor [[]string ]()),
114+ },
115+ Handler : func (ctx context.Context , toolCall tools.ToolCall ) (* tools.ToolCallResult , error ) {
116+ return & tools.ToolCallResult {Output : "invalid json {" }, nil
117+ },
118+ }
119+
120+ callFunc := callTool (context .Background (), tool )
121+ result , err := callFunc (map [string ]any {})
122+
123+ require .NoError (t , err )
124+ // Should fallback to string when JSON parsing fails
125+ assert .Equal (t , "invalid json {" , result )
126+ assert .IsType (t , "" , result )
127+ }
0 commit comments