Files
httprunner/uixt/mcp_server_test.go
lilong.129 f6e7e970f8 feat: 实现 AIQuery 功能并支持 OutputSchema
- 新增 AIQuery 方法到 StepMobile,支持使用自然语言从屏幕中提取信息
- 实现 AIQuery 在 driver_ext_ai.go 中的完整功能,包括屏幕截图和 LLM 查询
- 添加 OutputSchema 支持,允许用户定义自定义输出格式进行结构化查询
- 新增 ToolAIQuery MCP 工具,完整集成到 MCP 服务器中
- 在 ActionOptions 中添加 OutputSchema 字段和 WithOutputSchema 选项函数
- 添加 ACTION_Query 的配置支持和字段映射
- 完善测试覆盖:
  * 添加 TestAIQuery 单元测试,包含多种 OutputSchema 使用场景
  * 添加 TestToolAIQuery MCP 工具测试
  * 定义 GameInfo、UIElementInfo 等结构体用于测试
- 更新文档:
  * 在 docs/uixt/ai.md 中添加完整的 AIQuery 使用指南
  * 包含基本用法、OutputSchema 示例、最佳实践等
- 支持复杂的嵌套结构体和数组类型的 OutputSchema
- 与现有 AIAction、AIAssert 功能保持一致的 API 设计
2025-06-13 10:27:08 +08:00

1682 lines
50 KiB
Go

