forked from HAL9000/cleveragents-core
193 lines
10 KiB
Python
193 lines
10 KiB
Python
"""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)}"
|