tool_parser_json.rs 6.61 KB
Newer Older
1
2
3
4
5
//! JSON Parser Integration Tests
//!
//! Tests for the JSON parser which handles OpenAI, Claude, and generic JSON formats

use serde_json::json;
6
use sglang_router_rs::tool_parser::{JsonParser, TokenConfig, ToolParser};
7
8
9
10
11
12

#[tokio::test]
async fn test_simple_json_tool_call() {
    let parser = JsonParser::new();
    let input = r#"{"name": "get_weather", "arguments": {"location": "San Francisco"}}"#;

13
    let (normal_text, tools) = parser.parse_complete(input).await.unwrap();
14
    assert_eq!(tools.len(), 1);
15
    assert_eq!(normal_text, "");
16
    assert_eq!(tools[0].function.name, "get_weather");
17

18
    let args: serde_json::Value = serde_json::from_str(&tools[0].function.arguments).unwrap();
19
20
21
22
23
24
    assert_eq!(args["location"], "San Francisco");
}

#[tokio::test]
async fn test_json_array_of_tools() {
    let parser = JsonParser::new();
25
    let input = r#"Hello, here are the results: [
26
27
28
29
        {"name": "get_weather", "arguments": {"location": "SF"}},
        {"name": "search", "arguments": {"query": "news"}}
    ]"#;

30
    let (normal_text, tools) = parser.parse_complete(input).await.unwrap();
31
    assert_eq!(tools.len(), 2);
32
    assert_eq!(normal_text, "Hello, here are the results: ");
33
34
    assert_eq!(tools[0].function.name, "get_weather");
    assert_eq!(tools[1].function.name, "search");
35
36
37
38
39
40
41
}

#[tokio::test]
async fn test_json_with_parameters_key() {
    let parser = JsonParser::new();
    let input = r#"{"name": "calculate", "parameters": {"x": 10, "y": 20}}"#;

42
    let (normal_text, tools) = parser.parse_complete(input).await.unwrap();
43
    assert_eq!(tools.len(), 1);
44
    assert_eq!(normal_text, "");
45
    assert_eq!(tools[0].function.name, "calculate");
46

47
    let args: serde_json::Value = serde_json::from_str(&tools[0].function.arguments).unwrap();
48
49
50
51
52
53
54
55
56
    assert_eq!(args["x"], 10);
    assert_eq!(args["y"], 20);
}

#[tokio::test]
async fn test_json_extraction_from_text() {
    let parser = JsonParser::new();
    let input = r#"I'll help you with that. {"name": "search", "arguments": {"query": "rust"}} Let me search for that."#;

57
    let (normal_text, tools) = parser.parse_complete(input).await.unwrap();
58
    assert_eq!(tools.len(), 1);
59
60
61
62
    assert_eq!(
        normal_text,
        "I'll help you with that.  Let me search for that."
    );
63
    assert_eq!(tools[0].function.name, "search");
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
}

#[tokio::test]
async fn test_json_with_nested_objects() {
    let parser = JsonParser::new();
    let input = r#"{
        "name": "update_config",
        "arguments": {
            "settings": {
                "theme": "dark",
                "language": "en",
                "notifications": {
                    "email": true,
                    "push": false
                }
            }
        }
    }"#;

83
    let (normal_text, tools) = parser.parse_complete(input).await.unwrap();
84
    assert_eq!(tools.len(), 1);
85
    assert_eq!(normal_text, "");
86
    assert_eq!(tools[0].function.name, "update_config");
87

88
    let args: serde_json::Value = serde_json::from_str(&tools[0].function.arguments).unwrap();
89
90
91
92
93
94
95
96
97
    assert_eq!(args["settings"]["theme"], "dark");
    assert_eq!(args["settings"]["notifications"]["email"], true);
}

