Skip to content

Commit 46a4b0f

Browse files
committed
Fix Add testcase
1 parent 846de4d commit 46a4b0f

3 files changed

Lines changed: 179 additions & 4 deletions

File tree

crates/vespera_core/src/schema.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,14 @@ mod tests {
437437
assert!(required.is_empty());
438438
}
439439

440+
#[test]
441+
fn serialize_number_constraint_none_serializes_null() {
442+
// Direct call bypasses skip_serializing_if to cover the None branch
443+
let result =
444+
super::serialize_number_constraint(&None, serde_json::value::Serializer).unwrap();
445+
assert_eq!(result, serde_json::Value::Null);
446+
}
447+
440448
#[test]
441449
fn serialize_minimum_whole_number_as_integer() {
442450
let schema = Schema {

crates/vespera_macro/src/schema_macro/circular.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,8 @@ pub fn analyze_circular_refs(source_module_path: &[String], definition: &str) ->
6262
let mut circular_field_required = HashMap::new();
6363

6464
for field in &fields_named.named {
65-
let Some(field_ident) = field.ident.as_ref() else {
66-
continue;
67-
};
65+
// FieldsNamed guarantees all fields have identifiers
66+
let field_ident = field.ident.as_ref().expect("named field has ident");
6867
let field_name = field_ident.to_string();
6968
let ty_str = quote!(#field.ty).to_string().replace(' ', "");
7069

crates/vespera_macro/src/schema_macro/tests.rs

Lines changed: 169 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,175 @@ fn test_generate_schema_type_code_with_partial_fields() {
471471
assert!(result.is_ok());
472472
let (tokens, _metadata) = result.unwrap();
473473
let output = tokens.to_string();
474-
assert!(output.contains("UpdateUser"));
474+
assert!(
475+
output.contains("UpdateUser"),
476+
"should contain generated struct name: {output}"
477+
);
478+
}
479+
480+
// --- Coverage: sql_function_default_body branches ---
481+
482+
#[test]
483+
fn test_sql_function_default_non_path_type_skips() {
484+
// Reference type (&str) is Type::Reference, not Type::Path → sql_function_default_body returns None
485+
let attrs: Vec<syn::Attribute> = vec![syn::parse_quote!(#[sea_orm(default_value = "GEN()")])];
486+
let struct_name = syn::Ident::new("Test", proc_macro2::Span::call_site());
487+
let ty: syn::Type = syn::parse_str("&str").unwrap();
488+
let mut fns = Vec::new();
489+
let (serde, schema) =
490+
generate_sea_orm_default_attrs(&attrs, &struct_name, "val", &ty, &ty, false, &mut fns);
491+
assert!(serde.is_empty());
492+
assert!(schema.is_empty());
493+
assert!(fns.is_empty());
494+
}
495+
496+
#[test]
497+
fn test_sql_function_default_datetime_with_timezone() {
498+
let attrs: Vec<syn::Attribute> = vec![syn::parse_quote!(#[sea_orm(default_value = "NOW()")])];
499+
let struct_name = syn::Ident::new("Test", proc_macro2::Span::call_site());
500+
let ty: syn::Type = syn::parse_str("DateTimeWithTimeZone").unwrap();
501+
let mut fns = Vec::new();
502+
let (serde, schema) =
503+
generate_sea_orm_default_attrs(&attrs, &struct_name, "ts", &ty, &ty, false, &mut fns);
504+
let serde_str = serde.to_string();
505+
assert!(
506+
serde_str.contains("serde"),
507+
"should have serde attr: {serde_str}"
508+
);
509+
assert!(schema.is_empty());
510+
assert_eq!(fns.len(), 1);
511+
let fn_str = fns[0].to_string();
512+
assert!(
513+
fn_str.contains("UNIX_EPOCH"),
514+
"should use epoch default: {fn_str}"
515+
);
516+
}
517+
518+
#[test]
519+
fn test_sql_function_default_datetime_utc() {
520+
let attrs: Vec<syn::Attribute> = vec![syn::parse_quote!(#[sea_orm(default_value = "NOW()")])];
521+
let struct_name = syn::Ident::new("Test", proc_macro2::Span::call_site());
522+
let ty: syn::Type = syn::parse_str("DateTimeUtc").unwrap();
523+
let mut fns = Vec::new();
524+
let (serde, schema) =
525+
generate_sea_orm_default_attrs(&attrs, &struct_name, "ts", &ty, &ty, false, &mut fns);
526+
let serde_str = serde.to_string();
527+
assert!(
528+
serde_str.contains("serde"),
529+
"should have serde attr: {serde_str}"
530+
);
531+
assert!(schema.is_empty());
532+
assert_eq!(fns.len(), 1);
533+
let fn_str = fns[0].to_string();
534+
assert!(
535+
fn_str.contains("UNIX_EPOCH"),
536+
"should use epoch default: {fn_str}"
537+
);
538+
}
539+
540+
#[test]
541+
fn test_sql_function_default_datetime_local() {
542+
let attrs: Vec<syn::Attribute> = vec![syn::parse_quote!(#[sea_orm(default_value = "NOW()")])];
543+
let struct_name = syn::Ident::new("Test", proc_macro2::Span::call_site());
544+
let ty: syn::Type = syn::parse_str("DateTimeLocal").unwrap();
545+
let mut fns = Vec::new();
546+
let (serde, schema) =
547+
generate_sea_orm_default_attrs(&attrs, &struct_name, "ts", &ty, &ty, false, &mut fns);
548+
let serde_str = serde.to_string();
549+
assert!(
550+
serde_str.contains("serde"),
551+
"should have serde attr: {serde_str}"
552+
);
553+
assert!(schema.is_empty());
554+
assert_eq!(fns.len(), 1);
555+
let fn_str = fns[0].to_string();
556+
assert!(
557+
fn_str.contains("UNIX_EPOCH"),
558+
"should use epoch default: {fn_str}"
559+
);
560+
}
561+
562+
#[test]
563+
fn test_sql_function_default_naive_datetime() {
564+
let attrs: Vec<syn::Attribute> = vec![syn::parse_quote!(#[sea_orm(default_value = "NOW()")])];
565+
let struct_name = syn::Ident::new("Test", proc_macro2::Span::call_site());
566+
let ty: syn::Type = syn::parse_str("NaiveDateTime").unwrap();
567+
let mut fns = Vec::new();
568+
let (serde, schema) =
569+
generate_sea_orm_default_attrs(&attrs, &struct_name, "ts", &ty, &ty, false, &mut fns);
570+
let serde_str = serde.to_string();
571+
assert!(
572+
serde_str.contains("serde"),
573+
"should have serde attr: {serde_str}"
574+
);
575+
assert!(schema.is_empty());
576+
assert_eq!(fns.len(), 1);
577+
let fn_str = fns[0].to_string();
578+
assert!(
579+
fn_str.contains("UNIX_EPOCH"),
580+
"should use epoch default: {fn_str}"
581+
);
582+
}
583+
584+
#[test]
585+
fn test_sql_function_default_naive_date() {
586+
let attrs: Vec<syn::Attribute> =
587+
vec![syn::parse_quote!(#[sea_orm(default_value = "CURDATE()")])];
588+
let struct_name = syn::Ident::new("Test", proc_macro2::Span::call_site());
589+
let ty: syn::Type = syn::parse_str("NaiveDate").unwrap();
590+
let mut fns = Vec::new();
591+
let (serde, schema) =
592+
generate_sea_orm_default_attrs(&attrs, &struct_name, "d", &ty, &ty, false, &mut fns);
593+
let serde_str = serde.to_string();
594+
assert!(
595+
serde_str.contains("serde"),
596+
"should have serde attr: {serde_str}"
597+
);
598+
assert!(schema.is_empty());
599+
assert_eq!(fns.len(), 1);
600+
let fn_str = fns[0].to_string();
601+
assert!(
602+
fn_str.contains("from_ymd_opt"),
603+
"should use ymd default: {fn_str}"
604+
);
605+
}
606+
607+
#[test]
608+
fn test_sql_function_default_naive_time() {
609+
let attrs: Vec<syn::Attribute> =
610+
vec![syn::parse_quote!(#[sea_orm(default_value = "CURTIME()")])];
611+
let struct_name = syn::Ident::new("Test", proc_macro2::Span::call_site());
612+
let ty: syn::Type = syn::parse_str("NaiveTime").unwrap();
613+
let mut fns = Vec::new();
614+
let (serde, schema) =
615+
generate_sea_orm_default_attrs(&attrs, &struct_name, "t", &ty, &ty, false, &mut fns);
616+
let serde_str = serde.to_string();
617+
assert!(
618+
serde_str.contains("serde"),
619+
"should have serde attr: {serde_str}"
620+
);
621+
assert!(schema.is_empty());
622+
assert_eq!(fns.len(), 1);
623+
let fn_str = fns[0].to_string();
624+
assert!(
625+
fn_str.contains("from_hms_opt"),
626+
"should use hms default: {fn_str}"
627+
);
628+
}
629+
630+
// --- Coverage: is_parseable_type empty segments ---
631+
632+
#[test]
633+
fn test_is_parseable_type_empty_segments() {
634+
// Synthetically construct a Type::Path with empty segments (impossible through parsing)
635+
let ty = syn::Type::Path(syn::TypePath {
636+
qself: None,
637+
path: syn::Path {
638+
leading_colon: None,
639+
segments: syn::punctuated::Punctuated::new(),
640+
},
641+
});
642+
assert!(!is_parseable_type(&ty));
475643
}
476644

477645
#[test]

0 commit comments

Comments
 (0)