import pytest from rllm.parser import QwenToolParser, R1ToolParser from rllm.tools.tool_base import ToolCall class TestQwenToolParser: @pytest.fixture def parser(self): return QwenToolParser() def test_empty_response(self, parser): """Test parsing empty response.""" result = parser.parse("") assert len(result) == 0 def test_no_tool_calls(self, parser): """Test response with no tool calls.""" response = "This is a normal response without any tool calls." result = parser.parse(response) assert len(result) == 0 def test_single_valid_tool_call(self, parser): """Test parsing a single valid tool call.""" response = """ {"name": "search_weather", "arguments": {"location": "New York", "unit": "celsius"}} """ result = parser.parse(response) assert len(result) == 1 assert isinstance(result[0], ToolCall) assert result[0].name == "search_weather" assert result[0].arguments == {"location": "New York", "unit": "celsius"} def test_multiple_valid_tool_calls(self, parser): """Test parsing multiple valid tool calls.""" response = """ {"name": "search_weather", "arguments": {"location": "New York"}} {"name": "search_restaurants", "arguments": {"location": "New York", "cuisine": "Italian"}} """ result = parser.parse(response) assert len(result) == 2 assert result[0].name == "search_weather" assert result[1].name == "search_restaurants" def test_invalid_json_tool_call(self, parser): """Test parsing tool call with invalid JSON.""" response = """ {"name": "search_weather", "arguments": {invalid json}} """ result = parser.parse(response) assert len(result) == 0 def test_missing_tool_call_end(self, parser): """Test parsing tool call with missing end tag.""" response = """ {"name": "search_weather", "arguments": {"location": "New York"}} """ result = parser.parse(response) assert len(result) == 0 def test_get_tool_prompt(self, parser): """Test tool prompt generation.""" tools_schema = """ { "name": "search_weather", "description": "Search for weather information", "parameters": { "type": "object", "properties": { "location": {"type": "string"} } } } """ prompt = parser.get_tool_prompt(tools_schema) assert "" in prompt assert tools_schema in prompt assert "" in prompt class TestR1ToolParser: @pytest.fixture def parser(self): return R1ToolParser() def test_empty_response(self, parser): """Test parsing empty response.""" result = parser.parse("") assert len(result) == 0 def test_no_tool_calls(self, parser): """Test response with no tool calls.""" response = "This is a normal response without any tool calls." result = parser.parse(response) assert len(result) == 0 def test_single_valid_tool_call(self, parser): """Test parsing a single valid tool call.""" response = f""" {parser.tool_call_begin}function{parser.tool_sep}search_weather ```json {{"location": "New York", "unit": "celsius"}} ``` {parser.tool_call_end} """ result = parser.parse(response) assert len(result) == 1 assert isinstance(result[0], ToolCall) assert result[0].name == "search_weather" assert result[0].arguments == {"location": "New York", "unit": "celsius"} def test_multiple_valid_tool_calls(self, parser): """Test parsing multiple valid tool calls.""" response = f""" {parser.tool_call_begin}function{parser.tool_sep}search_weather ```json {{"location": "New York"}} ``` {parser.tool_call_end} {parser.tool_call_begin}function{parser.tool_sep}search_restaurants ```json {{"location": "New York", "cuisine": "Italian"}} ``` {parser.tool_call_end} """ result = parser.parse(response) assert len(result) == 2 assert result[0].name == "search_weather" assert result[1].name == "search_restaurants" def test_invalid_json_tool_call(self, parser): """Test parsing tool call with invalid JSON.""" response = f""" {parser.tool_call_begin}function{parser.tool_sep}search_weather ```json {{"location": "New York", invalid json}} ``` {parser.tool_call_end} """ result = parser.parse(response) assert len(result) == 0 def test_missing_tool_call_end(self, parser): """Test parsing tool call with missing end tag.""" response = f""" {parser.tool_call_begin}function{parser.tool_sep}search_weather ```json {{"location": "New York"}} ``` """ result = parser.parse(response) assert len(result) == 0 def test_missing_function_prefix(self, parser): """Test parsing tool call with missing function prefix.""" response = f""" {parser.tool_call_begin}search_weather ```json {{"location": "New York"}} ``` {parser.tool_call_end} """ result = parser.parse(response) assert len(result) == 0 def test_missing_json_block(self, parser): """Test parsing tool call with missing JSON block.""" response = f""" {parser.tool_call_begin}function{parser.tool_sep}search_weather {parser.tool_call_end} """ result = parser.parse(response) assert len(result) == 0