Skip to content

Commit 0129a72

Browse files
committed
Add testcase
1 parent 9d50df9 commit 0129a72

1 file changed

Lines changed: 90 additions & 54 deletions

File tree

crates/vespera_macro/src/parser/parameters.rs

Lines changed: 90 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,27 @@ use super::schema::{
1111
parse_type_to_schema_ref_with_schemas, rename_field,
1212
};
1313

14+
/// Convert SchemaRef to inline schema for query parameters
15+
/// Query parameters should always use inline schemas, not refs
16+
/// Adds nullable flag if the field is optional
17+
fn convert_to_inline_schema(field_schema: SchemaRef, is_optional: bool) -> SchemaRef {
18+
match field_schema {
19+
SchemaRef::Inline(mut schema) => {
20+
if is_optional {
21+
schema.nullable = Some(true);
22+
}
23+
SchemaRef::Inline(schema)
24+
}
25+
SchemaRef::Ref(_) => {
26+
let mut schema = Schema::new(SchemaType::Object);
27+
if is_optional {
28+
schema.nullable = Some(true);
29+
}
30+
SchemaRef::Inline(Box::new(schema))
31+
}
32+
}
33+
}
34+
1435
/// Analyze function parameter and convert to OpenAPI Parameter(s)
1536
/// Returns None if parameter should be ignored (e.g., Query<HashMap<...>>)
1637
/// Returns Some(Vec<Parameter>) with one or more parameters
@@ -393,46 +414,23 @@ fn parse_query_struct_to_parameters(
393414

394415
// Convert ref to inline if needed (Query parameters should not use refs)
395416
// If it's a ref to a known struct, get the struct definition and inline it
396-
if let SchemaRef::Ref(ref_ref) = &field_schema {
397-
// Try to extract type name from ref path (e.g., "#/components/schemas/User" -> "User")
398-
if let Some(type_name) =
417+
if let SchemaRef::Ref(ref_ref) = &field_schema
418+
&& let Some(type_name) =
399419
ref_ref.ref_path.strip_prefix("#/components/schemas/")
400-
&& let Some(struct_def) = struct_definitions.get(type_name)
401-
&& let Ok(nested_struct_item) =
402-
syn::parse_str::<syn::ItemStruct>(struct_def)
403-
{
404-
// Parse the nested struct to schema (inline)
405-
let nested_schema = parse_struct_to_schema(
406-
&nested_struct_item,
407-
known_schemas,
408-
struct_definitions,
409-
);
410-
field_schema = SchemaRef::Inline(Box::new(nested_schema));
411-
}
420+
&& let Some(struct_def) = struct_definitions.get(type_name)
421+
&& let Ok(nested_struct_item) =
422+
syn::parse_str::<syn::ItemStruct>(struct_def)
423+
{
424+
// Parse the nested struct to schema (inline)
425+
let nested_schema = parse_struct_to_schema(
426+
&nested_struct_item,
427+
known_schemas,
428+
struct_definitions,
429+
);
430+
field_schema = SchemaRef::Inline(Box::new(nested_schema));
412431
}
413432

414-
// If it's Option<T>, make it nullable
415-
let final_schema = if is_optional {
416-
if let SchemaRef::Inline(mut schema) = field_schema {
417-
schema.nullable = Some(true);
418-
SchemaRef::Inline(schema)
419-
} else {
420-
// If still a ref, convert to inline object with nullable
421-
SchemaRef::Inline(Box::new(Schema {
422-
schema_type: Some(SchemaType::Object),
423-
nullable: Some(true),
424-
..Schema::object()
425-
}))
426-
}
427-
} else {
428-
// If it's still a ref, convert to inline object
429-
match field_schema {
430-
SchemaRef::Ref(_) => {
431-
SchemaRef::Inline(Box::new(Schema::new(SchemaType::Object)))
432-
}
433-
SchemaRef::Inline(schema) => SchemaRef::Inline(schema),
434-
}
435-
};
433+
let final_schema = convert_to_inline_schema(field_schema, is_optional);
436434

437435
let required = !is_optional;
438436

@@ -1011,23 +1009,6 @@ mod tests {
10111009
}
10121010
}
10131011

1014-
// NOTE: Line 313 is defensive/unreachable code.
1015-
//
1016-
// Analysis: Line 313 requires:
1017-
// 1. is_optional == true (field type starts with "Option")
1018-
// 2. field_schema is still SchemaRef::Ref after the conversion at lines 294-304
1019-
//
1020-
// However, parse_type_to_schema_ref_with_schemas("Option<T>") ALWAYS returns
1021-
// SchemaRef::Inline because:
1022-
// - schema.rs lines 650-668 handle Option specially
1023-
// - If inner type is Inline → returns Inline (line 660)
1024-
// - If inner type is Ref → wraps in Inline (line 664)
1025-
//
1026-
// Therefore, for any field whose type starts with "Option", field_schema at line 290
1027-
// will always be SchemaRef::Inline, making the else branch at line 312-313 unreachable.
1028-
//
1029-
// This is defensive code guarding against future changes to Option handling in schema.rs.
1030-
10311012
#[test]
10321013
fn test_schema_ref_to_inline_conversion_required() {
10331014
// Test line 318: SchemaRef::Ref converted to inline for required fields
@@ -1117,4 +1098,59 @@ mod tests {
11171098
_ => panic!("Expected inline schema (converted from Ref via struct_def)"),
11181099
}
11191100
}
1101+
1102+
// Tests for convert_to_inline_schema helper function
1103+
#[test]
1104+
fn test_convert_to_inline_schema_inline_required() {
1105+
let schema = SchemaRef::Inline(Box::new(Schema::string()));
1106+
let result = convert_to_inline_schema(schema, false);
1107+
match result {
1108+
SchemaRef::Inline(s) => {
1109+
assert_eq!(s.schema_type, Some(SchemaType::String));
1110+
assert!(s.nullable.is_none());
1111+
}
1112+
_ => panic!("Expected Inline"),
1113+
}
1114+
}
1115+
1116+
#[test]
1117+
fn test_convert_to_inline_schema_inline_optional() {
1118+
let schema = SchemaRef::Inline(Box::new(Schema::string()));
1119+
let result = convert_to_inline_schema(schema, true);
1120+
match result {
1121+
SchemaRef::Inline(s) => {
1122+
assert_eq!(s.schema_type, Some(SchemaType::String));
1123+
assert_eq!(s.nullable, Some(true));
1124+
}
1125+
_ => panic!("Expected Inline"),
1126+
}
1127+
}
1128+
1129+
#[test]
1130+
fn test_convert_to_inline_schema_ref_required() {
1131+
use vespera_core::schema::Reference;
1132+
let schema = SchemaRef::Ref(Reference::schema("SomeType"));
1133+
let result = convert_to_inline_schema(schema, false);
1134+
match result {
1135+
SchemaRef::Inline(s) => {
1136+
assert_eq!(s.schema_type, Some(SchemaType::Object));
1137+
assert!(s.nullable.is_none());
1138+
}
1139+
_ => panic!("Expected Inline"),
1140+
}
1141+
}
1142+
1143+
#[test]
1144+
fn test_convert_to_inline_schema_ref_optional() {
1145+
use vespera_core::schema::Reference;
1146+
let schema = SchemaRef::Ref(Reference::schema("SomeType"));
1147+
let result = convert_to_inline_schema(schema, true);
1148+
match result {
1149+
SchemaRef::Inline(s) => {
1150+
assert_eq!(s.schema_type, Some(SchemaType::Object));
1151+
assert_eq!(s.nullable, Some(true));
1152+
}
1153+
_ => panic!("Expected Inline"),
1154+
}
1155+
}
11201156
}

0 commit comments

Comments
 (0)