auto-coder 0.1.400__py3-none-any.whl → 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of auto-coder might be problematic. Click here for more details.
- auto_coder-2.0.0.dist-info/LICENSE +158 -0
- auto_coder-2.0.0.dist-info/METADATA +558 -0
- auto_coder-2.0.0.dist-info/RECORD +795 -0
- {auto_coder-0.1.400.dist-info → auto_coder-2.0.0.dist-info}/WHEEL +1 -1
- {auto_coder-0.1.400.dist-info → auto_coder-2.0.0.dist-info}/entry_points.txt +3 -3
- autocoder/__init__.py +31 -0
- autocoder/agent/auto_filegroup.py +32 -13
- autocoder/agent/auto_learn_from_commit.py +9 -1
- autocoder/agent/base_agentic/__init__.py +3 -0
- autocoder/agent/base_agentic/agent_hub.py +1 -1
- autocoder/agent/base_agentic/base_agent.py +235 -136
- autocoder/agent/base_agentic/default_tools.py +119 -118
- autocoder/agent/base_agentic/test_base_agent.py +1 -1
- autocoder/agent/base_agentic/tool_registry.py +32 -20
- autocoder/agent/base_agentic/tools/read_file_tool_resolver.py +25 -4
- autocoder/agent/base_agentic/tools/write_to_file_tool_resolver.py +24 -11
- autocoder/agent/base_agentic/types.py +42 -0
- autocoder/agent/entry_command_agent/chat.py +73 -59
- autocoder/auto_coder.py +31 -40
- autocoder/auto_coder_rag.py +11 -1084
- autocoder/auto_coder_runner.py +1029 -2310
- autocoder/auto_coder_terminal.py +26 -0
- autocoder/auto_coder_terminal_v3.py +190 -0
- autocoder/chat/conf_command.py +224 -124
- autocoder/chat/models_command.py +361 -299
- autocoder/chat/rules_command.py +79 -31
- autocoder/chat_auto_coder.py +1021 -372
- autocoder/chat_auto_coder_lang.py +23 -732
- autocoder/commands/auto_command.py +26 -9
- autocoder/commands/auto_web.py +1 -1
- autocoder/commands/tools.py +44 -44
- autocoder/common/__init__.py +150 -128
- autocoder/common/ac_style_command_parser/__init__.py +39 -2
- autocoder/common/ac_style_command_parser/config.py +422 -0
- autocoder/common/ac_style_command_parser/parser.py +292 -78
- autocoder/common/ac_style_command_parser/test_parser.py +241 -16
- autocoder/common/ac_style_command_parser/test_typed_parser.py +342 -0
- autocoder/common/ac_style_command_parser/typed_parser.py +653 -0
- autocoder/common/action_yml_file_manager.py +25 -13
- autocoder/common/agent_events/__init__.py +52 -0
- autocoder/common/agent_events/agent_event_emitter.py +193 -0
- autocoder/common/agent_events/event_factory.py +177 -0
- autocoder/common/agent_events/examples.py +307 -0
- autocoder/common/agent_events/types.py +113 -0
- autocoder/common/agent_events/utils.py +68 -0
- autocoder/common/agent_hooks/__init__.py +44 -0
- autocoder/common/agent_hooks/examples.py +582 -0
- autocoder/common/agent_hooks/hook_executor.py +217 -0
- autocoder/common/agent_hooks/hook_manager.py +288 -0
- autocoder/common/agent_hooks/types.py +133 -0
- autocoder/common/agent_hooks/utils.py +99 -0
- autocoder/common/agent_query_queue/queue_executor.py +324 -0
- autocoder/common/agent_query_queue/queue_manager.py +325 -0
- autocoder/common/agents/__init__.py +11 -0
- autocoder/common/agents/agent_manager.py +323 -0
- autocoder/common/agents/agent_parser.py +189 -0
- autocoder/common/agents/example_usage.py +344 -0
- autocoder/common/agents/integration_example.py +330 -0
- autocoder/common/agents/test_agent_parser.py +545 -0
- autocoder/common/async_utils.py +101 -0
- autocoder/common/auto_coder_lang.py +23 -972
- autocoder/common/autocoderargs_parser/__init__.py +14 -0
- autocoder/common/autocoderargs_parser/parser.py +184 -0
- autocoder/common/autocoderargs_parser/tests/__init__.py +1 -0
- autocoder/common/autocoderargs_parser/tests/test_args_parser.py +235 -0
- autocoder/common/autocoderargs_parser/tests/test_token_parser.py +195 -0
- autocoder/common/autocoderargs_parser/token_parser.py +290 -0
- autocoder/common/buildin_tokenizer.py +2 -4
- autocoder/common/code_auto_generate.py +149 -74
- autocoder/common/code_auto_generate_diff.py +163 -70
- autocoder/common/code_auto_generate_editblock.py +179 -89
- autocoder/common/code_auto_generate_strict_diff.py +167 -72
- autocoder/common/code_auto_merge_editblock.py +13 -6
- autocoder/common/code_modification_ranker.py +1 -1
- autocoder/common/command_completer.py +3 -3
- autocoder/common/command_file_manager/manager.py +183 -47
- autocoder/common/command_file_manager/test_command_file_manager.py +507 -0
- autocoder/common/command_templates.py +1 -1
- autocoder/common/conf_utils.py +2 -4
- autocoder/common/conversations/config.py +11 -3
- autocoder/common/conversations/get_conversation_manager.py +100 -2
- autocoder/common/conversations/llm_stats_models.py +264 -0
- autocoder/common/conversations/manager.py +112 -28
- autocoder/common/conversations/models.py +16 -2
- autocoder/common/conversations/storage/index_manager.py +134 -10
- autocoder/common/core_config/__init__.py +63 -0
- autocoder/common/core_config/agentic_mode_manager.py +109 -0
- autocoder/common/core_config/base_manager.py +123 -0
- autocoder/common/core_config/compatibility.py +151 -0
- autocoder/common/core_config/config_manager.py +156 -0
- autocoder/common/core_config/conversation_manager.py +31 -0
- autocoder/common/core_config/exclude_manager.py +72 -0
- autocoder/common/core_config/file_manager.py +177 -0
- autocoder/common/core_config/human_as_model_manager.py +129 -0
- autocoder/common/core_config/lib_manager.py +54 -0
- autocoder/common/core_config/main_manager.py +81 -0
- autocoder/common/core_config/mode_manager.py +126 -0
- autocoder/common/core_config/models.py +70 -0
- autocoder/common/core_config/test_memory_manager.py +1056 -0
- autocoder/common/env_manager.py +282 -0
- autocoder/common/env_manager_usage_example.py +211 -0
- autocoder/common/file_checkpoint/conversation_checkpoint.py +19 -19
- autocoder/common/file_checkpoint/manager.py +264 -48
- autocoder/common/file_checkpoint/test_backup.py +1 -18
- autocoder/common/file_checkpoint/test_manager.py +270 -1
- autocoder/common/file_checkpoint/test_store.py +1 -17
- autocoder/common/file_handler/__init__.py +23 -0
- autocoder/common/file_handler/active_context_handler.py +159 -0
- autocoder/common/file_handler/add_files_handler.py +409 -0
- autocoder/common/file_handler/chat_handler.py +180 -0
- autocoder/common/file_handler/coding_handler.py +401 -0
- autocoder/common/file_handler/commit_handler.py +200 -0
- autocoder/common/file_handler/lib_handler.py +156 -0
- autocoder/common/file_handler/list_files_handler.py +111 -0
- autocoder/common/file_handler/mcp_handler.py +268 -0
- autocoder/common/file_handler/models_handler.py +493 -0
- autocoder/common/file_handler/remove_files_handler.py +172 -0
- autocoder/common/file_monitor/test_file_monitor.py +307 -0
- autocoder/common/git_utils.py +51 -10
- autocoder/common/global_cancel.py +15 -6
- autocoder/common/ignorefiles/test_ignore_file_utils.py +1 -1
- autocoder/common/international/__init__.py +31 -0
- autocoder/common/international/demo_international.py +92 -0
- autocoder/common/international/message_manager.py +157 -0
- autocoder/common/international/messages/__init__.py +56 -0
- autocoder/common/international/messages/async_command_messages.py +507 -0
- autocoder/common/international/messages/auto_coder_messages.py +2208 -0
- autocoder/common/international/messages/chat_auto_coder_messages.py +1547 -0
- autocoder/common/international/messages/command_help_messages.py +986 -0
- autocoder/common/international/messages/conversation_command_messages.py +191 -0
- autocoder/common/international/messages/git_helper_plugin_messages.py +159 -0
- autocoder/common/international/messages/queue_command_messages.py +751 -0
- autocoder/common/international/messages/rules_command_messages.py +77 -0
- autocoder/common/international/messages/sdk_messages.py +1707 -0
- autocoder/common/international/messages/token_helper_plugin_messages.py +361 -0
- autocoder/common/international/messages/tool_display_messages.py +1212 -0
- autocoder/common/international/messages/workflow_exception_messages.py +473 -0
- autocoder/common/international/test_international.py +612 -0
- autocoder/common/linter_core/__init__.py +28 -0
- autocoder/common/linter_core/base_linter.py +61 -0
- autocoder/common/linter_core/config_loader.py +271 -0
- autocoder/common/linter_core/formatters/__init__.py +0 -0
- autocoder/common/linter_core/formatters/base_formatter.py +38 -0
- autocoder/common/linter_core/formatters/raw_formatter.py +17 -0
- autocoder/common/linter_core/linter.py +166 -0
- autocoder/common/linter_core/linter_factory.py +216 -0
- autocoder/common/linter_core/linter_manager.py +333 -0
- autocoder/common/linter_core/linters/__init__.py +9 -0
- autocoder/common/linter_core/linters/java_linter.py +342 -0
- autocoder/common/linter_core/linters/python_linter.py +115 -0
- autocoder/common/linter_core/linters/typescript_linter.py +119 -0
- autocoder/common/linter_core/models/__init__.py +7 -0
- autocoder/common/linter_core/models/lint_result.py +91 -0
- autocoder/common/linter_core/models.py +33 -0
- autocoder/common/linter_core/tests/__init__.py +3 -0
- autocoder/common/linter_core/tests/test_config_loader.py +323 -0
- autocoder/common/linter_core/tests/test_config_loading.py +308 -0
- autocoder/common/linter_core/tests/test_factory_manager.py +234 -0
- autocoder/common/linter_core/tests/test_formatters.py +147 -0
- autocoder/common/linter_core/tests/test_integration.py +317 -0
- autocoder/common/linter_core/tests/test_java_linter.py +496 -0
- autocoder/common/linter_core/tests/test_linters.py +265 -0
- autocoder/common/linter_core/tests/test_models.py +81 -0
- autocoder/common/linter_core/tests/verify_config_loading.py +296 -0
- autocoder/common/linter_core/tests/verify_fixes.py +183 -0
- autocoder/common/llm_friendly_package/__init__.py +31 -0
- autocoder/common/llm_friendly_package/base_manager.py +102 -0
- autocoder/common/llm_friendly_package/docs_manager.py +121 -0
- autocoder/common/llm_friendly_package/library_manager.py +171 -0
- autocoder/common/{llm_friendly_package.py → llm_friendly_package/main_manager.py} +204 -231
- autocoder/common/llm_friendly_package/models.py +40 -0
- autocoder/common/llm_friendly_package/test_llm_friendly_package.py +536 -0
- autocoder/common/llms/__init__.py +15 -0
- autocoder/common/llms/demo_error_handling.py +85 -0
- autocoder/common/llms/factory.py +142 -0
- autocoder/common/llms/manager.py +264 -0
- autocoder/common/llms/pricing.py +121 -0
- autocoder/common/llms/registry.py +288 -0
- autocoder/common/llms/schema.py +77 -0
- autocoder/common/llms/simple_demo.py +45 -0
- autocoder/common/llms/test_quick_model.py +116 -0
- autocoder/common/llms/test_remove_functionality.py +182 -0
- autocoder/common/llms/tests/__init__.py +1 -0
- autocoder/common/llms/tests/test_manager.py +330 -0
- autocoder/common/llms/tests/test_registry.py +364 -0
- autocoder/common/mcp_tools/__init__.py +62 -0
- autocoder/common/{mcp_tools.py → mcp_tools/executor.py} +49 -40
- autocoder/common/{mcp_hub.py → mcp_tools/hub.py} +42 -68
- autocoder/common/{mcp_server_install.py → mcp_tools/installer.py} +16 -28
- autocoder/common/{mcp_server.py → mcp_tools/server.py} +176 -48
- autocoder/common/mcp_tools/test_keyboard_interrupt.py +93 -0
- autocoder/common/mcp_tools/test_mcp_tools.py +391 -0
- autocoder/common/{mcp_server_types.py → mcp_tools/types.py} +121 -48
- autocoder/common/mcp_tools/verify_functionality.py +202 -0
- autocoder/common/model_speed_tester.py +32 -26
- autocoder/common/priority_directory_finder/__init__.py +142 -0
- autocoder/common/priority_directory_finder/examples.py +230 -0
- autocoder/common/priority_directory_finder/finder.py +283 -0
- autocoder/common/priority_directory_finder/models.py +236 -0
- autocoder/common/priority_directory_finder/test_priority_directory_finder.py +431 -0
- autocoder/common/project_scanner/__init__.py +18 -0
- autocoder/common/project_scanner/compat.py +77 -0
- autocoder/common/project_scanner/scanner.py +436 -0
- autocoder/common/project_tracker/__init__.py +27 -0
- autocoder/common/project_tracker/api.py +228 -0
- autocoder/common/project_tracker/demo.py +272 -0
- autocoder/common/project_tracker/tracker.py +487 -0
- autocoder/common/project_tracker/types.py +53 -0
- autocoder/common/pruner/__init__.py +67 -0
- autocoder/common/pruner/agentic_conversation_pruner.py +746 -0
- autocoder/common/{context_pruner.py → pruner/context_pruner.py} +137 -40
- autocoder/common/pruner/conversation_message_ids_api.py +386 -0
- autocoder/common/pruner/conversation_message_ids_manager.py +347 -0
- autocoder/common/pruner/conversation_message_ids_pruner.py +473 -0
- autocoder/common/pruner/conversation_normalizer.py +347 -0
- autocoder/common/{conversation_pruner.py → pruner/conversation_pruner.py} +26 -6
- autocoder/common/pruner/test_agentic_conversation_pruner.py +784 -0
- autocoder/common/pruner/test_context_pruner.py +546 -0
- autocoder/common/pruner/test_conversation_normalizer.py +502 -0
- autocoder/common/pruner/test_tool_content_detector.py +324 -0
- autocoder/common/pruner/tool_content_detector.py +227 -0
- autocoder/common/pruner/tools/__init__.py +18 -0
- autocoder/common/pruner/tools/query_message_ids.py +264 -0
- autocoder/common/pruner/tools/test_agentic_pruning_logic.py +432 -0
- autocoder/common/pruner/tools/test_message_ids_pruning_only.py +192 -0
- autocoder/common/pull_requests/__init__.py +9 -1
- autocoder/common/pull_requests/utils.py +122 -1
- autocoder/common/rag_manager/rag_manager.py +36 -40
- autocoder/common/rulefiles/__init__.py +53 -1
- autocoder/common/rulefiles/api.py +250 -0
- autocoder/common/rulefiles/core/__init__.py +14 -0
- autocoder/common/rulefiles/core/manager.py +241 -0
- autocoder/common/rulefiles/core/selector.py +805 -0
- autocoder/common/rulefiles/models/__init__.py +20 -0
- autocoder/common/rulefiles/models/index.py +16 -0
- autocoder/common/rulefiles/models/init_rule.py +18 -0
- autocoder/common/rulefiles/models/rule_file.py +18 -0
- autocoder/common/rulefiles/models/rule_relevance.py +14 -0
- autocoder/common/rulefiles/models/summary.py +16 -0
- autocoder/common/rulefiles/test_rulefiles.py +776 -0
- autocoder/common/rulefiles/utils/__init__.py +34 -0
- autocoder/common/rulefiles/utils/monitor.py +86 -0
- autocoder/common/rulefiles/utils/parser.py +230 -0
- autocoder/common/save_formatted_log.py +67 -10
- autocoder/common/search_replace.py +8 -1
- autocoder/common/search_replace_patch/__init__.py +24 -0
- autocoder/common/search_replace_patch/base.py +115 -0
- autocoder/common/search_replace_patch/manager.py +248 -0
- autocoder/common/search_replace_patch/patch_replacer.py +304 -0
- autocoder/common/search_replace_patch/similarity_replacer.py +306 -0
- autocoder/common/search_replace_patch/string_replacer.py +181 -0
- autocoder/common/search_replace_patch/tests/__init__.py +3 -0
- autocoder/common/search_replace_patch/tests/run_tests.py +126 -0
- autocoder/common/search_replace_patch/tests/test_base.py +188 -0
- autocoder/common/search_replace_patch/tests/test_empty_line_insert.py +233 -0
- autocoder/common/search_replace_patch/tests/test_integration.py +389 -0
- autocoder/common/search_replace_patch/tests/test_manager.py +351 -0
- autocoder/common/search_replace_patch/tests/test_patch_replacer.py +316 -0
- autocoder/common/search_replace_patch/tests/test_regex_replacer.py +306 -0
- autocoder/common/search_replace_patch/tests/test_similarity_replacer.py +384 -0
- autocoder/common/shell_commands/__init__.py +197 -0
- autocoder/common/shell_commands/background_process_notifier.py +346 -0
- autocoder/common/shell_commands/command_executor.py +1127 -0
- autocoder/common/shell_commands/error_recovery.py +541 -0
- autocoder/common/shell_commands/exceptions.py +120 -0
- autocoder/common/shell_commands/interactive_executor.py +476 -0
- autocoder/common/shell_commands/interactive_pexpect_process.py +623 -0
- autocoder/common/shell_commands/interactive_process.py +744 -0
- autocoder/common/shell_commands/interactive_session_manager.py +1014 -0
- autocoder/common/shell_commands/monitoring.py +529 -0
- autocoder/common/shell_commands/process_cleanup.py +386 -0
- autocoder/common/shell_commands/process_manager.py +606 -0
- autocoder/common/shell_commands/test_interactive_pexpect_process.py +281 -0
- autocoder/common/shell_commands/tests/__init__.py +6 -0
- autocoder/common/shell_commands/tests/conftest.py +118 -0
- autocoder/common/shell_commands/tests/test_background_process_notifier.py +703 -0
- autocoder/common/shell_commands/tests/test_command_executor.py +448 -0
- autocoder/common/shell_commands/tests/test_error_recovery.py +305 -0
- autocoder/common/shell_commands/tests/test_exceptions.py +299 -0
- autocoder/common/shell_commands/tests/test_execute_batch.py +588 -0
- autocoder/common/shell_commands/tests/test_indented_batch_commands.py +244 -0
- autocoder/common/shell_commands/tests/test_integration.py +664 -0
- autocoder/common/shell_commands/tests/test_monitoring.py +546 -0
- autocoder/common/shell_commands/tests/test_performance.py +632 -0
- autocoder/common/shell_commands/tests/test_process_cleanup.py +397 -0
- autocoder/common/shell_commands/tests/test_process_manager.py +606 -0
- autocoder/common/shell_commands/tests/test_timeout_config.py +343 -0
- autocoder/common/shell_commands/tests/test_timeout_manager.py +520 -0
- autocoder/common/shell_commands/timeout_config.py +315 -0
- autocoder/common/shell_commands/timeout_manager.py +352 -0
- autocoder/common/terminal_paste/__init__.py +14 -0
- autocoder/common/terminal_paste/demo.py +145 -0
- autocoder/common/terminal_paste/demo_paste_functionality.py +95 -0
- autocoder/common/terminal_paste/paste_handler.py +200 -0
- autocoder/common/terminal_paste/paste_manager.py +118 -0
- autocoder/common/terminal_paste/tests/__init__.py +1 -0
- autocoder/common/terminal_paste/tests/test_paste_handler.py +182 -0
- autocoder/common/terminal_paste/tests/test_paste_manager.py +126 -0
- autocoder/common/terminal_paste/utils.py +163 -0
- autocoder/common/test_autocoder_args.py +232 -0
- autocoder/common/test_env_manager.py +173 -0
- autocoder/common/test_env_manager_integration.py +159 -0
- autocoder/common/text_similarity/__init__.py +9 -0
- autocoder/common/text_similarity/demo.py +216 -0
- autocoder/common/text_similarity/examples.py +266 -0
- autocoder/common/text_similarity/test_text_similarity.py +306 -0
- autocoder/common/text_similarity/text_similarity.py +194 -0
- autocoder/common/text_similarity/utils.py +125 -0
- autocoder/common/todos/__init__.py +61 -0
- autocoder/common/todos/cache/__init__.py +16 -0
- autocoder/common/todos/cache/base_cache.py +89 -0
- autocoder/common/todos/cache/cache_manager.py +228 -0
- autocoder/common/todos/cache/memory_cache.py +225 -0
- autocoder/common/todos/config.py +155 -0
- autocoder/common/todos/exceptions.py +35 -0
- autocoder/common/todos/get_todo_manager.py +161 -0
- autocoder/common/todos/manager.py +537 -0
- autocoder/common/todos/models.py +239 -0
- autocoder/common/todos/storage/__init__.py +14 -0
- autocoder/common/todos/storage/base_storage.py +76 -0
- autocoder/common/todos/storage/file_storage.py +278 -0
- autocoder/common/tokens/__init__.py +15 -0
- autocoder/common/tokens/counter.py +44 -2
- autocoder/common/tools_manager/__init__.py +17 -0
- autocoder/common/tools_manager/examples.py +162 -0
- autocoder/common/tools_manager/manager.py +385 -0
- autocoder/common/tools_manager/models.py +39 -0
- autocoder/common/tools_manager/test_tools_manager.py +303 -0
- autocoder/common/tools_manager/utils.py +191 -0
- autocoder/common/v2/agent/agentic_callbacks.py +270 -0
- autocoder/common/v2/agent/agentic_edit.py +2729 -2052
- autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
- autocoder/common/v2/agent/agentic_edit_tools/__init__.py +43 -2
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_read_tool_resolver.py +40 -0
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +52 -0
- autocoder/common/v2/agent/agentic_edit_tools/ask_followup_question_tool_resolver.py +8 -0
- autocoder/common/v2/agent/agentic_edit_tools/background_task_tool_resolver.py +1167 -0
- autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +2 -2
- autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_read_tool_resolver.py +214 -0
- autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_write_tool_resolver.py +299 -0
- autocoder/common/v2/agent/agentic_edit_tools/count_tokens_tool_resolver.py +290 -0
- autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +565 -30
- autocoder/common/v2/agent/agentic_edit_tools/execute_workflow_tool_resolver.py +485 -0
- autocoder/common/v2/agent/agentic_edit_tools/extract_to_text_tool_resolver.py +225 -0
- autocoder/common/v2/agent/agentic_edit_tools/lint_report.py +79 -0
- autocoder/common/v2/agent/agentic_edit_tools/linter_config_models.py +343 -0
- autocoder/common/v2/agent/agentic_edit_tools/linter_enabled_tool_resolver.py +189 -0
- autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +169 -101
- autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +349 -0
- autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +244 -51
- autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +667 -147
- autocoder/common/v2/agent/agentic_edit_tools/run_named_subagents_tool_resolver.py +691 -0
- autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +409 -140
- autocoder/common/v2/agent/agentic_edit_tools/session_interactive_tool_resolver.py +115 -0
- autocoder/common/v2/agent/agentic_edit_tools/session_start_tool_resolver.py +190 -0
- autocoder/common/v2/agent/agentic_edit_tools/session_stop_tool_resolver.py +76 -0
- autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +209 -194
- autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +135 -0
- autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +328 -0
- autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +2 -2
- autocoder/common/v2/agent/agentic_edit_tools/web_crawl_tool_resolver.py +557 -0
- autocoder/common/v2/agent/agentic_edit_tools/web_search_tool_resolver.py +600 -0
- autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +56 -121
- autocoder/common/v2/agent/agentic_edit_types.py +386 -10
- autocoder/common/v2/agent/runner/__init__.py +31 -0
- autocoder/common/v2/agent/runner/base_runner.py +92 -0
- autocoder/common/v2/agent/runner/file_based_event_runner.py +217 -0
- autocoder/common/v2/agent/runner/sdk_runner.py +182 -0
- autocoder/common/v2/agent/runner/terminal_runner.py +396 -0
- autocoder/common/v2/agent/runner/tool_display.py +589 -0
- autocoder/common/v2/agent/test_agentic_callbacks.py +265 -0
- autocoder/common/v2/agent/test_agentic_edit.py +194 -0
- autocoder/common/v2/agent/tool_caller/__init__.py +24 -0
- autocoder/common/v2/agent/tool_caller/default_tool_resolver_map.py +135 -0
- autocoder/common/v2/agent/tool_caller/integration_test.py +172 -0
- autocoder/common/v2/agent/tool_caller/plugins/__init__.py +14 -0
- autocoder/common/v2/agent/tool_caller/plugins/base_plugin.py +126 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/__init__.py +13 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/logging_plugin.py +164 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/security_filter_plugin.py +198 -0
- autocoder/common/v2/agent/tool_caller/plugins/plugin_interface.py +141 -0
- autocoder/common/v2/agent/tool_caller/test_tool_caller.py +278 -0
- autocoder/common/v2/agent/tool_caller/tool_call_plugin_manager.py +331 -0
- autocoder/common/v2/agent/tool_caller/tool_caller.py +337 -0
- autocoder/common/v2/agent/tool_caller/usage_example.py +193 -0
- autocoder/common/v2/code_agentic_editblock_manager.py +4 -4
- autocoder/common/v2/code_auto_generate.py +136 -78
- autocoder/common/v2/code_auto_generate_diff.py +135 -79
- autocoder/common/v2/code_auto_generate_editblock.py +174 -99
- autocoder/common/v2/code_auto_generate_strict_diff.py +151 -71
- autocoder/common/v2/code_auto_merge.py +1 -1
- autocoder/common/v2/code_auto_merge_editblock.py +13 -1
- autocoder/common/v2/code_diff_manager.py +3 -3
- autocoder/common/v2/code_editblock_manager.py +4 -14
- autocoder/common/v2/code_manager.py +1 -1
- autocoder/common/v2/code_strict_diff_manager.py +2 -2
- autocoder/common/wrap_llm_hint/__init__.py +10 -0
- autocoder/common/wrap_llm_hint/test_wrap_llm_hint.py +1067 -0
- autocoder/common/wrap_llm_hint/utils.py +432 -0
- autocoder/common/wrap_llm_hint/wrap_llm_hint.py +323 -0
- autocoder/completer/__init__.py +8 -0
- autocoder/completer/command_completer_v2.py +1051 -0
- autocoder/default_project/__init__.py +501 -0
- autocoder/dispacher/__init__.py +4 -12
- autocoder/dispacher/actions/action.py +165 -7
- autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
- autocoder/index/entry.py +117 -125
- autocoder/{agent → index/filter}/agentic_filter.py +323 -334
- autocoder/index/filter/normal_filter.py +5 -11
- autocoder/index/filter/quick_filter.py +1 -1
- autocoder/index/index.py +36 -9
- autocoder/index/tests/__init__.py +1 -0
- autocoder/index/tests/run_tests.py +195 -0
- autocoder/index/tests/test_entry.py +303 -0
- autocoder/index/tests/test_index_manager.py +314 -0
- autocoder/index/tests/test_module_integration.py +300 -0
- autocoder/index/tests/test_symbols_utils.py +183 -0
- autocoder/inner/__init__.py +4 -0
- autocoder/inner/agentic.py +932 -0
- autocoder/inner/async_command_handler.py +992 -0
- autocoder/inner/conversation_command_handlers.py +623 -0
- autocoder/inner/merge_command_handler.py +213 -0
- autocoder/inner/queue_command_handler.py +684 -0
- autocoder/models.py +95 -266
- autocoder/plugins/git_helper_plugin.py +31 -29
- autocoder/plugins/token_helper_plugin.py +156 -37
- autocoder/pyproject/__init__.py +32 -29
- autocoder/rag/agentic_rag.py +215 -75
- autocoder/rag/cache/simple_cache.py +1 -2
- autocoder/rag/loaders/image_loader.py +1 -1
- autocoder/rag/long_context_rag.py +42 -26
- autocoder/rag/qa_conversation_strategy.py +1 -1
- autocoder/rag/terminal/__init__.py +17 -0
- autocoder/rag/terminal/args.py +581 -0
- autocoder/rag/terminal/bootstrap.py +61 -0
- autocoder/rag/terminal/command_handlers.py +653 -0
- autocoder/rag/terminal/formatters/__init__.py +20 -0
- autocoder/rag/terminal/formatters/base.py +70 -0
- autocoder/rag/terminal/formatters/json_format.py +66 -0
- autocoder/rag/terminal/formatters/stream_json.py +95 -0
- autocoder/rag/terminal/formatters/text.py +28 -0
- autocoder/rag/terminal/init.py +120 -0
- autocoder/rag/terminal/utils.py +106 -0
- autocoder/rag/test_agentic_rag.py +389 -0
- autocoder/rag/test_doc_filter.py +3 -3
- autocoder/rag/test_long_context_rag.py +1 -1
- autocoder/rag/test_token_limiter.py +517 -10
- autocoder/rag/token_counter.py +3 -0
- autocoder/rag/token_limiter.py +19 -15
- autocoder/rag/tools/__init__.py +26 -2
- autocoder/rag/tools/bochaai_example.py +343 -0
- autocoder/rag/tools/bochaai_sdk.py +541 -0
- autocoder/rag/tools/metaso_example.py +268 -0
- autocoder/rag/tools/metaso_sdk.py +417 -0
- autocoder/rag/tools/recall_tool.py +28 -7
- autocoder/rag/tools/run_integration_tests.py +204 -0
- autocoder/rag/tools/test_all_providers.py +318 -0
- autocoder/rag/tools/test_bochaai_integration.py +482 -0
- autocoder/rag/tools/test_final_integration.py +215 -0
- autocoder/rag/tools/test_metaso_integration.py +424 -0
- autocoder/rag/tools/test_metaso_real.py +171 -0
- autocoder/rag/tools/test_web_crawl_tool.py +639 -0
- autocoder/rag/tools/test_web_search_tool.py +509 -0
- autocoder/rag/tools/todo_read_tool.py +202 -0
- autocoder/rag/tools/todo_write_tool.py +412 -0
- autocoder/rag/tools/web_crawl_tool.py +634 -0
- autocoder/rag/tools/web_search_tool.py +558 -0
- autocoder/rag/tools/web_tools_example.py +119 -0
- autocoder/rag/types.py +16 -0
- autocoder/rag/variable_holder.py +4 -2
- autocoder/rags.py +86 -79
- autocoder/regexproject/__init__.py +23 -21
- autocoder/run_context.py +9 -0
- autocoder/sdk/__init__.py +50 -161
- autocoder/sdk/api.py +370 -0
- autocoder/sdk/async_runner/__init__.py +26 -0
- autocoder/sdk/async_runner/async_executor.py +650 -0
- autocoder/sdk/async_runner/async_handler.py +356 -0
- autocoder/sdk/async_runner/markdown_processor.py +595 -0
- autocoder/sdk/async_runner/task_metadata.py +284 -0
- autocoder/sdk/async_runner/worktree_manager.py +438 -0
- autocoder/sdk/cli/__init__.py +2 -5
- autocoder/sdk/cli/formatters.py +28 -204
- autocoder/sdk/cli/handlers.py +77 -44
- autocoder/sdk/cli/main.py +158 -170
- autocoder/sdk/cli/options.py +95 -22
- autocoder/sdk/constants.py +139 -51
- autocoder/sdk/core/auto_coder_core.py +484 -267
- autocoder/sdk/core/bridge.py +298 -118
- autocoder/sdk/exceptions.py +18 -12
- autocoder/sdk/formatters/__init__.py +19 -0
- autocoder/sdk/formatters/input.py +64 -0
- autocoder/sdk/formatters/output.py +247 -0
- autocoder/sdk/formatters/stream.py +54 -0
- autocoder/sdk/models/__init__.py +6 -5
- autocoder/sdk/models/options.py +55 -18
- autocoder/sdk/utils/formatters.py +27 -195
- autocoder/suffixproject/__init__.py +28 -25
- autocoder/terminal/__init__.py +14 -0
- autocoder/terminal/app.py +454 -0
- autocoder/terminal/args.py +32 -0
- autocoder/terminal/bootstrap.py +178 -0
- autocoder/terminal/command_processor.py +521 -0
- autocoder/terminal/command_registry.py +57 -0
- autocoder/terminal/help.py +97 -0
- autocoder/terminal/tasks/__init__.py +5 -0
- autocoder/terminal/tasks/background.py +77 -0
- autocoder/terminal/tasks/task_event.py +70 -0
- autocoder/terminal/ui/__init__.py +13 -0
- autocoder/terminal/ui/completer.py +268 -0
- autocoder/terminal/ui/keybindings.py +75 -0
- autocoder/terminal/ui/session.py +41 -0
- autocoder/terminal/ui/toolbar.py +64 -0
- autocoder/terminal/utils/__init__.py +13 -0
- autocoder/terminal/utils/errors.py +18 -0
- autocoder/terminal/utils/paths.py +19 -0
- autocoder/terminal/utils/shell.py +43 -0
- autocoder/terminal_v3/__init__.py +10 -0
- autocoder/terminal_v3/app.py +201 -0
- autocoder/terminal_v3/handlers/__init__.py +5 -0
- autocoder/terminal_v3/handlers/command_handler.py +131 -0
- autocoder/terminal_v3/models/__init__.py +6 -0
- autocoder/terminal_v3/models/conversation_buffer.py +214 -0
- autocoder/terminal_v3/models/message.py +50 -0
- autocoder/terminal_v3/models/tool_display.py +247 -0
- autocoder/terminal_v3/ui/__init__.py +7 -0
- autocoder/terminal_v3/ui/keybindings.py +56 -0
- autocoder/terminal_v3/ui/layout.py +141 -0
- autocoder/terminal_v3/ui/styles.py +43 -0
- autocoder/tsproject/__init__.py +23 -23
- autocoder/utils/auto_coder_utils/chat_stream_out.py +1 -1
- autocoder/utils/llms.py +88 -80
- autocoder/utils/math_utils.py +101 -0
- autocoder/utils/model_provider_selector.py +16 -4
- autocoder/utils/operate_config_api.py +33 -5
- autocoder/utils/thread_utils.py +2 -2
- autocoder/version.py +4 -2
- autocoder/workflow_agents/__init__.py +84 -0
- autocoder/workflow_agents/agent.py +143 -0
- autocoder/workflow_agents/exceptions.py +573 -0
- autocoder/workflow_agents/executor.py +489 -0
- autocoder/workflow_agents/loader.py +737 -0
- autocoder/workflow_agents/runner.py +267 -0
- autocoder/workflow_agents/types.py +172 -0
- autocoder/workflow_agents/utils.py +434 -0
- autocoder/workflow_agents/workflow_manager.py +211 -0
- auto_coder-0.1.400.dist-info/METADATA +0 -396
- auto_coder-0.1.400.dist-info/RECORD +0 -425
- auto_coder-0.1.400.dist-info/licenses/LICENSE +0 -201
- autocoder/auto_coder_server.py +0 -672
- autocoder/benchmark.py +0 -138
- autocoder/common/ac_style_command_parser/example.py +0 -7
- autocoder/common/cleaner.py +0 -31
- autocoder/common/command_completer_v2.py +0 -615
- autocoder/common/directory_cache/__init__.py +0 -1
- autocoder/common/directory_cache/cache.py +0 -192
- autocoder/common/directory_cache/test_cache.py +0 -190
- autocoder/common/file_checkpoint/examples.py +0 -217
- autocoder/common/llm_friendly_package_example.py +0 -138
- autocoder/common/llm_friendly_package_test.py +0 -63
- autocoder/common/pull_requests/test_module.py +0 -1
- autocoder/common/rulefiles/autocoderrules_utils.py +0 -484
- autocoder/common/text.py +0 -30
- autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py +0 -42
- autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.py +0 -70
- autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py +0 -163
- autocoder/common/v2/agent/agentic_tool_display.py +0 -183
- autocoder/plugins/dynamic_completion_example.py +0 -148
- autocoder/plugins/sample_plugin.py +0 -160
- autocoder/sdk/cli/__main__.py +0 -26
- autocoder/sdk/cli/completion_wrapper.py +0 -38
- autocoder/sdk/cli/install_completion.py +0 -301
- autocoder/sdk/models/messages.py +0 -209
- autocoder/sdk/session/__init__.py +0 -32
- autocoder/sdk/session/session.py +0 -106
- autocoder/sdk/session/session_manager.py +0 -56
- {auto_coder-0.1.400.dist-info → auto_coder-2.0.0.dist-info}/top_level.txt +0 -0
- /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Test module for SearchReplaceManager
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import unittest
|
|
6
|
+
from unittest.mock import patch, MagicMock
|
|
7
|
+
|
|
8
|
+
from ..manager import SearchReplaceManager
|
|
9
|
+
from ..base import ReplaceStrategy, ReplaceResult
|
|
10
|
+
from ..string_replacer import StringReplacer
|
|
11
|
+
from ..patch_replacer import PatchReplacer
|
|
12
|
+
from ..similarity_replacer import SimilarityReplacer
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestSearchReplaceManager(unittest.TestCase):
|
|
16
|
+
"""Test SearchReplaceManager functionality"""
|
|
17
|
+
|
|
18
|
+
def setUp(self):
|
|
19
|
+
"""Set up test fixtures"""
|
|
20
|
+
self.manager = SearchReplaceManager()
|
|
21
|
+
self.custom_manager = SearchReplaceManager(default_strategy=ReplaceStrategy.SIMILARITY)
|
|
22
|
+
|
|
23
|
+
def test_initialization(self):
|
|
24
|
+
"""Test proper initialization"""
|
|
25
|
+
self.assertEqual(self.manager.default_strategy, ReplaceStrategy.STRING)
|
|
26
|
+
self.assertEqual(self.custom_manager.default_strategy, ReplaceStrategy.SIMILARITY)
|
|
27
|
+
|
|
28
|
+
# Check that replacers are initialized
|
|
29
|
+
self.assertIsInstance(self.manager.replacers.get(ReplaceStrategy.STRING), StringReplacer)
|
|
30
|
+
|
|
31
|
+
def test_get_replacer(self):
|
|
32
|
+
"""Test getting replacer by strategy"""
|
|
33
|
+
string_replacer = self.manager.get_replacer(ReplaceStrategy.STRING)
|
|
34
|
+
self.assertIsInstance(string_replacer, StringReplacer)
|
|
35
|
+
|
|
36
|
+
similarity_replacer = self.manager.get_replacer(ReplaceStrategy.SIMILARITY)
|
|
37
|
+
self.assertIsInstance(similarity_replacer, SimilarityReplacer)
|
|
38
|
+
|
|
39
|
+
# Test non-existent strategy
|
|
40
|
+
non_existent = self.manager.get_replacer(ReplaceStrategy.PATCH)
|
|
41
|
+
if non_existent:
|
|
42
|
+
self.assertIsInstance(non_existent, PatchReplacer)
|
|
43
|
+
|
|
44
|
+
def test_replace_with_default_strategy(self):
|
|
45
|
+
"""Test replace using default strategy"""
|
|
46
|
+
content = "Hello world\n"
|
|
47
|
+
search_blocks = [("Hello world", "Hello AutoCoder")]
|
|
48
|
+
|
|
49
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'replace') as mock_replace:
|
|
50
|
+
mock_replace.return_value = ReplaceResult(success=True, message="Success", new_content="Hello AutoCoder\n")
|
|
51
|
+
|
|
52
|
+
result = self.manager.replace(content, search_blocks)
|
|
53
|
+
|
|
54
|
+
self.assertTrue(result.success)
|
|
55
|
+
self.assertEqual(result.new_content, "Hello AutoCoder\n")
|
|
56
|
+
mock_replace.assert_called_once_with(content, search_blocks)
|
|
57
|
+
|
|
58
|
+
def test_replace_with_specified_strategy(self):
|
|
59
|
+
"""Test replace using specified strategy"""
|
|
60
|
+
content = "Hello world\n"
|
|
61
|
+
search_blocks = [("Hello world", "Hello AutoCoder")]
|
|
62
|
+
|
|
63
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'replace') as mock_replace:
|
|
64
|
+
mock_replace.return_value = ReplaceResult(success=True, message="Success", new_content="Hello AutoCoder\n")
|
|
65
|
+
|
|
66
|
+
result = self.manager.replace(content, search_blocks, ReplaceStrategy.SIMILARITY)
|
|
67
|
+
|
|
68
|
+
self.assertTrue(result.success)
|
|
69
|
+
self.assertEqual(result.new_content, "Hello AutoCoder\n")
|
|
70
|
+
mock_replace.assert_called_once_with(content, search_blocks)
|
|
71
|
+
|
|
72
|
+
def test_replace_with_unavailable_strategy(self):
|
|
73
|
+
"""Test replace with unavailable strategy"""
|
|
74
|
+
content = "Hello world"
|
|
75
|
+
search_blocks = [("world", "AutoCoder")]
|
|
76
|
+
|
|
77
|
+
# Mock strategy not available
|
|
78
|
+
with patch.object(self.manager, 'get_replacer', return_value=None):
|
|
79
|
+
result = self.manager.replace(content, search_blocks, ReplaceStrategy.PATCH)
|
|
80
|
+
|
|
81
|
+
self.assertFalse(result.success)
|
|
82
|
+
self.assertIn("not available", result.message)
|
|
83
|
+
|
|
84
|
+
def test_replace_with_fallback_first_success(self):
|
|
85
|
+
"""Test fallback strategy when first strategy succeeds"""
|
|
86
|
+
content = "Hello world"
|
|
87
|
+
search_blocks = [("world", "AutoCoder")]
|
|
88
|
+
|
|
89
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'replace') as mock_regex_replace:
|
|
90
|
+
mock_regex_replace.return_value = ReplaceResult(success=True, message="Success", new_content="Hello AutoCoder")
|
|
91
|
+
|
|
92
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'can_handle', return_value=True):
|
|
93
|
+
result = self.manager.replace_with_fallback(content, search_blocks)
|
|
94
|
+
|
|
95
|
+
self.assertTrue(result.success)
|
|
96
|
+
self.assertEqual(result.new_content, "Hello AutoCoder")
|
|
97
|
+
self.assertEqual(result.metadata['used_strategy'], 'string')
|
|
98
|
+
mock_regex_replace.assert_called_once()
|
|
99
|
+
|
|
100
|
+
def test_replace_with_fallback_second_success(self):
|
|
101
|
+
"""Test fallback strategy when first fails, second succeeds"""
|
|
102
|
+
content = "Hello world"
|
|
103
|
+
search_blocks = [("world", "AutoCoder")]
|
|
104
|
+
|
|
105
|
+
# First strategy fails
|
|
106
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'replace') as mock_regex_replace:
|
|
107
|
+
mock_regex_replace.return_value = ReplaceResult(success=False, message="Failed")
|
|
108
|
+
|
|
109
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'can_handle', return_value=True):
|
|
110
|
+
# Second strategy succeeds
|
|
111
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'replace') as mock_similarity_replace:
|
|
112
|
+
mock_similarity_replace.return_value = ReplaceResult(success=True, message="Success", new_content="Hello AutoCoder")
|
|
113
|
+
|
|
114
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'can_handle', return_value=True):
|
|
115
|
+
result = self.manager.replace_with_fallback(content, search_blocks)
|
|
116
|
+
|
|
117
|
+
self.assertTrue(result.success)
|
|
118
|
+
self.assertEqual(result.new_content, "Hello AutoCoder")
|
|
119
|
+
self.assertEqual(result.metadata['used_strategy'], 'similarity')
|
|
120
|
+
mock_regex_replace.assert_called_once()
|
|
121
|
+
mock_similarity_replace.assert_called_once()
|
|
122
|
+
|
|
123
|
+
def test_replace_with_fallback_all_fail(self):
|
|
124
|
+
"""Test fallback strategy when all strategies fail"""
|
|
125
|
+
content = "Hello world"
|
|
126
|
+
search_blocks = [("world", "AutoCoder")]
|
|
127
|
+
|
|
128
|
+
# All strategies fail
|
|
129
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'replace') as mock_regex_replace:
|
|
130
|
+
mock_regex_replace.return_value = ReplaceResult(success=False, message="Failed")
|
|
131
|
+
|
|
132
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'can_handle', return_value=True):
|
|
133
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'replace') as mock_similarity_replace:
|
|
134
|
+
mock_similarity_replace.return_value = ReplaceResult(success=False, message="Failed")
|
|
135
|
+
|
|
136
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'can_handle', return_value=True):
|
|
137
|
+
result = self.manager.replace_with_fallback(content, search_blocks)
|
|
138
|
+
|
|
139
|
+
self.assertFalse(result.success)
|
|
140
|
+
self.assertIn('all_strategies_failed', result.metadata)
|
|
141
|
+
self.assertIn('tried_strategies', result.metadata)
|
|
142
|
+
|
|
143
|
+
def test_replace_with_fallback_custom_strategies(self):
|
|
144
|
+
"""Test fallback with custom strategy list"""
|
|
145
|
+
content = "Hello world"
|
|
146
|
+
search_blocks = [("world", "AutoCoder")]
|
|
147
|
+
strategies = [ReplaceStrategy.SIMILARITY, ReplaceStrategy.STRING]
|
|
148
|
+
|
|
149
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'replace') as mock_similarity_replace:
|
|
150
|
+
mock_similarity_replace.return_value = ReplaceResult(success=True, message="Success", new_content="Hello AutoCoder")
|
|
151
|
+
|
|
152
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'can_handle', return_value=True):
|
|
153
|
+
result = self.manager.replace_with_fallback(content, search_blocks, strategies)
|
|
154
|
+
|
|
155
|
+
self.assertTrue(result.success)
|
|
156
|
+
self.assertEqual(result.metadata['used_strategy'], 'similarity')
|
|
157
|
+
mock_similarity_replace.assert_called_once()
|
|
158
|
+
|
|
159
|
+
def test_replace_with_fallback_no_suitable_replacer(self):
|
|
160
|
+
"""Test fallback when no suitable replacer is found"""
|
|
161
|
+
content = "Hello world"
|
|
162
|
+
search_blocks = [("world", "AutoCoder")]
|
|
163
|
+
|
|
164
|
+
with patch.object(self.manager, 'get_replacer', return_value=None):
|
|
165
|
+
result = self.manager.replace_with_fallback(content, search_blocks)
|
|
166
|
+
|
|
167
|
+
self.assertFalse(result.success)
|
|
168
|
+
self.assertIn("No suitable replacer found", result.message)
|
|
169
|
+
|
|
170
|
+
def test_replace_with_fallback_replacer_cannot_handle(self):
|
|
171
|
+
"""Test fallback when replacer cannot handle content"""
|
|
172
|
+
content = "Hello world"
|
|
173
|
+
search_blocks = [("world", "AutoCoder")]
|
|
174
|
+
|
|
175
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'can_handle', return_value=False):
|
|
176
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'can_handle', return_value=False):
|
|
177
|
+
result = self.manager.replace_with_fallback(content, search_blocks)
|
|
178
|
+
|
|
179
|
+
self.assertFalse(result.success)
|
|
180
|
+
|
|
181
|
+
def test_get_available_strategies(self):
|
|
182
|
+
"""Test getting available strategies"""
|
|
183
|
+
strategies = self.manager.get_available_strategies()
|
|
184
|
+
|
|
185
|
+
self.assertIsInstance(strategies, list)
|
|
186
|
+
self.assertIn(ReplaceStrategy.STRING, strategies)
|
|
187
|
+
self.assertIn(ReplaceStrategy.SIMILARITY, strategies)
|
|
188
|
+
|
|
189
|
+
def test_set_default_strategy(self):
|
|
190
|
+
"""Test setting default strategy"""
|
|
191
|
+
original_default = self.manager.default_strategy
|
|
192
|
+
|
|
193
|
+
self.manager.set_default_strategy(ReplaceStrategy.SIMILARITY)
|
|
194
|
+
self.assertEqual(self.manager.default_strategy, ReplaceStrategy.SIMILARITY)
|
|
195
|
+
|
|
196
|
+
# Test setting unavailable strategy
|
|
197
|
+
with patch.object(self.manager, 'replacers', {ReplaceStrategy.STRING: MagicMock()}):
|
|
198
|
+
self.manager.set_default_strategy(ReplaceStrategy.PATCH)
|
|
199
|
+
self.assertEqual(self.manager.default_strategy, ReplaceStrategy.SIMILARITY) # Should not change
|
|
200
|
+
|
|
201
|
+
def test_configure_replacer_string(self):
|
|
202
|
+
"""Test configuring string replacer"""
|
|
203
|
+
string_replacer = self.manager.get_replacer(ReplaceStrategy.STRING)
|
|
204
|
+
if string_replacer and isinstance(string_replacer, StringReplacer):
|
|
205
|
+
original_lenient = string_replacer.lenient_mode
|
|
206
|
+
|
|
207
|
+
self.manager.configure_replacer(ReplaceStrategy.STRING, lenient_mode=False)
|
|
208
|
+
self.assertFalse(string_replacer.lenient_mode)
|
|
209
|
+
|
|
210
|
+
# Reset
|
|
211
|
+
string_replacer.lenient_mode = original_lenient
|
|
212
|
+
|
|
213
|
+
def test_configure_replacer_similarity(self):
|
|
214
|
+
"""Test configuring similarity replacer"""
|
|
215
|
+
similarity_replacer = self.manager.get_replacer(ReplaceStrategy.SIMILARITY)
|
|
216
|
+
if similarity_replacer and isinstance(similarity_replacer, SimilarityReplacer):
|
|
217
|
+
original_threshold = similarity_replacer.similarity_threshold
|
|
218
|
+
|
|
219
|
+
self.manager.configure_replacer(ReplaceStrategy.SIMILARITY, similarity_threshold=0.9)
|
|
220
|
+
self.assertEqual(similarity_replacer.similarity_threshold, 0.9)
|
|
221
|
+
|
|
222
|
+
# Reset
|
|
223
|
+
similarity_replacer.similarity_threshold = original_threshold
|
|
224
|
+
|
|
225
|
+
def test_configure_replacer_patch(self):
|
|
226
|
+
"""Test configuring patch replacer"""
|
|
227
|
+
patch_replacer = self.manager.get_replacer(ReplaceStrategy.PATCH)
|
|
228
|
+
if patch_replacer and isinstance(patch_replacer, PatchReplacer):
|
|
229
|
+
original_use_patch_ng = patch_replacer.use_patch_ng
|
|
230
|
+
|
|
231
|
+
with patch.object(patch_replacer, '_load_patch_module'):
|
|
232
|
+
self.manager.configure_replacer(ReplaceStrategy.PATCH, use_patch_ng=False)
|
|
233
|
+
self.assertFalse(patch_replacer.use_patch_ng)
|
|
234
|
+
|
|
235
|
+
# Reset
|
|
236
|
+
patch_replacer.use_patch_ng = original_use_patch_ng
|
|
237
|
+
|
|
238
|
+
def test_configure_replacer_unavailable(self):
|
|
239
|
+
"""Test configuring unavailable replacer"""
|
|
240
|
+
with patch.object(self.manager, 'get_replacer', return_value=None):
|
|
241
|
+
# Should not raise exception
|
|
242
|
+
self.manager.configure_replacer(ReplaceStrategy.PATCH, use_patch_ng=True)
|
|
243
|
+
|
|
244
|
+
def test_configure_replacer_exception(self):
|
|
245
|
+
"""Test exception handling in configure_replacer"""
|
|
246
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'lenient_mode',
|
|
247
|
+
side_effect=Exception("Config error")):
|
|
248
|
+
# Should not raise exception
|
|
249
|
+
self.manager.configure_replacer(ReplaceStrategy.STRING, lenient_mode=True)
|
|
250
|
+
|
|
251
|
+
def test_get_replacer_info_string(self):
|
|
252
|
+
"""Test getting string replacer info"""
|
|
253
|
+
info = self.manager.get_replacer_info(ReplaceStrategy.STRING)
|
|
254
|
+
|
|
255
|
+
self.assertTrue(info['available'])
|
|
256
|
+
self.assertEqual(info['strategy'], 'string')
|
|
257
|
+
self.assertEqual(info['class_name'], 'StringReplacer') # Updated from RegexReplacer
|
|
258
|
+
self.assertIn('lenient_mode', info)
|
|
259
|
+
|
|
260
|
+
def test_get_replacer_info_similarity(self):
|
|
261
|
+
"""Test getting similarity replacer info"""
|
|
262
|
+
info = self.manager.get_replacer_info(ReplaceStrategy.SIMILARITY)
|
|
263
|
+
|
|
264
|
+
self.assertTrue(info['available'])
|
|
265
|
+
self.assertEqual(info['strategy'], 'similarity')
|
|
266
|
+
self.assertEqual(info['class_name'], 'SimilarityReplacer')
|
|
267
|
+
self.assertIn('similarity_threshold', info)
|
|
268
|
+
|
|
269
|
+
def test_get_replacer_info_patch(self):
|
|
270
|
+
"""Test getting patch replacer info"""
|
|
271
|
+
info = self.manager.get_replacer_info(ReplaceStrategy.PATCH)
|
|
272
|
+
|
|
273
|
+
if info['available']:
|
|
274
|
+
self.assertEqual(info['strategy'], 'patch')
|
|
275
|
+
self.assertEqual(info['class_name'], 'PatchReplacer')
|
|
276
|
+
self.assertIn('use_patch_ng', info)
|
|
277
|
+
self.assertIn('patch_module_available', info)
|
|
278
|
+
|
|
279
|
+
def test_get_replacer_info_unavailable(self):
|
|
280
|
+
"""Test getting info for unavailable replacer"""
|
|
281
|
+
with patch.object(self.manager, 'get_replacer', return_value=None):
|
|
282
|
+
info = self.manager.get_replacer_info(ReplaceStrategy.PATCH)
|
|
283
|
+
|
|
284
|
+
self.assertFalse(info['available'])
|
|
285
|
+
self.assertEqual(info['strategy'], 'patch')
|
|
286
|
+
|
|
287
|
+
def test_get_replacer_info_exception(self):
|
|
288
|
+
"""Test get_replacer_info with exception during info gathering"""
|
|
289
|
+
with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'lenient_mode',
|
|
290
|
+
side_effect=Exception("Mock exception")):
|
|
291
|
+
info = self.manager.get_replacer_info(ReplaceStrategy.STRING)
|
|
292
|
+
|
|
293
|
+
self.assertTrue(info['available'])
|
|
294
|
+
self.assertEqual(info['strategy'], 'string') # Updated from regex
|
|
295
|
+
self.assertEqual(info['class_name'], 'StringReplacer')
|
|
296
|
+
|
|
297
|
+
def test_get_status(self):
|
|
298
|
+
"""Test get_status method"""
|
|
299
|
+
status = self.manager.get_status()
|
|
300
|
+
|
|
301
|
+
self.assertIn('available_strategies', status)
|
|
302
|
+
self.assertIn('default_strategy', status)
|
|
303
|
+
self.assertEqual(status['default_strategy'], 'string') # Updated from regex
|
|
304
|
+
self.assertIn('replacer_info', status) # Changed from 'replacers' to 'replacer_info'
|
|
305
|
+
|
|
306
|
+
def test_initialize_replacers_with_failures(self):
|
|
307
|
+
"""Test initialization when some replacers fail to initialize"""
|
|
308
|
+
with patch('autocoder.common.search_replace_patch.manager.StringReplacer',
|
|
309
|
+
side_effect=Exception("String replacer init failed")):
|
|
310
|
+
with patch('autocoder.common.search_replace_patch.manager.logger') as mock_logger:
|
|
311
|
+
manager = SearchReplaceManager()
|
|
312
|
+
|
|
313
|
+
# Should handle initialization failures gracefully
|
|
314
|
+
mock_logger.error.assert_called()
|
|
315
|
+
|
|
316
|
+
# Should still have other replacers
|
|
317
|
+
self.assertIsInstance(manager.get_replacer(ReplaceStrategy.SIMILARITY), SimilarityReplacer)
|
|
318
|
+
|
|
319
|
+
def test_manager_with_different_defaults(self):
|
|
320
|
+
"""Test manager with different default strategies"""
|
|
321
|
+
regex_manager = SearchReplaceManager(ReplaceStrategy.STRING)
|
|
322
|
+
similarity_manager = SearchReplaceManager(ReplaceStrategy.SIMILARITY)
|
|
323
|
+
|
|
324
|
+
self.assertEqual(regex_manager.default_strategy, ReplaceStrategy.STRING)
|
|
325
|
+
self.assertEqual(similarity_manager.default_strategy, ReplaceStrategy.SIMILARITY)
|
|
326
|
+
|
|
327
|
+
def test_empty_search_blocks(self):
|
|
328
|
+
"""Test handling empty search blocks"""
|
|
329
|
+
content = "Hello world"
|
|
330
|
+
search_blocks = []
|
|
331
|
+
|
|
332
|
+
result = self.manager.replace(content, search_blocks)
|
|
333
|
+
self.assertFalse(result.success)
|
|
334
|
+
|
|
335
|
+
def test_integration_with_real_replacers(self):
|
|
336
|
+
"""Test integration with real replacer instances"""
|
|
337
|
+
content = "Hello world"
|
|
338
|
+
search_blocks = [("world", "AutoCoder")]
|
|
339
|
+
|
|
340
|
+
# This should work with real replacers
|
|
341
|
+
result = self.manager.replace(content, search_blocks)
|
|
342
|
+
|
|
343
|
+
if result.success:
|
|
344
|
+
self.assertEqual(result.new_content, "Hello AutoCoder")
|
|
345
|
+
else:
|
|
346
|
+
# If it fails, it should be due to replacer logic, not manager logic
|
|
347
|
+
self.assertIsInstance(result.message, str)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
if __name__ == '__main__':
|
|
351
|
+
unittest.main()
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Test module for PatchReplacer
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import unittest
|
|
6
|
+
from unittest.mock import patch, MagicMock, mock_open
|
|
7
|
+
import tempfile
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
from ..patch_replacer import PatchReplacer
|
|
11
|
+
from ..base import ReplaceStrategy
|
|
12
|
+
|
|
13
|
+
# Type ignore for MagicMock assignments in tests
|
|
14
|
+
# pyright: reportAttributeAccessIssue=false
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TestPatchReplacer(unittest.TestCase):
|
|
18
|
+
"""Test PatchReplacer functionality"""
|
|
19
|
+
|
|
20
|
+
def setUp(self):
|
|
21
|
+
"""Set up test fixtures"""
|
|
22
|
+
self.replacer = PatchReplacer(use_patch_ng=True)
|
|
23
|
+
self.unidiff_replacer = PatchReplacer(use_patch_ng=False)
|
|
24
|
+
|
|
25
|
+
def test_initialization(self):
|
|
26
|
+
"""Test proper initialization"""
|
|
27
|
+
self.assertEqual(self.replacer.strategy, ReplaceStrategy.PATCH)
|
|
28
|
+
self.assertTrue(self.replacer.use_patch_ng)
|
|
29
|
+
self.assertFalse(self.unidiff_replacer.use_patch_ng)
|
|
30
|
+
|
|
31
|
+
def test_search_blocks_to_unified_diff(self):
|
|
32
|
+
"""Test converting search blocks to unified diff format"""
|
|
33
|
+
search_blocks = [
|
|
34
|
+
("old_line1\nold_line2", "new_line1\nnew_line2"),
|
|
35
|
+
("old_line3", "new_line3")
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
diff = self.replacer._search_blocks_to_unified_diff(search_blocks, "test.txt")
|
|
39
|
+
|
|
40
|
+
self.assertIn("--- a/test.txt", diff)
|
|
41
|
+
self.assertIn("+++ b/test.txt", diff)
|
|
42
|
+
self.assertIn("@@", diff)
|
|
43
|
+
self.assertIn("-old_line1", diff)
|
|
44
|
+
self.assertIn("+new_line1", diff)
|
|
45
|
+
self.assertIn("-old_line3", diff)
|
|
46
|
+
self.assertIn("+new_line3", diff)
|
|
47
|
+
|
|
48
|
+
def test_replace_no_patch_module(self):
|
|
49
|
+
"""Test replace when no patch module is available"""
|
|
50
|
+
replacer = PatchReplacer()
|
|
51
|
+
replacer._patch_module = None
|
|
52
|
+
|
|
53
|
+
content = "Hello world"
|
|
54
|
+
search_blocks = [("Hello", "Hi")]
|
|
55
|
+
|
|
56
|
+
result = replacer.replace(content, search_blocks)
|
|
57
|
+
|
|
58
|
+
self.assertFalse(result.success)
|
|
59
|
+
self.assertIn("No patch module available", result.message)
|
|
60
|
+
|
|
61
|
+
def test_replace_invalid_search_blocks(self):
|
|
62
|
+
"""Test replace with invalid search blocks"""
|
|
63
|
+
content = "Hello world"
|
|
64
|
+
|
|
65
|
+
# Empty search blocks
|
|
66
|
+
result = self.replacer.replace(content, [])
|
|
67
|
+
self.assertFalse(result.success)
|
|
68
|
+
self.assertIn("Invalid search blocks", result.message)
|
|
69
|
+
|
|
70
|
+
# Empty search text is now valid for insertion
|
|
71
|
+
result = self.replacer.replace(content, [("", "replacement")])
|
|
72
|
+
self.assertTrue(result.success) # Should succeed as insertion
|
|
73
|
+
|
|
74
|
+
def test_can_handle(self):
|
|
75
|
+
"""Test can_handle method"""
|
|
76
|
+
# Should handle valid blocks when module is available
|
|
77
|
+
self.replacer._patch_module = MagicMock() # type: ignore
|
|
78
|
+
self.assertTrue(self.replacer.can_handle("content", [("old", "new")]))
|
|
79
|
+
|
|
80
|
+
# Should not handle when no module available
|
|
81
|
+
self.replacer._patch_module = None
|
|
82
|
+
self.assertFalse(self.replacer.can_handle("content", [("old", "new")]))
|
|
83
|
+
|
|
84
|
+
# Should not handle invalid blocks
|
|
85
|
+
self.replacer._patch_module = MagicMock() # type: ignore
|
|
86
|
+
self.assertFalse(self.replacer.can_handle("content", []))
|
|
87
|
+
|
|
88
|
+
@patch('tempfile.NamedTemporaryFile')
|
|
89
|
+
@patch('builtins.open', new_callable=mock_open, read_data="Hello AutoCoder")
|
|
90
|
+
@patch('os.path.exists', return_value=True)
|
|
91
|
+
@patch('os.unlink')
|
|
92
|
+
def test_apply_patch_ng_success(self, mock_unlink, mock_exists, mock_file, mock_temp):
|
|
93
|
+
"""Test successful patch application with patch-ng"""
|
|
94
|
+
# Mock temp file
|
|
95
|
+
mock_temp_file = MagicMock()
|
|
96
|
+
mock_temp_file.name = "/tmp/test.txt"
|
|
97
|
+
mock_temp.return_value.__enter__.return_value = mock_temp_file
|
|
98
|
+
|
|
99
|
+
# Mock patch-ng
|
|
100
|
+
mock_patch_module = MagicMock()
|
|
101
|
+
mock_patchset = MagicMock()
|
|
102
|
+
mock_patchset.apply.return_value = True
|
|
103
|
+
mock_patch_module.PatchSet.from_string.return_value = mock_patchset
|
|
104
|
+
|
|
105
|
+
self.replacer._patch_module = mock_patch_module
|
|
106
|
+
|
|
107
|
+
content = "Hello world"
|
|
108
|
+
diff_content = "some diff content"
|
|
109
|
+
|
|
110
|
+
result = self.replacer._apply_patch_ng(content, diff_content, "test.txt")
|
|
111
|
+
|
|
112
|
+
self.assertEqual(result, "Hello AutoCoder")
|
|
113
|
+
mock_patchset.apply.assert_called_once()
|
|
114
|
+
|
|
115
|
+
@patch('tempfile.NamedTemporaryFile')
|
|
116
|
+
def test_apply_patch_ng_failure(self, mock_temp):
|
|
117
|
+
"""Test failed patch application with patch-ng"""
|
|
118
|
+
# Mock temp file
|
|
119
|
+
mock_temp_file = MagicMock()
|
|
120
|
+
mock_temp_file.name = "/tmp/test.txt"
|
|
121
|
+
mock_temp.return_value.__enter__.return_value = mock_temp_file
|
|
122
|
+
|
|
123
|
+
# Mock patch-ng failure
|
|
124
|
+
mock_patch_module = MagicMock()
|
|
125
|
+
mock_patchset = MagicMock()
|
|
126
|
+
mock_patchset.apply.return_value = False
|
|
127
|
+
mock_patch_module.PatchSet.from_string.return_value = mock_patchset
|
|
128
|
+
|
|
129
|
+
self.replacer._patch_module = mock_patch_module
|
|
130
|
+
|
|
131
|
+
content = "Hello world"
|
|
132
|
+
diff_content = "some diff content"
|
|
133
|
+
|
|
134
|
+
result = self.replacer._apply_patch_ng(content, diff_content, "test.txt")
|
|
135
|
+
|
|
136
|
+
self.assertIsNone(result)
|
|
137
|
+
|
|
138
|
+
@patch('tempfile.NamedTemporaryFile')
|
|
139
|
+
def test_apply_patch_ng_exception(self, mock_temp):
|
|
140
|
+
"""Test exception handling in patch-ng application"""
|
|
141
|
+
# Mock temp file
|
|
142
|
+
mock_temp_file = MagicMock()
|
|
143
|
+
mock_temp_file.name = "/tmp/test.txt"
|
|
144
|
+
mock_temp.return_value.__enter__.return_value = mock_temp_file
|
|
145
|
+
|
|
146
|
+
# Mock patch-ng exception
|
|
147
|
+
mock_patch_module = MagicMock()
|
|
148
|
+
mock_patch_module.PatchSet.from_string.side_effect = Exception("Patch error")
|
|
149
|
+
|
|
150
|
+
self.replacer._patch_module = mock_patch_module
|
|
151
|
+
|
|
152
|
+
content = "Hello world"
|
|
153
|
+
diff_content = "some diff content"
|
|
154
|
+
|
|
155
|
+
result = self.replacer._apply_patch_ng(content, diff_content, "test.txt")
|
|
156
|
+
|
|
157
|
+
self.assertIsNone(result)
|
|
158
|
+
|
|
159
|
+
def test_apply_unidiff_no_patches(self):
|
|
160
|
+
"""Test unidiff application when no patches are found"""
|
|
161
|
+
mock_patch_module = MagicMock()
|
|
162
|
+
mock_patchset = MagicMock()
|
|
163
|
+
mock_patchset.__bool__.return_value = False
|
|
164
|
+
mock_patch_module.PatchSet.return_value = mock_patchset
|
|
165
|
+
|
|
166
|
+
self.replacer._patch_module = mock_patch_module
|
|
167
|
+
|
|
168
|
+
content = "Hello world"
|
|
169
|
+
diff_content = "some diff content"
|
|
170
|
+
|
|
171
|
+
result = self.replacer._apply_unidiff(content, diff_content, "test.txt")
|
|
172
|
+
|
|
173
|
+
self.assertIsNone(result)
|
|
174
|
+
|
|
175
|
+
def test_apply_unidiff_success(self):
|
|
176
|
+
"""Test successful unidiff application"""
|
|
177
|
+
mock_patch_module = MagicMock()
|
|
178
|
+
mock_patchset = MagicMock()
|
|
179
|
+
mock_patchset.__bool__.return_value = True
|
|
180
|
+
mock_patch_file = MagicMock()
|
|
181
|
+
mock_patchset.__getitem__.return_value = mock_patch_file
|
|
182
|
+
mock_patch_module.PatchSet.return_value = mock_patchset
|
|
183
|
+
|
|
184
|
+
self.replacer._patch_module = mock_patch_module
|
|
185
|
+
|
|
186
|
+
content = "Hello world"
|
|
187
|
+
diff_content = "some diff content"
|
|
188
|
+
|
|
189
|
+
with patch.object(self.replacer, '_apply_patch_to_lines', return_value=["Hello AutoCoder"]):
|
|
190
|
+
result = self.replacer._apply_unidiff(content, diff_content, "test.txt")
|
|
191
|
+
|
|
192
|
+
self.assertEqual(result, "Hello AutoCoder")
|
|
193
|
+
|
|
194
|
+
def test_apply_unidiff_exception(self):
|
|
195
|
+
"""Test exception handling in unidiff application"""
|
|
196
|
+
mock_patch_module = MagicMock()
|
|
197
|
+
mock_patch_module.PatchSet.side_effect = Exception("Unidiff error")
|
|
198
|
+
|
|
199
|
+
self.replacer._patch_module = mock_patch_module
|
|
200
|
+
|
|
201
|
+
content = "Hello world"
|
|
202
|
+
diff_content = "some diff content"
|
|
203
|
+
|
|
204
|
+
result = self.replacer._apply_unidiff(content, diff_content, "test.txt")
|
|
205
|
+
|
|
206
|
+
self.assertIsNone(result)
|
|
207
|
+
|
|
208
|
+
def test_replace_with_patch_ng_success(self):
|
|
209
|
+
"""Test successful replace using patch-ng"""
|
|
210
|
+
mock_patch_module = MagicMock()
|
|
211
|
+
self.replacer._patch_module = mock_patch_module
|
|
212
|
+
self.replacer.use_patch_ng = True
|
|
213
|
+
|
|
214
|
+
content = "Hello world"
|
|
215
|
+
search_blocks = [("Hello", "Hi")]
|
|
216
|
+
|
|
217
|
+
with patch.object(self.replacer, '_apply_patch_ng', return_value="Hi world"):
|
|
218
|
+
result = self.replacer.replace(content, search_blocks)
|
|
219
|
+
|
|
220
|
+
self.assertTrue(result.success)
|
|
221
|
+
self.assertEqual(result.new_content, "Hi world")
|
|
222
|
+
self.assertEqual(result.applied_count, 1)
|
|
223
|
+
self.assertEqual(result.total_count, 1)
|
|
224
|
+
self.assertEqual(result.metadata['strategy'], 'patch')
|
|
225
|
+
self.assertEqual(result.metadata['patch_module'], 'patch-ng')
|
|
226
|
+
|
|
227
|
+
def test_replace_with_unidiff_success(self):
|
|
228
|
+
"""Test successful replace using unidiff"""
|
|
229
|
+
mock_patch_module = MagicMock()
|
|
230
|
+
self.replacer._patch_module = mock_patch_module
|
|
231
|
+
self.replacer.use_patch_ng = False
|
|
232
|
+
|
|
233
|
+
content = "Hello world"
|
|
234
|
+
search_blocks = [("Hello", "Hi")]
|
|
235
|
+
|
|
236
|
+
with patch.object(self.replacer, '_apply_unidiff', return_value="Hi world"):
|
|
237
|
+
result = self.replacer.replace(content, search_blocks)
|
|
238
|
+
|
|
239
|
+
self.assertTrue(result.success)
|
|
240
|
+
self.assertEqual(result.new_content, "Hi world")
|
|
241
|
+
self.assertEqual(result.applied_count, 1)
|
|
242
|
+
self.assertEqual(result.total_count, 1)
|
|
243
|
+
self.assertEqual(result.metadata['strategy'], 'patch')
|
|
244
|
+
self.assertEqual(result.metadata['patch_module'], 'unidiff')
|
|
245
|
+
|
|
246
|
+
def test_replace_patch_failure(self):
|
|
247
|
+
"""Test replace when patch application fails"""
|
|
248
|
+
mock_patch_module = MagicMock()
|
|
249
|
+
self.replacer._patch_module = mock_patch_module
|
|
250
|
+
|
|
251
|
+
content = "Hello world"
|
|
252
|
+
search_blocks = [("Hello", "Hi")]
|
|
253
|
+
|
|
254
|
+
with patch.object(self.replacer, '_apply_patch_ng', return_value=None):
|
|
255
|
+
result = self.replacer.replace(content, search_blocks)
|
|
256
|
+
|
|
257
|
+
self.assertFalse(result.success)
|
|
258
|
+
self.assertIn("Failed to apply patch", result.message)
|
|
259
|
+
self.assertEqual(result.applied_count, 0)
|
|
260
|
+
self.assertEqual(result.total_count, 1)
|
|
261
|
+
self.assertEqual(len(result.errors), 1)
|
|
262
|
+
|
|
263
|
+
def test_replace_exception_handling(self):
|
|
264
|
+
"""Test exception handling in replace method"""
|
|
265
|
+
mock_patch_module = MagicMock()
|
|
266
|
+
self.replacer._patch_module = mock_patch_module
|
|
267
|
+
|
|
268
|
+
content = "Hello world"
|
|
269
|
+
search_blocks = [("Hello", "Hi")]
|
|
270
|
+
|
|
271
|
+
with patch.object(self.replacer, '_search_blocks_to_unified_diff', side_effect=Exception("Diff error")):
|
|
272
|
+
result = self.replacer.replace(content, search_blocks)
|
|
273
|
+
|
|
274
|
+
self.assertFalse(result.success)
|
|
275
|
+
self.assertIn("Error in patch replacement", result.message)
|
|
276
|
+
self.assertEqual(result.applied_count, 0)
|
|
277
|
+
self.assertEqual(result.total_count, 1)
|
|
278
|
+
self.assertEqual(len(result.errors), 1)
|
|
279
|
+
|
|
280
|
+
def test_multiple_search_blocks(self):
|
|
281
|
+
"""Test with multiple search blocks"""
|
|
282
|
+
mock_patch_module = MagicMock()
|
|
283
|
+
self.replacer._patch_module = mock_patch_module
|
|
284
|
+
|
|
285
|
+
content = "Hello world, goodbye world"
|
|
286
|
+
search_blocks = [
|
|
287
|
+
("Hello", "Hi"),
|
|
288
|
+
("goodbye", "farewell")
|
|
289
|
+
]
|
|
290
|
+
|
|
291
|
+
with patch.object(self.replacer, '_apply_patch_ng', return_value="Hi world, farewell world"):
|
|
292
|
+
result = self.replacer.replace(content, search_blocks)
|
|
293
|
+
|
|
294
|
+
self.assertTrue(result.success)
|
|
295
|
+
self.assertEqual(result.new_content, "Hi world, farewell world")
|
|
296
|
+
self.assertEqual(result.applied_count, 2)
|
|
297
|
+
self.assertEqual(result.total_count, 2)
|
|
298
|
+
|
|
299
|
+
def test_diff_content_generation(self):
|
|
300
|
+
"""Test that diff content is generated correctly"""
|
|
301
|
+
search_blocks = [("line1", "modified_line1")]
|
|
302
|
+
|
|
303
|
+
with patch.object(self.replacer, '_search_blocks_to_unified_diff') as mock_diff:
|
|
304
|
+
mock_diff.return_value = "mocked_diff"
|
|
305
|
+
|
|
306
|
+
mock_patch_module = MagicMock()
|
|
307
|
+
self.replacer._patch_module = mock_patch_module
|
|
308
|
+
|
|
309
|
+
with patch.object(self.replacer, '_apply_patch_ng', return_value="result"):
|
|
310
|
+
self.replacer.replace("content", search_blocks)
|
|
311
|
+
|
|
312
|
+
mock_diff.assert_called_once_with(search_blocks)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
if __name__ == '__main__':
|
|
316
|
+
unittest.main()
|