Skip to content

Commit 85d980c

Browse files
committed
Add coverage
1 parent e4f1946 commit 85d980c

4 files changed

Lines changed: 276 additions & 99 deletions

File tree

crates/vespera_macro/src/parser/operation.rs

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -160,45 +160,45 @@ pub fn build_operation_from_function(
160160
}
161161

162162
// Fallback: if last arg is String/&str and no body yet, treat as text/plain body
163-
if request_body.is_none() {
164-
if let Some(FnArg::Typed(PatType { ty, .. })) = sig.inputs.last() {
165-
let is_string = match ty.as_ref() {
166-
Type::Path(type_path) => type_path
167-
.path
168-
.segments
169-
.last()
170-
.map(|s| s.ident == "String" || s.ident == "str")
171-
.unwrap_or(false),
172-
Type::Reference(type_ref) => {
173-
if let Type::Path(p) = type_ref.elem.as_ref() {
174-
p.path
175-
.segments
176-
.last()
177-
.map(|s| s.ident == "String" || s.ident == "str")
178-
.unwrap_or(false)
179-
} else {
180-
false
181-
}
163+
if request_body.is_none()
164+
&& let Some(FnArg::Typed(PatType { ty, .. })) = sig.inputs.last()
165+
{
166+
let is_string = match ty.as_ref() {
167+
Type::Path(type_path) => type_path
168+
.path
169+
.segments
170+
.last()
171+
.map(|s| s.ident == "String" || s.ident == "str")
172+
.unwrap_or(false),
173+
Type::Reference(type_ref) => {
174+
if let Type::Path(p) = type_ref.elem.as_ref() {
175+
p.path
176+
.segments
177+
.last()
178+
.map(|s| s.ident == "String" || s.ident == "str")
179+
.unwrap_or(false)
180+
} else {
181+
false
182182
}
183-
_ => false,
184-
};
185-
186-
if is_string {
187-
let mut content = BTreeMap::new();
188-
content.insert(
189-
"text/plain".to_string(),
190-
MediaType {
191-
schema: Some(SchemaRef::Inline(Box::new(Schema::string()))),
192-
example: None,
193-
examples: None,
194-
},
195-
);
196-
request_body = Some(RequestBody {
197-
description: None,
198-
content,
199-
required: Some(true),
200-
});
201183
}
184+
_ => false,
185+
};
186+
187+
if is_string {
188+
let mut content = BTreeMap::new();
189+
content.insert(
190+
"text/plain".to_string(),
191+
MediaType {
192+
schema: Some(SchemaRef::Inline(Box::new(Schema::string()))),
193+
example: None,
194+
examples: None,
195+
},
196+
);
197+
request_body = Some(RequestBody {
198+
description: None,
199+
content,
200+
required: Some(true),
201+
});
202202
}
203203
}
204204

crates/vespera_macro/src/parser/parameters.rs

Lines changed: 46 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -47,26 +47,25 @@ pub fn parse_function_parameter(
4747
let ident_str = segment.ident.to_string();
4848

4949
// Handle Option<TypedHeader<T>>
50-
if ident_str == "Option" {
51-
if let syn::PathArguments::AngleBracketed(args) = &segment.arguments
52-
&& let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first()
53-
&& let Type::Path(inner_type_path) = inner_ty
54-
&& !inner_type_path.path.segments.is_empty()
55-
{
56-
let inner_segment = inner_type_path.path.segments.last().unwrap();
57-
let inner_ident_str = inner_segment.ident.to_string();
50+
if ident_str == "Option"
51+
&& let syn::PathArguments::AngleBracketed(args) = &segment.arguments
52+
&& let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first()
53+
&& let Type::Path(inner_type_path) = inner_ty
54+
&& !inner_type_path.path.segments.is_empty()
55+
{
56+
let inner_segment = inner_type_path.path.segments.last().unwrap();
57+
let inner_ident_str = inner_segment.ident.to_string();
5858

59-
if inner_ident_str == "TypedHeader" {
60-
// TypedHeader always uses string schema regardless of inner type
61-
return Some(vec![Parameter {
62-
name: param_name.replace("_", "-"),
63-
r#in: ParameterLocation::Header,
64-
description: None,
65-
required: Some(false),
66-
schema: Some(SchemaRef::Inline(Box::new(Schema::string()))),
67-
example: None,
68-
}]);
69-
}
59+
if inner_ident_str == "TypedHeader" {
60+
// TypedHeader always uses string schema regardless of inner type
61+
return Some(vec![Parameter {
62+
name: param_name.replace("_", "-"),
63+
r#in: ParameterLocation::Header,
64+
description: None,
65+
required: Some(false),
66+
schema: Some(SchemaRef::Inline(Box::new(Schema::string()))),
67+
example: None,
68+
}]);
7069
}
7170
}
7271
}
@@ -119,11 +118,11 @@ pub fn parse_function_parameter(
119118
}
120119
} else {
121120
// Single path parameter
122-
// Allow only when exactly one path parameter is provided
123-
if path_params.len() != 1 {
124-
return None;
125-
}
126-
let name = path_params[0].clone();
121+
// Allow only when exactly one path parameter is provided
122+
if path_params.len() != 1 {
123+
return None;
124+
}
125+
let name = path_params[0].clone();
127126
return Some(vec![Parameter {
128127
name,
129128
r#in: ParameterLocation::Path,
@@ -268,16 +267,16 @@ fn is_primitive_like(ty: &Type) -> bool {
268267
if is_primitive_type(ty) {
269268
return true;
270269
}
271-
if let Type::Path(type_path) = ty {
272-
if let Some(seg) = type_path.path.segments.last() {
273-
let ident = seg.ident.to_string();
274-
if let syn::PathArguments::AngleBracketed(args) = &seg.arguments {
275-
if let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() {
276-
if (ident == "Vec" || ident == "Option") && is_primitive_like(inner_ty) {
277-
return true;
278-
}
279-
}
280-
}
270+
if let Type::Path(type_path) = ty
271+
&& let Some(seg) = type_path.path.segments.last()
272+
{
273+
let ident = seg.ident.to_string();
274+
if let syn::PathArguments::AngleBracketed(args) = &seg.arguments
275+
&& let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first()
276+
&& (ident == "Vec" || ident == "Option")
277+
&& is_primitive_like(inner_ty)
278+
{
279+
return true;
281280
}
282281
}
283282
false
@@ -459,15 +458,15 @@ fn parse_query_struct_to_parameters(
459458
#[cfg(test)]
460459
mod tests {
461460
use super::*;
461+
use insta::{assert_debug_snapshot, with_settings};
462462
use rstest::rstest;
463463
use std::collections::HashMap;
464464
use vespera_core::route::ParameterLocation;
465-
use insta::{assert_debug_snapshot, with_settings};
466465

467466
fn setup_test_data(func_src: &str) -> (HashMap<String, String>, HashMap<String, String>) {
468467
let mut struct_definitions = HashMap::new();
469468
let known_schemas: HashMap<String, String> = HashMap::new();
470-
469+
471470
if func_src.contains("QueryParams") {
472471
struct_definitions.insert(
473472
"QueryParams".to_string(),
@@ -480,7 +479,7 @@ mod tests {
480479
.to_string(),
481480
);
482481
}
483-
482+
484483
if func_src.contains("User") {
485484
struct_definitions.insert(
486485
"User".to_string(),
@@ -493,7 +492,7 @@ mod tests {
493492
.to_string(),
494493
);
495494
}
496-
495+
497496
(known_schemas, struct_definitions)
498497
}
499498

@@ -604,14 +603,10 @@ mod tests {
604603
let func: syn::ItemFn = syn::parse_str(func_src).unwrap();
605604
let (known_schemas, struct_definitions) = setup_test_data(func_src);
606605
let mut parameters = Vec::new();
607-
606+
608607
for (idx, arg) in func.sig.inputs.iter().enumerate() {
609-
let result = parse_function_parameter(
610-
arg,
611-
&path_params,
612-
&known_schemas,
613-
&struct_definitions,
614-
);
608+
let result =
609+
parse_function_parameter(arg, &path_params, &known_schemas, &struct_definitions);
615610
let expected = expected_locations
616611
.get(idx)
617612
.unwrap_or_else(|| expected_locations.last().unwrap());
@@ -682,15 +677,14 @@ mod tests {
682677
"pub struct User { pub id: i32 }".to_string(),
683678
);
684679
let mut known_schemas = known_schemas;
685-
known_schemas.insert("CustomHeader".to_string(), "#/components/schemas/CustomHeader".to_string());
680+
known_schemas.insert(
681+
"CustomHeader".to_string(),
682+
"#/components/schemas/CustomHeader".to_string(),
683+
);
686684

687685
for (idx, arg) in func.sig.inputs.iter().enumerate() {
688-
let result = parse_function_parameter(
689-
arg,
690-
&path_params,
691-
&known_schemas,
692-
&struct_definitions,
693-
);
686+
let result =
687+
parse_function_parameter(arg, &path_params, &known_schemas, &struct_definitions);
694688
assert!(
695689
result.is_none(),
696690
"Expected None at arg index {}, func: {}, got: {:?}",

0 commit comments

Comments
 (0)