1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
//! Tests for tools array generation
//!
//! These tests ensure that tools arrays are properly typed as union types
//! instead of falling back to serde_json::Value
use openapi_to_rust::test_helpers::*;
use serde_json::json;
#[test]
fn test_tools_array_uses_proper_union_types() {
// Test that tools arrays in CreateMessageParams use proper union types for tools
let spec = json!({
"openapi": "3.1.0",
"info": {"title": "Test", "version": "1.0"},
"components": {
"schemas": {
"CreateMessageParams": {
"type": "object",
"properties": {
"model": {"type": "string"},
"messages": {
"type": "array",
"items": {"$ref": "#/components/schemas/Message"}
},
"tools": {
"type": "array",
"items": {
"oneOf": [
{"$ref": "#/components/schemas/Tool"},
{"$ref": "#/components/schemas/BashTool"}
]
},
"description": "Tools available to the model"
}
},
"required": ["model", "messages"]
},
"Message": {
"type": "object",
"properties": {
"role": {"type": "string"},
"content": {"type": "string"}
},
"required": ["role", "content"]
},
"Tool": {
"type": "object",
"properties": {
"type": {"const": "custom"},
"name": {"type": "string"},
"description": {"type": "string"},
"input_schema": {"$ref": "#/components/schemas/InputSchema"}
},
"required": ["name", "input_schema"]
},
"BashTool": {
"type": "object",
"properties": {
"type": {"const": "bash"},
"name": {"type": "string"}
},
"required": ["name"]
},
"InputSchema": {
"type": "object",
"properties": {
"type": {"type": "string"},
"properties": {"type": "object"}
}
}
}
}
});
let result = test_generation("tools_array_union_test", spec).expect("Generation failed");
// Assert that a union type was generated for the tools array
assert!(
result.contains("pub enum CreateMessageParamsToolsItem") || result.contains("ToolsItem"),
"Should generate a union enum for tools array items"
);
// Assert that Tool and BashTool types were generated
assert!(
result.contains("pub struct Tool"),
"Tool struct should be generated"
);
assert!(
result.contains("pub struct BashTool"),
"BashTool struct should be generated"
);
// Check that the tools field uses Vec of the union type, not serde_json::Value
assert!(
!result.contains("Vec<serde_json::Value>"),
"Tools field should NOT use serde_json::Value"
);
// For discriminated unions, we should see serde tag attributes or proper enum variants
assert!(
result.contains("#[serde(tag = \"type\")]")
|| result.contains("Custom")
|| result.contains("Bash")
|| result.contains("Tool(Tool)")
|| result.contains("BashTool(BashTool)"),
"Union should have proper enum variants or discriminator attributes"
);
}
#[test]
fn test_beta_tools_array_uses_proper_union_types() {
// Test that Beta tools arrays use proper union types
let spec = json!({
"openapi": "3.1.0",
"info": {"title": "Test", "version": "1.0"},
"components": {
"schemas": {
"BetaCreateMessageParams": {
"type": "object",
"properties": {
"model": {"type": "string"},
"messages": {
"type": "array",
"items": {"$ref": "#/components/schemas/Message"}
},
"tools": {
"type": "array",
"items": {
"oneOf": [
{"$ref": "#/components/schemas/BetaTool"},
{"$ref": "#/components/schemas/BetaComputerUseTool"}
]
},
"description": "Beta tools available to the model"
}
},
"required": ["model", "messages"]
},
"Message": {
"type": "object",
"properties": {
"role": {"type": "string"},
"content": {"type": "string"}
},
"required": ["role", "content"]
},
"BetaTool": {
"type": "object",
"properties": {
"type": {"const": "custom"},
"name": {"type": "string"},
"description": {"type": "string"},
"input_schema": {"$ref": "#/components/schemas/BetaInputSchema"}
},
"required": ["name", "input_schema"]
},
"BetaComputerUseTool": {
"type": "object",
"properties": {
"type": {"const": "computer_20241022"},
"name": {"type": "string"},
"display_width_px": {"type": "integer"},
"display_height_px": {"type": "integer"}
},
"required": ["name"]
},
"BetaInputSchema": {
"type": "object",
"properties": {
"type": {"type": "string"},
"properties": {"type": "object"}
}
}
}
}
});
let result = test_generation("beta_tools_array_union_test", spec).expect("Generation failed");
// The tools field should NOT use serde_json::Value
assert!(
!result.contains("Vec<serde_json::Value>"),
"Beta tools field should not use serde_json::Value"
);
// Should have a union type for tools
assert!(
result.contains("BetaCreateMessageParamsToolsItem")
|| result.contains("enum") && result.contains("BetaTool"),
"Should have union type for beta tools"
);
// Verify BetaTool and BetaComputerUseTool structs are generated
assert!(
result.contains("pub struct BetaTool"),
"BetaTool type should be generated"
);
assert!(
result.contains("pub struct BetaComputerUseTool"),
"BetaComputerUseTool type should be generated"
);
}
#[test]
fn test_simple_array_with_single_tool_type() {
// Test a simpler case where tools array has only one type
let spec = json!({
"openapi": "3.1.0",
"info": {"title": "Test", "version": "1.0"},
"components": {
"schemas": {
"SimpleRequest": {
"type": "object",
"properties": {
"tools": {
"type": "array",
"items": {"$ref": "#/components/schemas/SimpleTool"}
}
}
},
"SimpleTool": {
"type": "object",
"properties": {
"name": {"type": "string"},
"description": {"type": "string"}
},
"required": ["name"]
}
}
}
});
let result = test_generation("simple_tools_array_test", spec).expect("Generation failed");
// The tools field should use Vec<SimpleTool>, not serde_json::Value
assert!(
!result.contains("serde_json::Value"),
"Simple tools field should not use serde_json::Value"
);
assert!(
result.contains("Vec<SimpleTool>"),
"Simple tools field should use Vec<SimpleTool>"
);
// Verify SimpleTool struct is generated
assert!(
result.contains("pub struct SimpleTool"),
"SimpleTool type should be generated"
);
}