"""Step definitions for tool command processing unit tests.""" import json import re from behave import given, then, when @given("a content with simple file_read tool command") def step_given_simple_file_read_content(context): """Set up content with a simple file_read command.""" context.content = """ Some text before [TOOL_EXECUTE:file_read] {"file": "simple.txt"} [/TOOL_EXECUTE] Some text after """ @given("a content with nested JSON file_write tool command") def step_given_nested_json_content(context): """Set up content with nested JSON in file_write command.""" context.content = """ [TOOL_EXECUTE:file_write] {"file": "analysis.json", "content": "{\\"document_info\\": {\\"analysis_date\\": \\"2025-10-03\\", \\"total_confidence\\": 0.91}, \\"parties\\": [{\\"name\\": \\"TechCorp\\", \\"confidence\\": 0.95}]}"} [/TOOL_EXECUTE] """ @given("a content with multiple tool commands") def step_given_multiple_commands(context): """Set up content with multiple tool commands.""" context.content = """ First we load: [TOOL_EXECUTE:file_read] {"file": "contract.txt"} [/TOOL_EXECUTE] Then we save: [TOOL_EXECUTE:file_write] {"file": "output.json", "content": "{\\"key\\": \\"value\\"}"} [/TOOL_EXECUTE] """ @given("a content with complex legal contract analyzer JSON") def step_given_complex_json_content(context): """Set up content with complex nested JSON from legal contract analyzer.""" context.content = """ [TOOL_EXECUTE:file_write] {"file": "contract_analysis.json", "content": "{\\"document_info\\": {\\"analysis_date\\": \\"2025-10-03\\", \\"document_type\\": \\"service_agreement\\", \\"total_confidence\\": 0.91, \\"analysis_version\\": \\"1.0\\"}, \\"parties\\": [{\\"name\\": \\"TechCorp Solutions Inc.\\", \\"type\\": \\"company\\", \\"role\\": \\"provider\\", \\"contact_info\\": \\"123 Tech Street, San Francisco, CA 94105\\", \\"representative\\": {\\"name\\": \\"John Smith\\", \\"title\\": \\"Chief Technology Officer\\"}, \\"confidence\\": 0.95}, {\\"name\\": \\"Global Enterprises LLC\\", \\"type\\": \\"company\\", \\"role\\": \\"client\\", \\"contact_info\\": \\"456 Business Ave, Los Angeles, CA 90001\\", \\"representative\\": {\\"name\\": \\"Sarah Johnson\\", \\"title\\": \\"Chief Executive Officer\\"}, \\"confidence\\": 0.95}], \\"dates\\": {\\"signing_date\\": \\"2024-01-15\\", \\"effective_date\\": \\"2024-01-15\\", \\"expiration_date\\": \\"2026-01-15\\", \\"payment_due_days\\": 30, \\"termination_notice_days\\": 90, \\"confidence\\": 0.98}, \\"financial_terms\\": {\\"total_value\\": {\\"amount\\": 120000, \\"currency\\": \\"USD\\", \\"period\\": \\"24 months\\", \\"confidence\\": 1.0}, \\"payment_schedule\\": [{\\"amount\\": 5000, \\"frequency\\": \\"monthly\\", \\"due_date_offset\\": 30, \\"description\\": \\"Monthly service fee\\", \\"confidence\\": 1.0}], \\"penalties_fees\\": [{\\"type\\": \\"late_payment_penalty\\", \\"amount\\": \\"1.5% per month\\", \\"condition\\": \\"Late payment\\", \\"confidence\\": 1.0}], \\"overall_confidence\\": 0.98}, \\"obligations\\": {\\"party_obligations\\": [{\\"party\\": \\"TechCorp Solutions Inc.\\", \\"deliverables\\": [\\"Virtual server hosting\\", \\"Data storage and backup services\\", \\"Network infrastructure management\\", \\"24/7 technical support\\"], \\"performance_standards\\": [\\"99.9% uptime guarantee\\"], \\"confidence\\": 0.95}], \\"overall_confidence\\": 0.93}, \\"legal_terms\\": {\\"governing_law\\": \\"State of California\\", \\"termination_conditions\\": [\\"90 days written notice by either party\\", \\"Immediate termination for non-payment or material breach\\"], \\"liability_clauses\\": [\\"Total liability limited to 12 months of payments\\"], \\"confidentiality\\": \\"yes\\", \\"confidence\\": 0.92}, \\"risk_assessment\\": {\\"high_risk_terms\\": [\\"Limited liability cap may be insufficient\\", \\"No data privacy clauses\\"], \\"missing_clauses\\": [\\"Force Majeure\\", \\"Dispute Resolution\\", \\"Data Protection\\", \\"IP Ownership\\"], \\"ambiguous_language\\": [\\"Proprietary information not defined\\", \\"Technical specifications unclear\\"], \\"overall_risk_score\\": 0.65, \\"risk_level\\": \\"Medium-High\\", \\"confidence\\": 0.87}, \\"extraction_summary\\": {\\"total_sections_analyzed\\": 6, \\"successfully_extracted_fields\\": 18, \\"failed_extractions\\": [], \\"overall_confidence\\": 0.91}}"} [/TOOL_EXECUTE] """ @when("I extract the tool command using regex") def step_when_extract_single_command(context): """Extract a single tool command using regex pattern.""" pattern = r"\[TOOL_EXECUTE:(\w+)\]\s*(.*?)\s*\[/TOOL_EXECUTE\]" matches = list(re.finditer(pattern, context.content, re.DOTALL)) context.matches = matches if len(matches) > 0: context.tool_name = matches[0].group(1) params_str = matches[0].group(2).strip() context.params = json.loads(params_str) # Try to parse nested JSON if it exists if "content" in context.params and isinstance(context.params["content"], str): try: context.nested_json = json.loads(context.params["content"]) except json.JSONDecodeError: context.nested_json = None @when("I extract all tool commands using regex") def step_when_extract_all_commands(context): """Extract all tool commands using regex pattern.""" pattern = r"\[TOOL_EXECUTE:(\w+)\]\s*(.*?)\s*\[/TOOL_EXECUTE\]" context.matches = list(re.finditer(pattern, context.content, re.DOTALL)) @then('the tool name should be "{expected_name}"') def step_then_check_tool_name(context, expected_name): """Verify the tool name matches expectation.""" assert context.tool_name == expected_name, f"Expected '{expected_name}', got '{context.tool_name}'" @then('the parameters should contain file "{expected_file}"') def step_then_check_file_parameter(context, expected_file): """Verify the file parameter matches expectation.""" assert "file" in context.params, "Parameters should contain 'file' key" assert context.params["file"] == expected_file, f"Expected file '{expected_file}', got '{context.params['file']}'" @then("the nested JSON content should be parseable") def step_then_nested_json_parseable(context): """Verify nested JSON can be parsed.""" assert context.nested_json is not None, "Nested JSON should be parseable" @then('the nested JSON should contain document_info with analysis_date "{expected_date}"') def step_then_check_analysis_date(context, expected_date): """Verify nested JSON contains expected analysis_date.""" assert "document_info" in context.nested_json, "Nested JSON should contain document_info" assert context.nested_json["document_info"]["analysis_date"] == expected_date @then('the nested JSON should contain parties with name "{expected_name}"') def step_then_check_party_name(context, expected_name): """Verify nested JSON contains expected party name.""" assert "parties" in context.nested_json, "Nested JSON should contain parties" assert len(context.nested_json["parties"]) > 0, "Parties array should not be empty" assert context.nested_json["parties"][0]["name"] == expected_name @then("I should find {count:d} tool commands") def step_then_check_command_count(context, count): """Verify the number of tool commands found.""" assert len(context.matches) == count, f"Expected {count} commands, found {len(context.matches)}" @then('the first tool command should be "{expected_name}"') def step_then_check_first_command(context, expected_name): """Verify the first tool command name.""" assert len(context.matches) > 0, "Should have at least one command" first_name = context.matches[0].group(1) assert first_name == expected_name, f"Expected '{expected_name}', got '{first_name}'" @then('the second tool command should be "{expected_name}"') def step_then_check_second_command(context, expected_name): """Verify the second tool command name.""" assert len(context.matches) > 1, "Should have at least two commands" second_name = context.matches[1].group(1) assert second_name == expected_name, f"Expected '{expected_name}', got '{second_name}'" @then("the complex nested JSON should be parseable") def step_then_complex_json_parseable(context): """Verify complex nested JSON can be parsed.""" assert context.nested_json is not None, "Complex nested JSON should be parseable" @then("the complex nested JSON should contain all required sections") def step_then_check_all_sections(context): """Verify all required sections exist in complex JSON.""" required_sections = [ "document_info", "parties", "dates", "financial_terms", "obligations", "legal_terms", "risk_assessment", "extraction_summary", ] for section in required_sections: assert section in context.nested_json, f"Missing required section: {section}" @then('the complex nested JSON document_info analysis_date should be "{expected_date}"') def step_then_check_complex_analysis_date(context, expected_date): """Verify complex JSON analysis_date.""" assert context.nested_json["document_info"]["analysis_date"] == expected_date @then('the complex nested JSON first party name should be "{expected_name}"') def step_then_check_first_party(context, expected_name): """Verify first party name in complex JSON.""" assert context.nested_json["parties"][0]["name"] == expected_name @then('the complex nested JSON second party name should be "{expected_name}"') def step_then_check_second_party(context, expected_name): """Verify second party name in complex JSON.""" assert context.nested_json["parties"][1]["name"] == expected_name @then("the complex nested JSON financial total_value amount should be {expected_amount:d}") def step_then_check_financial_amount(context, expected_amount): """Verify financial amount in complex JSON.""" actual_amount = context.nested_json["financial_terms"]["total_value"]["amount"] assert actual_amount == expected_amount, f"Expected {expected_amount}, got {actual_amount}" @then("the complex nested JSON should have {count:d} missing_clauses") def step_then_check_missing_clauses_count(context, count): """Verify number of missing clauses in complex JSON.""" missing_clauses = context.nested_json["risk_assessment"]["missing_clauses"] assert len(missing_clauses) == count, f"Expected {count} missing clauses, found {len(missing_clauses)}"