Skip to content

Commit 64d2661

Browse files
committed
Add testcase
1 parent 6d6f9ad commit 64d2661

1 file changed

Lines changed: 169 additions & 0 deletions

File tree

crates/vespera_macro/src/schema_macro/from_model.rs

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,4 +1671,173 @@ pub struct Model {
16711671
output
16721672
);
16731673
}
1674+
1675+
#[test]
1676+
#[serial]
1677+
fn test_generate_from_model_parent_stub_all_relation_types() {
1678+
// Coverage for lines 114, 117, 120
1679+
// Tests: Parent stub generation with:
1680+
use tempfile::TempDir;
1681+
1682+
let temp_dir = TempDir::new().unwrap();
1683+
let src_dir = temp_dir.path().join("src");
1684+
let models_dir = src_dir.join("models");
1685+
std::fs::create_dir_all(&models_dir).unwrap();
1686+
1687+
// Create memo.rs with REQUIRED circular back-ref to user
1688+
// This triggers needs_parent_stub = true
1689+
let memo_model = r#"
1690+
pub struct Model {
1691+
pub id: i32,
1692+
pub title: String,
1693+
pub user_id: i32,
1694+
#[sea_orm(belongs_to = "super::user::Entity", from = "user_id")]
1695+
pub user: BelongsTo<super::user::Entity>,
1696+
}
1697+
"#;
1698+
std::fs::write(models_dir.join("memo.rs"), memo_model).unwrap();
1699+
1700+
// Create profile.rs (for optional single relation)
1701+
let profile_model = r#"
1702+
pub struct Model {
1703+
pub id: i32,
1704+
pub bio: String,
1705+
}
1706+
"#;
1707+
std::fs::write(models_dir.join("profile.rs"), profile_model).unwrap();
1708+
1709+
// Create settings.rs (for required single relation)
1710+
let settings_model = r#"
1711+
pub struct Model {
1712+
pub id: i32,
1713+
pub theme: String,
1714+
}
1715+
"#;
1716+
std::fs::write(models_dir.join("settings.rs"), settings_model).unwrap();
1717+
1718+
// Save and set CARGO_MANIFEST_DIR
1719+
let original_manifest_dir = std::env::var("CARGO_MANIFEST_DIR").ok();
1720+
unsafe { std::env::set_var("CARGO_MANIFEST_DIR", temp_dir.path()) };
1721+
1722+
let new_type_name = syn::Ident::new("UserSchema", proc_macro2::Span::call_site());
1723+
let source_type: Type = syn::parse_str("crate::models::user::Model").unwrap();
1724+
1725+
// Field mappings with various relation types
1726+
let field_mappings = vec![
1727+
// Regular field
1728+
(
1729+
syn::Ident::new("id", proc_macro2::Span::call_site()),
1730+
syn::Ident::new("id", proc_macro2::Span::call_site()),
1731+
false,
1732+
false,
1733+
),
1734+
// HasMany (line 113) - this one triggers needs_parent_stub
1735+
(
1736+
syn::Ident::new("memos", proc_macro2::Span::call_site()),
1737+
syn::Ident::new("memos", proc_macro2::Span::call_site()),
1738+
false,
1739+
true,
1740+
),
1741+
// Optional single relation (line 114)
1742+
(
1743+
syn::Ident::new("profile", proc_macro2::Span::call_site()),
1744+
syn::Ident::new("profile", proc_macro2::Span::call_site()),
1745+
false,
1746+
true,
1747+
),
1748+
// Required single relation (line 117)
1749+
(
1750+
syn::Ident::new("settings", proc_macro2::Span::call_site()),
1751+
syn::Ident::new("settings", proc_macro2::Span::call_site()),
1752+
false,
1753+
true,
1754+
),
1755+
// Relation field NOT in relation_fields (line 120)
1756+
(
1757+
syn::Ident::new("orphan_rel", proc_macro2::Span::call_site()),
1758+
syn::Ident::new("orphan_rel", proc_macro2::Span::call_site()),
1759+
false,
1760+
true,
1761+
),
1762+
];
1763+
1764+
// Relation fields - note: orphan_rel is NOT included here (hits line 120)
1765+
let relation_fields = vec![
1766+
// HasMany without inline_type_info (triggers needs_parent_stub)
1767+
create_test_relation_info(
1768+
"memos",
1769+
"HasMany",
1770+
quote! { crate::models::memo::Schema },
1771+
false,
1772+
),
1773+
// Optional HasOne (hits line 114)
1774+
create_test_relation_info(
1775+
"profile",
1776+
"HasOne",
1777+
quote! { crate::models::profile::Schema },
1778+
true, // optional
1779+
),
1780+
// Required BelongsTo (hits line 117)
1781+
create_test_relation_info(
1782+
"settings",
1783+
"BelongsTo",
1784+
quote! { crate::models::settings::Schema },
1785+
false, // required
1786+
),
1787+
// Note: orphan_rel is NOT in relation_fields (hits line 120)
1788+
];
1789+
1790+
let source_module_path = vec![
1791+
"crate".to_string(),
1792+
"models".to_string(),
1793+
"user".to_string(),
1794+
];
1795+
1796+
let tokens = generate_from_model_with_relations(
1797+
&new_type_name,
1798+
&source_type,
1799+
&field_mappings,
1800+
&relation_fields,
1801+
&source_module_path,
1802+
&[],
1803+
);
1804+
1805+
// Restore CARGO_MANIFEST_DIR
1806+
unsafe {
1807+
if let Some(dir) = original_manifest_dir {
1808+
std::env::set_var("CARGO_MANIFEST_DIR", dir);
1809+
} else {
1810+
std::env::remove_var("CARGO_MANIFEST_DIR");
1811+
}
1812+
}
1813+
1814+
let output = tokens.to_string();
1815+
assert!(output.contains("impl UserSchema"));
1816+
// Should have parent stub (line 307)
1817+
assert!(
1818+
output.contains("__parent_stub__"),
1819+
"Should have parent stub: {}",
1820+
output
1821+
);
1822+
// Parent stub should have various default values
1823+
// Line 113: memos: vec![]
1824+
assert!(
1825+
output.contains("memos : vec ! []"),
1826+
"Should have memos: vec![]: {}",
1827+
output
1828+
);
1829+
// Line 114 & 117: profile/settings: None (both optional and required single relations)
1830+
// (Both produce None in parent stub)
1831+
assert!(
1832+
output.contains("profile : None") || output.contains("settings : None"),
1833+
"Should have None for single relations: {}",
1834+
output
1835+
);
1836+
// Line 120: orphan_rel: Default::default()
1837+
assert!(
1838+
output.contains("Default :: default ()"),
1839+
"Should have Default::default() for orphan: {}",
1840+
output
1841+
);
1842+
}
16741843
}

0 commit comments

Comments
 (0)