Spaces:
Paused
Paused
| # -*- coding: utf-8 -*- | |
| """Edit tool test case.""" | |
| import os | |
| import tempfile | |
| from unittest.async_case import IsolatedAsyncioTestCase | |
| from agentscope.tool import Edit | |
| from agentscope.permission import ( | |
| PermissionContext, | |
| PermissionBehavior, | |
| PermissionRule, | |
| ) | |
| class EditToolTest(IsolatedAsyncioTestCase): | |
| """The edit tool test case.""" | |
| async def asyncSetUp(self) -> None: | |
| """The async setup method.""" | |
| self.edit_tool = Edit() | |
| # Create a temporary file for testing | |
| self.temp_file = tempfile.NamedTemporaryFile( | |
| mode="w", | |
| delete=False, | |
| suffix=".txt", | |
| ) | |
| self.temp_file.write("Hello World\nThis is a test\n") | |
| self.temp_file.close() | |
| async def asyncTearDown(self) -> None: | |
| """Clean up temporary files.""" | |
| if os.path.exists(self.temp_file.name): | |
| os.unlink(self.temp_file.name) | |
| async def test_tool_properties(self) -> None: | |
| """Test edit tool properties.""" | |
| self.assertEqual(self.edit_tool.name, "Edit") | |
| self.assertIsInstance(self.edit_tool.description, str) | |
| self.assertIsInstance(self.edit_tool.input_schema, dict) | |
| self.assertFalse(self.edit_tool.is_mcp) | |
| self.assertFalse(self.edit_tool.is_read_only) | |
| self.assertFalse(self.edit_tool.is_concurrency_safe) | |
| async def test_check_permissions(self) -> None: | |
| """Test edit tool permission checking. | |
| Edit tool should return PASSTHROUGH for non-dangerous paths, | |
| allowing PermissionEngine to check allow rules. | |
| """ | |
| context = PermissionContext() | |
| tool_input = {"file_path": "/tmp/test.txt"} | |
| decision = await self.edit_tool.check_permissions(tool_input, context) | |
| self.assertEqual(decision.behavior, PermissionBehavior.PASSTHROUGH) | |
| async def test_simple_edit(self) -> None: | |
| """Test simple file editing.""" | |
| chunk = await self.edit_tool( | |
| file_path=self.temp_file.name, | |
| old_string="Hello World", | |
| new_string="Hello Python", | |
| ) | |
| self.assertEqual(chunk.state, "running") | |
| self.assertTrue(chunk.is_last) | |
| # Verify file content | |
| with open(self.temp_file.name, "r", encoding="utf-8") as f: | |
| content = f.read() | |
| self.assertIn("Hello Python", content) | |
| self.assertNotIn("Hello World", content) | |
| async def test_edit_not_found(self) -> None: | |
| """Test editing with string not found.""" | |
| chunk = await self.edit_tool( | |
| file_path=self.temp_file.name, | |
| old_string="NonExistent", | |
| new_string="Something", | |
| ) | |
| self.assertEqual(chunk.state, "error") | |
| self.assertIn("not found", chunk.content[0].text) | |
| async def test_edit_multiple_occurrences(self) -> None: | |
| """Test editing with multiple occurrences.""" | |
| # Write file with duplicate content | |
| with open(self.temp_file.name, "w", encoding="utf-8") as f: | |
| f.write("test\ntest\ntest\n") | |
| chunk = await self.edit_tool( | |
| file_path=self.temp_file.name, | |
| old_string="test", | |
| new_string="replaced", | |
| ) | |
| # Should fail without replace_all | |
| self.assertEqual(chunk.state, "error") | |
| async def test_edit_replace_all(self) -> None: | |
| """Test editing with replace_all flag.""" | |
| # Write file with duplicate content | |
| with open(self.temp_file.name, "w", encoding="utf-8") as f: | |
| f.write("test\ntest\ntest\n") | |
| chunk = await self.edit_tool( | |
| file_path=self.temp_file.name, | |
| old_string="test", | |
| new_string="replaced", | |
| replace_all=True, | |
| ) | |
| self.assertEqual(chunk.state, "running") | |
| # Verify all occurrences replaced | |
| with open(self.temp_file.name, "r", encoding="utf-8") as f: | |
| content = f.read() | |
| self.assertEqual(content.count("replaced"), 3) | |
| self.assertEqual(content.count("test"), 0) | |
| async def test_match_rule_glob_pattern(self) -> None: | |
| """Test match_rule with glob patterns.""" | |
| # Test exact match | |
| self.assertTrue( | |
| await self.edit_tool.match_rule( | |
| "test.py", | |
| {"file_path": "test.py"}, | |
| ), | |
| ) | |
| # Test wildcard pattern | |
| self.assertTrue( | |
| await self.edit_tool.match_rule( | |
| "*.py", | |
| {"file_path": "test.py"}, | |
| ), | |
| ) | |
| # Test directory pattern | |
| self.assertTrue( | |
| await self.edit_tool.match_rule( | |
| "/tmp/**", | |
| {"file_path": "/tmp/test.py"}, | |
| ), | |
| ) | |
| # Test non-matching pattern | |
| self.assertFalse( | |
| await self.edit_tool.match_rule( | |
| "*.txt", | |
| {"file_path": "test.py"}, | |
| ), | |
| ) | |
| # Test empty file_path | |
| self.assertFalse( | |
| await self.edit_tool.match_rule( | |
| "*.py", | |
| {"file_path": ""}, | |
| ), | |
| ) | |
| async def test_generate_suggestions(self) -> None: | |
| """Test generate_suggestions for file operations.""" | |
| # Test suggestion for file in subdirectory | |
| suggestions = await self.edit_tool.generate_suggestions( | |
| {"file_path": "/tmp/project/src/main.py"}, | |
| ) | |
| self.assertIsInstance(suggestions, list) | |
| self.assertGreater(len(suggestions), 0) | |
| self.assertIsInstance(suggestions[0], PermissionRule) | |
| # Should suggest parent directory pattern | |
| suggestion_contents = [s.rule_content for s in suggestions] | |
| self.assertIn("/tmp/project/src/**", suggestion_contents) | |
| # Test suggestion for file in root | |
| suggestions = await self.edit_tool.generate_suggestions( | |
| {"file_path": "/test.py"}, | |
| ) | |
| self.assertGreater(len(suggestions), 0) | |