#[tokio::test]
async fn test_json_with_special_characters() {
    let parser = JsonParser::new();
    let input = r#"{"name": "echo", "arguments": {"text": "Line 1\nLine 2\tTabbed", "path": "C:\\Users\\test"}}"#;

98
    let (normal_text, tools) = parser.parse_complete(input).await.unwrap();
99
    assert_eq!(tools.len(), 1);
100
    assert_eq!(normal_text, "");
101

102
    let args: serde_json::Value = serde_json::from_str(&tools[0].function.arguments).unwrap();
103
104
105
106
107
108
109
110
111
    assert_eq!(args["text"], "Line 1\nLine 2\tTabbed");
    assert_eq!(args["path"], "C:\\Users\\test");
}

#[tokio::test]
async fn test_json_with_unicode() {
    let parser = JsonParser::new();
    let input = r#"{"name": "translate", "arguments": {"text": "Hello 世界 🌍", "emoji": "😊"}}"#;

112
    let (normal_text, tools) = parser.parse_complete(input).await.unwrap();
113
    assert_eq!(tools.len(), 1);
114
    assert_eq!(normal_text, "");
115

116
    let args: serde_json::Value = serde_json::from_str(&tools[0].function.arguments).unwrap();
117
118
119
120
121
122
123
124
125
    assert_eq!(args["text"], "Hello 世界 🌍");
    assert_eq!(args["emoji"], "😊");
}

#[tokio::test]
async fn test_json_empty_arguments() {
    let parser = JsonParser::new();
    let input = r#"{"name": "ping", "arguments": {}}"#;

126
    let (normal_text, tools) = parser.parse_complete(input).await.unwrap();
127
    assert_eq!(tools.len(), 1);
128
    assert_eq!(normal_text, "");
129
    assert_eq!(tools[0].function.name, "ping");
130

131
    let args: serde_json::Value = serde_json::from_str(&tools[0].function.arguments).unwrap();
132
133
134
135
136
137
138
139
140
    assert_eq!(args, json!({}));
}

#[tokio::test]
async fn test_json_invalid_format() {
    let parser = JsonParser::new();

    // Missing closing brace
    let input = r#"{"name": "test", "arguments": {"key": "value""#;
141
    let (normal_text, tools) = parser.parse_complete(input).await.unwrap();
142
    assert_eq!(tools.len(), 0);
143
144
145
146
    assert_eq!(
        normal_text,
        "{\"name\": \"test\", \"arguments\": {\"key\": \"value\""
    );
147
148
149

    // Not JSON at all
    let input = "This is just plain text";
150
151
    let (_normal_text, tools) = parser.parse_complete(input).await.unwrap();
    assert_eq!(tools.len(), 0);
152
153
154
155
156
157
158
159
160
161
162
}

#[tokio::test]
async fn test_json_format_detection() {
    let parser = JsonParser::new();

    assert!(parser.detect_format(r#"{"name": "test", "arguments": {}}"#));
    assert!(parser.detect_format(r#"[{"name": "test"}]"#));
    assert!(!parser.detect_format("plain text"));
    assert!(!parser.detect_format(r#"{"key": "value"}"#)); // No name field
}
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191

#[tokio::test]
async fn test_parse_with_wrapper_tokens() {
    let parser = JsonParser::with_config(TokenConfig {
        start_tokens: vec!["<tool>".to_string()],
        end_tokens: vec!["</tool>".to_string()],
        separator: ", ".to_string(),
    });

    let input = r#"<tool>{"name": "test", "arguments": {}}</tool>"#;
    let (normal_text, tool_calls) = parser.parse_complete(input).await.unwrap();
    assert_eq!(tool_calls.len(), 1);
    assert_eq!(tool_calls[0].function.name, "test");
    assert_eq!(normal_text, ""); // Wrapper tokens with no extra text
}

#[tokio::test]
async fn test_parse_with_start_token_invalid_json() {
    let parser = JsonParser::with_config(TokenConfig {
        start_tokens: vec!["<|python_tag|>".to_string()],
        end_tokens: vec!["".to_string()],
        separator: ";".to_string(),
    });

    let input = r#"Hello world <|python_tag|>this is not valid json at all"#;
    let (normal_text, tool_calls) = parser.parse_complete(input).await.unwrap();
    assert_eq!(tool_calls.len(), 0);
    assert_eq!(normal_text, input); // Should return entire original text when JSON parsing fails
}