Files
wehub-resource-sync c3bf08ac8d
K8s Workspace Integration Tests / k8s-workspace-tests (push) Has been cancelled
Pre-commit / run (ubuntu-latest) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.11) (push) Has been cancelled
Web UI / check (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:27 +08:00

237 lines
7.4 KiB
Python

# -*- coding: utf-8 -*-
"""Glob tool test case."""
import os
import tempfile
from unittest.async_case import IsolatedAsyncioTestCase
from utils import AnyString
from agentscope.tool import Glob
from agentscope.permission import (
PermissionContext,
PermissionBehavior,
PermissionRule,
)
class GlobToolTest(IsolatedAsyncioTestCase):
"""The glob tool test case."""
async def asyncSetUp(self) -> None:
"""The async setup method."""
self.glob_tool = Glob()
# Create a temporary directory with test files
self.temp_dir = tempfile.mkdtemp()
# Create test files
with open(
os.path.join(self.temp_dir, "test1.py"),
"w",
encoding="utf-8",
):
pass
with open(
os.path.join(self.temp_dir, "test2.py"),
"w",
encoding="utf-8",
):
pass
with open(
os.path.join(self.temp_dir, "test.txt"),
"w",
encoding="utf-8",
):
pass
# Create subdirectory
sub_dir = os.path.join(self.temp_dir, "subdir")
os.makedirs(sub_dir)
with open(os.path.join(sub_dir, "test3.py"), "w", encoding="utf-8"):
pass
async def asyncTearDown(self) -> None:
"""Clean up temporary files."""
import shutil
if os.path.exists(self.temp_dir):
shutil.rmtree(self.temp_dir)
async def test_tool_properties(self) -> None:
"""Test glob tool properties."""
self.assertEqual(self.glob_tool.name, "Glob")
self.assertIsInstance(self.glob_tool.description, str)
self.assertIsInstance(self.glob_tool.input_schema, dict)
self.assertFalse(self.glob_tool.is_mcp)
self.assertTrue(self.glob_tool.is_read_only)
self.assertTrue(self.glob_tool.is_concurrency_safe)
async def test_check_permissions(self) -> None:
"""Test glob tool permission checking."""
context = PermissionContext()
tool_input = {"pattern": "*.py"}
decision = await self.glob_tool.check_permissions(tool_input, context)
# Read/Glob/Grep are read-only, return PASSTHROUGH
self.assertEqual(decision.behavior, PermissionBehavior.PASSTHROUGH)
async def test_simple_pattern(self) -> None:
"""Test simple glob pattern."""
chunk = await self.glob_tool(
pattern="*.py",
path=self.temp_dir,
)
self.assertEqual(chunk.state, "running")
# Should find test1.py and test2.py
content = chunk.content[0].text
self.assertIn("test1.py", content)
self.assertIn("test2.py", content)
self.assertNotIn("test.txt", content)
async def test_recursive_pattern(self) -> None:
"""Test recursive glob pattern."""
chunk = await self.glob_tool(
pattern="**/*.py",
path=self.temp_dir,
)
content = chunk.content[0].text
# Should find all .py files including in subdirectory
self.assertIn("test1.py", content)
self.assertIn("test2.py", content)
self.assertIn("test3.py", content)
async def test_windows_style_separator_pattern(self) -> None:
"""Test glob patterns that use backslashes as path separators."""
chunk = await self.glob_tool(
pattern=r"subdir\*.py",
path=self.temp_dir,
)
self.assertDictEqual(
chunk.model_dump(),
{
"content": [
{
"type": "text",
"text": os.path.join(
self.temp_dir,
"subdir",
"test3.py",
),
"id": AnyString(),
},
],
"state": "running",
"is_last": True,
"metadata": {},
"id": AnyString(),
},
)
async def test_no_matches(self) -> None:
"""Test pattern with no matches."""
chunk = await self.glob_tool(
pattern="*.nonexistent",
path=self.temp_dir,
)
self.assertEqual(chunk.state, "running")
self.assertIn("No files found", chunk.content[0].text)
async def test_match_rule_path(self) -> None:
"""Test match_rule with path patterns."""
# Test matching explicit path
self.assertTrue(
await self.glob_tool.match_rule(
self.temp_dir,
{"path": self.temp_dir, "pattern": "*.py"},
),
)
# Test wildcard pattern matching path
parent_dir = os.path.dirname(self.temp_dir)
self.assertTrue(
await self.glob_tool.match_rule(
parent_dir + "/**",
{"path": self.temp_dir, "pattern": "*.py"},
),
)
# Test non-matching path
self.assertFalse(
await self.glob_tool.match_rule(
"/some/other/path/**",
{"path": self.temp_dir, "pattern": "*.py"},
),
)
async def test_match_rule_pattern(self) -> None:
"""Test match_rule with pattern matching."""
# Test matching against the pattern itself
self.assertTrue(
await self.glob_tool.match_rule(
"*.py",
{"pattern": "*.py"},
),
)
# Test wildcard pattern matching
self.assertTrue(
await self.glob_tool.match_rule(
"**/*.py",
{"pattern": "src/**/*.py"},
),
)
# Test non-matching pattern
self.assertFalse(
await self.glob_tool.match_rule(
"*.txt",
{"pattern": "*.py"},
),
)
async def test_match_rule_path_priority(self) -> None:
"""Test that path matching takes priority over pattern matching."""
# If path matches, should return True even if pattern doesn't
self.assertTrue(
await self.glob_tool.match_rule(
self.temp_dir,
{"path": self.temp_dir, "pattern": "*.txt"},
),
)
async def test_generate_suggestions_with_path(self) -> None:
"""Test generate_suggestions for glob with explicit path."""
suggestions = await self.glob_tool.generate_suggestions(
{"path": self.temp_dir, "pattern": "*.py"},
)
self.assertIsInstance(suggestions, list)
self.assertGreater(len(suggestions), 0)
self.assertIsInstance(suggestions[0], PermissionRule)
# Should suggest directory pattern
abs_path = os.path.abspath(self.temp_dir)
expected_pattern = abs_path.rstrip("/") + "/**"
suggestion_contents = [s.rule_content for s in suggestions]
self.assertIn(expected_pattern, suggestion_contents)
async def test_generate_suggestions_defaults_to_cwd(self) -> None:
"""Test generate_suggestions defaults to cwd when no path provided."""
suggestions = await self.glob_tool.generate_suggestions(
{"pattern": "*.py"},
)
self.assertIsInstance(suggestions, list)
self.assertGreater(len(suggestions), 0)
cwd = os.getcwd()
expected_pattern = os.path.abspath(cwd).rstrip("/") + "/**"
suggestion_contents = [s.rule_content for s in suggestions]
self.assertIn(expected_pattern, suggestion_contents)