package uixt
import (
"testing"
"github.com/httprunner/httprunner/v5/internal/json"
"github.com/httprunner/httprunner/v5/uixt/option"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewMCPServer(t *testing.T) {
server := NewMCPServer()
assert.NotNil(t, server)
assert.NotEmpty(t, server.ListTools())
// Check that tools are registered
tools := server.ListTools()
assert.Greater(t, len(tools), 0, "Should have at least one tool registered")
// Check specific tools exist
expectedTools := []string{
"list_available_devices",
"select_device",
"tap_xy",
"tap_abs_xy",
"tap_ocr",
"tap_cv",
"double_tap_xy",
"swipe",
"swipe_direction",
"swipe_coordinate",
"swipe_to_tap_app",
"swipe_to_tap_text",
"swipe_to_tap_texts",
"drag",
"input",
"screenshot",
"screenrecord",
"get_screen_size",
"press_button",
"home",
"back",
"list_packages",
"app_launch",
"app_terminate",
"app_install",
"app_uninstall",
"app_clear",
"sleep",
"sleep_ms",
"sleep_random",
"set_ime",
"get_source",
"close_popups",
"web_login_none_ui",
"secondary_click",
"hover_by_selector",
"tap_by_selector",
"secondary_click_by_selector",
"web_close_tab",
"ai_action",
"finished",
}
registeredToolNames := make(map[string]bool)
for _, tool := range tools {
registeredToolNames[tool.Name] = true
}
for _, expectedTool := range expectedTools {
assert.True(t, registeredToolNames[expectedTool], "Tool %s should be registered", expectedTool)
}
}
func TestToolInterfaces(t *testing.T) {
// Test that all tools implement the ActionTool interface correctly
tools := []ActionTool{
&ToolListAvailableDevices{},
&ToolSelectDevice{},
&ToolTapXY{},
&ToolTapAbsXY{},
&ToolTapByOCR{},
&ToolTapByCV{},
&ToolDoubleTapXY{},
&ToolSwipe{},
&ToolSwipeDirection{},
&ToolSwipeCoordinate{},
&ToolSwipeToTapApp{},
&ToolSwipeToTapText{},
&ToolSwipeToTapTexts{},
&ToolDrag{},
&ToolInput{},
&ToolScreenShot{},
&ToolGetScreenSize{},
&ToolPressButton{},
&ToolHome{},
&ToolBack{},
&ToolListPackages{},
&ToolLaunchApp{},
&ToolTerminateApp{},
&ToolAppInstall{},
&ToolAppUninstall{},
&ToolAppClear{},
&ToolSleep{},
&ToolSleepMS{},
&ToolSleepRandom{},
&ToolSetIme{},
&ToolGetSource{},
&ToolClosePopups{},
&ToolWebLoginNoneUI{},
&ToolSecondaryClick{},
&ToolHoverBySelector{},
&ToolTapBySelector{},
&ToolSecondaryClickBySelector{},
&ToolWebCloseTab{},
&ToolAIAction{},
&ToolAIQuery{},
&ToolFinished{},
}
for _, tool := range tools {
assert.NotEmpty(t, string(tool.Name()), "Tool name should not be empty")
assert.NotEmpty(t, tool.Description(), "Tool description should not be empty")
assert.NotNil(t, tool.Options(), "Tool options should not be nil")
assert.NotNil(t, tool.Implement(), "Tool implementation should not be nil")
}
}
func TestIgnoreNotFoundErrorOption(t *testing.T) {
// Test that ignore_NotFoundError option is properly extracted and applied
server := NewMCPServer()
// Test TapByOCR tool
tapOCRTool := server.GetToolByAction(option.ACTION_TapByOCR)
assert.NotNil(t, tapOCRTool, "TapByOCR tool should be available")
// Create a mock action with ignore_NotFoundError option
actionOptions := option.NewActionOptions(
option.WithIgnoreNotFoundError(true),
option.WithMaxRetryTimes(2),
option.WithIndex(1),
option.WithRegex(true),
option.WithTapRandomRect(true),
)
action := option.MobileAction{
Method: option.ACTION_TapByOCR,
Params: "test_text",
ActionOptions: *actionOptions,
}
// Convert action to MCP call tool request
request, err := tapOCRTool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err, "Should convert action to request without error")
// Verify that ignore_NotFoundError option is included in arguments
args := request.Params.Arguments
assert.Equal(t, true, args["ignore_NotFoundError"], "ignore_NotFoundError should be true")
assert.Equal(t, 2, args["max_retry_times"], "max_retry_times should be 2")
assert.Equal(t, 1, args["index"], "index should be 1")
assert.Equal(t, true, args["regex"], "regex should be true")
assert.Equal(t, true, args["tap_random_rect"], "tap_random_rect should be true")
assert.Equal(t, "test_text", args["text"], "text should be test_text")
}
func TestExtractActionOptionsToArguments(t *testing.T) {
// Test the extractActionOptionsToArguments helper function
actionOptions := []option.ActionOption{
option.WithIgnoreNotFoundError(true),
option.WithMaxRetryTimes(3),
option.WithIndex(2),
option.WithRegex(true),
option.WithTapRandomRect(false), // false should not be included
option.WithDuration(1.5),
}
arguments := make(map[string]any)
extractActionOptionsToArguments(actionOptions, arguments)
// Verify extracted options
assert.Equal(t, true, arguments["ignore_NotFoundError"], "ignore_NotFoundError should be extracted")
assert.Equal(t, 3, arguments["max_retry_times"], "max_retry_times should be extracted")
assert.Equal(t, 2, arguments["index"], "index should be extracted")
assert.Equal(t, true, arguments["regex"], "regex should be extracted")
assert.Equal(t, 1.5, arguments["duration"], "duration should be extracted")
// tap_random_rect should not be included since it's false
_, exists := arguments["tap_random_rect"]
assert.False(t, exists, "tap_random_rect should not be included when false")
}
// TestToolListAvailableDevices tests the ToolListAvailableDevices implementation
func TestToolListAvailableDevices(t *testing.T) {
tool := &ToolListAvailableDevices{}
// Test Name
assert.Equal(t, option.ACTION_ListAvailableDevices, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest
action := option.MobileAction{
Method: option.ACTION_ListAvailableDevices,
Params: nil,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_ListAvailableDevices), request.Params.Name)
assert.Empty(t, request.Params.Arguments)
}
// TestToolSelectDevice tests the ToolSelectDevice implementation
func TestToolSelectDevice(t *testing.T) {
tool := &ToolSelectDevice{}
// Test Name
assert.Equal(t, option.ACTION_SelectDevice, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
assert.Len(t, options, 2) // platform and serial
// Test ConvertActionToCallToolRequest
action := option.MobileAction{
Method: option.ACTION_SelectDevice,
Params: nil,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_SelectDevice), request.Params.Name)
}
// TestToolTapXY tests the ToolTapXY implementation
func TestToolTapXY(t *testing.T) {
tool := &ToolTapXY{}
// Test Name
assert.Equal(t, option.ACTION_TapXY, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_TapXY,
Params: []float64{0.5, 0.6},
ActionOptions: option.ActionOptions{
Duration: 1.5,
},
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_TapXY), request.Params.Name)
assert.Equal(t, 0.5, request.Params.Arguments["x"])
assert.Equal(t, 0.6, request.Params.Arguments["y"])
assert.Equal(t, 1.5, request.Params.Arguments["duration"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_TapXY,
Params: "invalid",
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolTapAbsXY tests the ToolTapAbsXY implementation
func TestToolTapAbsXY(t *testing.T) {
tool := &ToolTapAbsXY{}
// Test Name
assert.Equal(t, option.ACTION_TapAbsXY, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_TapAbsXY,
Params: []float64{100.0, 200.0},
ActionOptions: option.ActionOptions{
Duration: 2.0,
},
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_TapAbsXY), request.Params.Name)
assert.Equal(t, 100.0, request.Params.Arguments["x"])
assert.Equal(t, 200.0, request.Params.Arguments["y"])
assert.Equal(t, 2.0, request.Params.Arguments["duration"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_TapAbsXY,
Params: []float64{100.0}, // missing y coordinate
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolTapByOCR tests the ToolTapByOCR implementation
func TestToolTapByOCR(t *testing.T) {
tool := &ToolTapByOCR{}
// Test Name
assert.Equal(t, option.ACTION_TapByOCR, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
actionOptions := option.NewActionOptions(
option.WithIgnoreNotFoundError(true),
option.WithMaxRetryTimes(3),
option.WithIndex(1),
option.WithRegex(true),
option.WithTapRandomRect(true),
)
action := option.MobileAction{
Method: option.ACTION_TapByOCR,
Params: "test_text",
ActionOptions: *actionOptions,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_TapByOCR), request.Params.Name)
assert.Equal(t, "test_text", request.Params.Arguments["text"])
assert.Equal(t, true, request.Params.Arguments["ignore_NotFoundError"])
assert.Equal(t, 3, request.Params.Arguments["max_retry_times"])
assert.Equal(t, 1, request.Params.Arguments["index"])
assert.Equal(t, true, request.Params.Arguments["regex"])
assert.Equal(t, true, request.Params.Arguments["tap_random_rect"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_TapByOCR,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolTapByCV tests the ToolTapByCV implementation
func TestToolTapByCV(t *testing.T) {
tool := &ToolTapByCV{}
// Test Name
assert.Equal(t, option.ACTION_TapByCV, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest
actionOptions := option.NewActionOptions(
option.WithIgnoreNotFoundError(true),
option.WithMaxRetryTimes(2),
option.WithTapRandomRect(true),
)
action := option.MobileAction{
Method: option.ACTION_TapByCV,
Params: nil,
ActionOptions: *actionOptions,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_TapByCV), request.Params.Name)
assert.Equal(t, "", request.Params.Arguments["imagePath"])
assert.Equal(t, true, request.Params.Arguments["ignore_NotFoundError"])
assert.Equal(t, 2, request.Params.Arguments["max_retry_times"])
assert.Equal(t, true, request.Params.Arguments["tap_random_rect"])
}
// TestToolDoubleTapXY tests the ToolDoubleTapXY implementation
func TestToolDoubleTapXY(t *testing.T) {
tool := &ToolDoubleTapXY{}
// Test Name
assert.Equal(t, option.ACTION_DoubleTapXY, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_DoubleTapXY,
Params: []float64{0.3, 0.7},
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_DoubleTapXY), request.Params.Name)
assert.Equal(t, 0.3, request.Params.Arguments["x"])
assert.Equal(t, 0.7, request.Params.Arguments["y"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_DoubleTapXY,
Params: "invalid",
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolSwipe tests the ToolSwipe implementation
func TestToolSwipe(t *testing.T) {
tool := &ToolSwipe{}
// Test Name
assert.Equal(t, option.ACTION_Swipe, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with direction params (string)
directionAction := option.MobileAction{
Method: option.ACTION_Swipe,
Params: "up",
ActionOptions: option.ActionOptions{
Duration: 1.5,
PressDuration: 0.5,
},
}
request, err := tool.ConvertActionToCallToolRequest(directionAction)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_Swipe), request.Params.Name)
assert.Equal(t, "up", request.Params.Arguments["direction"])
assert.Equal(t, 1.5, request.Params.Arguments["duration"])
assert.Equal(t, 0.5, request.Params.Arguments["pressDuration"])
// Test ConvertActionToCallToolRequest with coordinate params
coordinateAction := option.MobileAction{
Method: option.ACTION_Swipe,
Params: []float64{0.1, 0.2, 0.8, 0.9},
ActionOptions: option.ActionOptions{
Duration: 2.0,
PressDuration: 1.0,
},
}
request, err = tool.ConvertActionToCallToolRequest(coordinateAction)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_Swipe), request.Params.Name)
assert.Equal(t, 0.1, request.Params.Arguments["from_x"])
assert.Equal(t, 0.2, request.Params.Arguments["from_y"])
assert.Equal(t, 0.8, request.Params.Arguments["to_x"])
assert.Equal(t, 0.9, request.Params.Arguments["to_y"])
assert.Equal(t, 2.0, request.Params.Arguments["duration"])
assert.Equal(t, 1.0, request.Params.Arguments["pressDuration"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_Swipe,
Params: 123, // should be string or []float64
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
// Test ConvertActionToCallToolRequest with incomplete coordinate params
incompleteAction := option.MobileAction{
Method: option.ACTION_Swipe,
Params: []float64{0.1, 0.2}, // missing toX and toY
}
_, err = tool.ConvertActionToCallToolRequest(incompleteAction)
assert.Error(t, err)
}
// TestToolSwipeDirection tests the ToolSwipeDirection implementation
func TestToolSwipeDirection(t *testing.T) {
tool := &ToolSwipeDirection{}
// Test Name
assert.Equal(t, option.ACTION_SwipeDirection, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_SwipeDirection,
Params: "up",
ActionOptions: option.ActionOptions{
Duration: 1.0,
PressDuration: 0.5,
},
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_SwipeDirection), request.Params.Name)
assert.Equal(t, "up", request.Params.Arguments["direction"])
assert.Equal(t, 1.0, request.Params.Arguments["duration"])
assert.Equal(t, 0.5, request.Params.Arguments["pressDuration"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_SwipeDirection,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolSwipeCoordinate tests the ToolSwipeCoordinate implementation
func TestToolSwipeCoordinate(t *testing.T) {
tool := &ToolSwipeCoordinate{}
// Test Name
assert.Equal(t, option.ACTION_SwipeCoordinate, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_SwipeCoordinate,
Params: []float64{0.1, 0.2, 0.8, 0.9},
ActionOptions: option.ActionOptions{
Duration: 2.0,
PressDuration: 1.0,
},
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_SwipeCoordinate), request.Params.Name)
assert.Equal(t, 0.1, request.Params.Arguments["from_x"])
assert.Equal(t, 0.2, request.Params.Arguments["from_y"])
assert.Equal(t, 0.8, request.Params.Arguments["to_x"])
assert.Equal(t, 0.9, request.Params.Arguments["to_y"])
assert.Equal(t, 2.0, request.Params.Arguments["duration"])
assert.Equal(t, 1.0, request.Params.Arguments["pressDuration"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_SwipeCoordinate,
Params: []float64{0.1, 0.2}, // missing toX and toY
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolSwipeToTapApp tests the ToolSwipeToTapApp implementation
func TestToolSwipeToTapApp(t *testing.T) {
tool := &ToolSwipeToTapApp{}
// Test Name
assert.Equal(t, option.ACTION_SwipeToTapApp, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
actionOptions := option.NewActionOptions(
option.WithIgnoreNotFoundError(true),
option.WithMaxRetryTimes(3),
option.WithIndex(1),
)
action := option.MobileAction{
Method: option.ACTION_SwipeToTapApp,
Params: "WeChat",
ActionOptions: *actionOptions,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_SwipeToTapApp), request.Params.Name)
assert.Equal(t, "WeChat", request.Params.Arguments["appName"])
assert.Equal(t, true, request.Params.Arguments["ignore_NotFoundError"])
assert.Equal(t, 3, request.Params.Arguments["max_retry_times"])
assert.Equal(t, 1, request.Params.Arguments["index"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_SwipeToTapApp,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolSwipeToTapText tests the ToolSwipeToTapText implementation
func TestToolSwipeToTapText(t *testing.T) {
tool := &ToolSwipeToTapText{}
// Test Name
assert.Equal(t, option.ACTION_SwipeToTapText, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
actionOptions := option.NewActionOptions(
option.WithIgnoreNotFoundError(true),
option.WithMaxRetryTimes(2),
option.WithRegex(true),
)
action := option.MobileAction{
Method: option.ACTION_SwipeToTapText,
Params: "Submit",
ActionOptions: *actionOptions,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_SwipeToTapText), request.Params.Name)
assert.Equal(t, "Submit", request.Params.Arguments["text"])
assert.Equal(t, true, request.Params.Arguments["ignore_NotFoundError"])
assert.Equal(t, 2, request.Params.Arguments["max_retry_times"])
assert.Equal(t, true, request.Params.Arguments["regex"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_SwipeToTapText,
Params: []int{1, 2, 3}, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolSwipeToTapTexts tests the ToolSwipeToTapTexts implementation
func TestToolSwipeToTapTexts(t *testing.T) {
tool := &ToolSwipeToTapTexts{}
// Test Name
assert.Equal(t, option.ACTION_SwipeToTapTexts, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
actionOptions := option.NewActionOptions(
option.WithIgnoreNotFoundError(true),
option.WithRegex(true),
)
action := option.MobileAction{
Method: option.ACTION_SwipeToTapTexts,
Params: []string{"OK", "确定", "Submit"},
ActionOptions: *actionOptions,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_SwipeToTapTexts), request.Params.Name)
texts, ok := request.Params.Arguments["texts"].([]string)
require.True(t, ok)
assert.Equal(t, []string{"OK", "确定", "Submit"}, texts)
assert.Equal(t, true, request.Params.Arguments["ignore_NotFoundError"])
assert.Equal(t, true, request.Params.Arguments["regex"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_SwipeToTapTexts,
Params: "single_string", // should be []string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolDrag tests the ToolDrag implementation
func TestToolDrag(t *testing.T) {
tool := &ToolDrag{}
// Test Name
assert.Equal(t, option.ACTION_Drag, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_Drag,
Params: []float64{0.1, 0.2, 0.8, 0.9},
ActionOptions: option.ActionOptions{
Duration: 2.5,
},
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_Drag), request.Params.Name)
assert.Equal(t, 0.1, request.Params.Arguments["from_x"])
assert.Equal(t, 0.2, request.Params.Arguments["from_y"])
assert.Equal(t, 0.8, request.Params.Arguments["to_x"])
assert.Equal(t, 0.9, request.Params.Arguments["to_y"])
assert.Equal(t, 2500.0, request.Params.Arguments["duration"]) // converted to milliseconds
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_Drag,
Params: []float64{0.1, 0.2}, // missing toX and toY
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolInput tests the ToolInput implementation
func TestToolInput(t *testing.T) {
tool := &ToolInput{}
// Test Name
assert.Equal(t, option.ACTION_Input, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_Input,
Params: "Hello World",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_Input), request.Params.Name)
assert.Equal(t, "Hello World", request.Params.Arguments["text"])
}
// TestToolScreenShot tests the ToolScreenShot implementation
func TestToolScreenShot(t *testing.T) {
tool := &ToolScreenShot{}
// Test Name
assert.Equal(t, option.ACTION_ScreenShot, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest
action := option.MobileAction{
Method: option.ACTION_ScreenShot,
Params: nil,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_ScreenShot), request.Params.Name)
assert.Empty(t, request.Params.Arguments)
}
// TestToolGetScreenSize tests the ToolGetScreenSize implementation
func TestToolGetScreenSize(t *testing.T) {
tool := &ToolGetScreenSize{}
// Test Name
assert.Equal(t, option.ACTION_GetScreenSize, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest
action := option.MobileAction{
Method: option.ACTION_GetScreenSize,
Params: nil,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_GetScreenSize), request.Params.Name)
assert.Empty(t, request.Params.Arguments)
}
// TestToolPressButton tests the ToolPressButton implementation
func TestToolPressButton(t *testing.T) {
tool := &ToolPressButton{}
// Test Name
assert.Equal(t, option.ACTION_PressButton, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_PressButton,
Params: "HOME",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_PressButton), request.Params.Name)
assert.Equal(t, "HOME", request.Params.Arguments["button"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_PressButton,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolHome tests the ToolHome implementation
func TestToolHome(t *testing.T) {
tool := &ToolHome{}
// Test Name
assert.Equal(t, option.ACTION_Home, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest
action := option.MobileAction{
Method: option.ACTION_Home,
Params: nil,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_Home), request.Params.Name)
assert.Empty(t, request.Params.Arguments)
}
// TestToolBack tests the ToolBack implementation
func TestToolBack(t *testing.T) {
tool := &ToolBack{}
// Test Name
assert.Equal(t, option.ACTION_Back, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest
action := option.MobileAction{
Method: option.ACTION_Back,
Params: nil,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_Back), request.Params.Name)
assert.Empty(t, request.Params.Arguments)
}
// TestToolListPackages tests the ToolListPackages implementation
func TestToolListPackages(t *testing.T) {
tool := &ToolListPackages{}
// Test Name
assert.Equal(t, option.ACTION_ListPackages, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest
action := option.MobileAction{
Method: option.ACTION_ListPackages,
Params: nil,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_ListPackages), request.Params.Name)
assert.Empty(t, request.Params.Arguments)
}
// TestToolLaunchApp tests the ToolLaunchApp implementation
func TestToolLaunchApp(t *testing.T) {
tool := &ToolLaunchApp{}
// Test Name
assert.Equal(t, option.ACTION_AppLaunch, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_AppLaunch,
Params: "com.example.app",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_AppLaunch), request.Params.Name)
assert.Equal(t, "com.example.app", request.Params.Arguments["packageName"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_AppLaunch,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolTerminateApp tests the ToolTerminateApp implementation
func TestToolTerminateApp(t *testing.T) {
tool := &ToolTerminateApp{}
// Test Name
assert.Equal(t, option.ACTION_AppTerminate, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_AppTerminate,
Params: "com.example.app",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_AppTerminate), request.Params.Name)
assert.Equal(t, "com.example.app", request.Params.Arguments["packageName"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_AppTerminate,
Params: []int{1, 2, 3}, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolAppInstall tests the ToolAppInstall implementation
func TestToolAppInstall(t *testing.T) {
tool := &ToolAppInstall{}
// Test Name
assert.Equal(t, option.ACTION_AppInstall, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_AppInstall,
Params: "https://example.com/app.apk",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_AppInstall), request.Params.Name)
assert.Equal(t, "https://example.com/app.apk", request.Params.Arguments["appUrl"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_AppInstall,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolAppUninstall tests the ToolAppUninstall implementation
func TestToolAppUninstall(t *testing.T) {
tool := &ToolAppUninstall{}
// Test Name
assert.Equal(t, option.ACTION_AppUninstall, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_AppUninstall,
Params: "com.example.app",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_AppUninstall), request.Params.Name)
assert.Equal(t, "com.example.app", request.Params.Arguments["packageName"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_AppUninstall,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolAppClear tests the ToolAppClear implementation
func TestToolAppClear(t *testing.T) {
tool := &ToolAppClear{}
// Test Name
assert.Equal(t, option.ACTION_AppClear, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_AppClear,
Params: "com.example.app",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_AppClear), request.Params.Name)
assert.Equal(t, "com.example.app", request.Params.Arguments["packageName"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_AppClear,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolSleep tests the ToolSleep implementation
func TestToolSleep(t *testing.T) {
tool := &ToolSleep{}
// Test Name
assert.Equal(t, option.ACTION_Sleep, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_Sleep,
Params: 2.5,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_Sleep), request.Params.Name)
assert.Equal(t, 2.5, request.Params.Arguments["seconds"])
}
// TestToolSleepMS tests the ToolSleepMS implementation
func TestToolSleepMS(t *testing.T) {
tool := &ToolSleepMS{}
// Test Name
assert.Equal(t, option.ACTION_SleepMS, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_SleepMS,
Params: int64(1500),
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_SleepMS), request.Params.Name)
assert.Equal(t, int64(1500), request.Params.Arguments["milliseconds"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_SleepMS,
Params: "invalid", // should be int64
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolSleepRandom tests the ToolSleepRandom implementation
func TestToolSleepRandom(t *testing.T) {
tool := &ToolSleepRandom{}
// Test Name
assert.Equal(t, option.ACTION_SleepRandom, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_SleepRandom,
Params: []float64{1.0, 3.0},
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_SleepRandom), request.Params.Name)
params, ok := request.Params.Arguments["params"].([]float64)
require.True(t, ok)
assert.Equal(t, []float64{1.0, 3.0}, params)
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_SleepRandom,
Params: "invalid", // should be []float64
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolSetIme tests the ToolSetIme implementation
func TestToolSetIme(t *testing.T) {
tool := &ToolSetIme{}
// Test Name
assert.Equal(t, option.ACTION_SetIme, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_SetIme,
Params: "com.google.android.inputmethod.latin",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_SetIme), request.Params.Name)
assert.Equal(t, "com.google.android.inputmethod.latin", request.Params.Arguments["ime"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_SetIme,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolGetSource tests the ToolGetSource implementation
func TestToolGetSource(t *testing.T) {
tool := &ToolGetSource{}
// Test Name
assert.Equal(t, option.ACTION_GetSource, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_GetSource,
Params: "com.example.app",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_GetSource), request.Params.Name)
assert.Equal(t, "com.example.app", request.Params.Arguments["packageName"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_GetSource,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolClosePopups tests the ToolClosePopups implementation
func TestToolClosePopups(t *testing.T) {
tool := &ToolClosePopups{}
// Test Name
assert.Equal(t, option.ACTION_ClosePopups, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest
action := option.MobileAction{
Method: option.ACTION_ClosePopups,
Params: nil,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_ClosePopups), request.Params.Name)
assert.Empty(t, request.Params.Arguments)
}
// TestToolAIAction tests the ToolAIAction implementation
func TestToolAIAction(t *testing.T) {
tool := &ToolAIAction{}
// Test Name
assert.Equal(t, option.ACTION_AIAction, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_AIAction,
Params: "Click on the login button",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_AIAction), request.Params.Name)
assert.Equal(t, "Click on the login button", request.Params.Arguments["prompt"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_AIAction,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolAIQuery tests the ToolAIQuery implementation
func TestToolAIQuery(t *testing.T) {
tool := &ToolAIQuery{}
// Test Name
assert.Equal(t, option.ACTION_Query, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_Query,
Params: "What is displayed on the screen?",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_Query), request.Params.Name)
assert.Equal(t, "What is displayed on the screen?", request.Params.Arguments["prompt"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_Query,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolFinished tests the ToolFinished implementation
func TestToolFinished(t *testing.T) {
tool := &ToolFinished{}
// Test Name
assert.Equal(t, option.ACTION_Finished, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_Finished,
Params: "Task completed successfully",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_Finished), request.Params.Name)
assert.Equal(t, "Task completed successfully", request.Params.Arguments["content"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_Finished,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolWebLoginNoneUI tests the ToolWebLoginNoneUI implementation
func TestToolWebLoginNoneUI(t *testing.T) {
tool := &ToolWebLoginNoneUI{}
// Test Name
assert.Equal(t, option.ACTION_WebLoginNoneUI, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest
action := option.MobileAction{
Method: option.ACTION_WebLoginNoneUI,
Params: nil,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_WebLoginNoneUI), request.Params.Name)
assert.Empty(t, request.Params.Arguments)
}
// TestToolSecondaryClick tests the ToolSecondaryClick implementation
func TestToolSecondaryClick(t *testing.T) {
tool := &ToolSecondaryClick{}
// Test Name
assert.Equal(t, option.ACTION_SecondaryClick, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_SecondaryClick,
Params: []float64{0.5, 0.6},
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_SecondaryClick), request.Params.Name)
assert.Equal(t, 0.5, request.Params.Arguments["x"])
assert.Equal(t, 0.6, request.Params.Arguments["y"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_SecondaryClick,
Params: "invalid", // should be []float64
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolHoverBySelector tests the ToolHoverBySelector implementation
func TestToolHoverBySelector(t *testing.T) {
tool := &ToolHoverBySelector{}
// Test Name
assert.Equal(t, option.ACTION_HoverBySelector, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_HoverBySelector,
Params: "#login-button",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_HoverBySelector), request.Params.Name)
assert.Equal(t, "#login-button", request.Params.Arguments["selector"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_HoverBySelector,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolTapBySelector tests the ToolTapBySelector implementation
func TestToolTapBySelector(t *testing.T) {
tool := &ToolTapBySelector{}
// Test Name
assert.Equal(t, option.ACTION_TapBySelector, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_TapBySelector,
Params: "//button[@id='submit']",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_TapBySelector), request.Params.Name)
assert.Equal(t, "//button[@id='submit']", request.Params.Arguments["selector"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_TapBySelector,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolSecondaryClickBySelector tests the ToolSecondaryClickBySelector implementation
func TestToolSecondaryClickBySelector(t *testing.T) {
tool := &ToolSecondaryClickBySelector{}
// Test Name
assert.Equal(t, option.ACTION_SecondaryClickBySelector, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_SecondaryClickBySelector,
Params: ".context-menu-trigger",
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_SecondaryClickBySelector), request.Params.Name)
assert.Equal(t, ".context-menu-trigger", request.Params.Arguments["selector"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_SecondaryClickBySelector,
Params: 123, // should be string
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
// TestToolWebCloseTab tests the ToolWebCloseTab implementation
func TestToolWebCloseTab(t *testing.T) {
tool := &ToolWebCloseTab{}
// Test Name
assert.Equal(t, option.ACTION_WebCloseTab, tool.Name())
// Test Description
assert.NotEmpty(t, tool.Description())
// Test Options
options := tool.Options()
assert.NotNil(t, options)
// Test ConvertActionToCallToolRequest with valid params
action := option.MobileAction{
Method: option.ACTION_WebCloseTab,
Params: 1,
}
request, err := tool.ConvertActionToCallToolRequest(action)
assert.NoError(t, err)
assert.Equal(t, string(option.ACTION_WebCloseTab), request.Params.Name)
assert.Equal(t, 1, request.Params.Arguments["tabIndex"])
// Test ConvertActionToCallToolRequest with invalid params
invalidAction := option.MobileAction{
Method: option.ACTION_WebCloseTab,
Params: "invalid", // should be int
}
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
assert.Error(t, err)
}
func TestPreMarkOperationConfiguration(t *testing.T) {
// Test that pre_mark_operation is configurable and not hardcoded
server := NewMCPServer()
// Get the tap_xy tool
tapTool := server.GetToolByAction(option.ACTION_TapXY)
assert.NotNil(t, tapTool)
// Test conversion with pre_mark_operation enabled
actionWithPreMark := option.MobileAction{
Method: option.ACTION_TapXY,
Params: []float64{0.5, 0.5},
ActionOptions: *option.NewActionOptions(option.WithPreMarkOperation(true)),
}
request, err := tapTool.ConvertActionToCallToolRequest(actionWithPreMark)
assert.NoError(t, err)
assert.Equal(t, true, request.Params.Arguments["pre_mark_operation"])
// Test conversion without pre_mark_operation
actionWithoutPreMark := option.MobileAction{
Method: option.ACTION_TapXY,
Params: []float64{0.5, 0.5},
ActionOptions: *option.NewActionOptions(option.WithPreMarkOperation(false)),
}
request2, err := tapTool.ConvertActionToCallToolRequest(actionWithoutPreMark)
assert.NoError(t, err)
// Should not have pre_mark_operation in arguments when false
_, exists := request2.Params.Arguments["pre_mark_operation"]
assert.False(t, exists)
}
func TestGenerateReturnSchema(t *testing.T) {
// Test with ToolListPackages
tool := ToolListPackages{}
schema := GenerateReturnSchema(tool)
// Check that standard MCPResponse fields are included
assert.Contains(t, schema, "action")
assert.Contains(t, schema, "success")
assert.Contains(t, schema, "message")
assert.Equal(t, "string: Action performed", schema["action"])
assert.Equal(t, "boolean: Whether the operation was successful", schema["success"])
assert.Equal(t, "string: Human-readable message describing the result", schema["message"])
// Check that tool-specific fields are included at the same level
assert.Contains(t, schema, "packages")
assert.Contains(t, schema, "count")
assert.Equal(t, "[]string: List of installed app package names on the device", schema["packages"])
assert.Equal(t, "int: Number of installed packages", schema["count"])
// Ensure "data" field is not present in the new flat structure
assert.NotContains(t, schema, "data")
}
func TestMCPResponseInheritance(t *testing.T) {
// Test creating a response with tool data
returnData := ToolListPackages{
Packages: []string{"com.example.app1", "com.example.app2"},
Count: 2,
}
// Test JSON marshaling
jsonData, err := json.Marshal(returnData)
assert.NoError(t, err)
// Parse back to verify structure
var parsed map[string]interface{}
err = json.Unmarshal(jsonData, &parsed)
assert.NoError(t, err)
// Check that tool-specific fields are present
assert.Equal(t, float64(2), parsed["count"]) // JSON numbers are float64
packages, ok := parsed["packages"].([]interface{})
assert.True(t, ok)
assert.Len(t, packages, 2)
assert.Equal(t, "com.example.app1", packages[0])
assert.Equal(t, "com.example.app2", packages[1])
}
func TestNewMCPSuccessResponse(t *testing.T) {
// Test the simplified NewMCPSuccessResponse function
message := "Successfully slept for 5 seconds"
returnData := ToolSleep{
Seconds: 5.0,
Duration: "5s",
}
// Test JSON marshaling directly first
jsonData, err := json.Marshal(returnData)
assert.NoError(t, err)
// Parse the JSON to verify structure
var parsed map[string]interface{}
err = json.Unmarshal(jsonData, &parsed)
assert.NoError(t, err)
assert.Equal(t, float64(5.0), parsed["seconds"])
assert.Equal(t, "5s", parsed["duration"])
// Test the MCP response function with actual tool instance
tool := &ToolSleep{}
result := NewMCPSuccessResponse(message, tool)
assert.NotNil(t, result)
}
func TestNewMCPErrorResponse(t *testing.T) {
// Test error response creation
result := NewMCPErrorResponse("Test error message")
assert.NotNil(t, result)
}