use proc_macro2::{TokenStream, TokenTree};
use syn::{DeriveInput, parse_quote};
use crate::entity::expand;
fn tokens(input: &DeriveInput) -> usize {
fn count(stream: TokenStream) -> usize {
stream
.into_iter()
.map(|tree| match tree {
TokenTree::Group(group) => 1 + count(group.stream()),
_ => 1
})
.sum()
}
count(expand(input))
}
fn assert_within(label: &str, count: usize, ceiling: usize) {
let floor = ceiling / 2;
assert!(
count >= floor,
"{label} expanded to {count} tokens, less than half the recorded {ceiling}: a generator \
probably stopped emitting"
);
assert!(
count <= ceiling,
"{label} expanded to {count} tokens, above the recorded ceiling of {ceiling}: check what \
the change added and raise the ceiling deliberately"
);
}
#[test]
fn minimal_entity_stays_small() {
let input: DeriveInput = parse_quote! {
#[entity(table = "widgets")]
pub struct Widget {
#[id]
pub id: uuid::Uuid,
#[field(create, update, response)]
pub name: String,
}
};
assert_within("minimal entity", tokens(&input), 2_800);
}
#[test]
fn wide_entity_scales_with_columns() {
let input: DeriveInput = parse_quote! {
#[entity(table = "widgets")]
pub struct Widget {
#[id]
pub id: uuid::Uuid,
#[field(create, update, response)]
pub c1: String,
#[field(create, update, response)]
pub c2: String,
#[field(create, update, response)]
pub c3: String,
#[field(create, update, response)]
pub c4: String,
#[field(create, update, response)]
pub c5: String,
#[field(create, update, response)]
pub c6: String,
#[field(create, update, response)]
pub c7: String,
#[field(create, update, response)]
pub c8: String,
#[field(create, update, response)]
pub c9: String,
#[field(create, update, response)]
pub c10: String,
}
};
assert_within("ten-column entity", tokens(&input), 4_400);
}
#[test]
fn fully_annotated_entity_stays_within_budget() {
let input: DeriveInput = parse_quote! {
#[entity(
table = "widgets",
migrations,
soft_delete,
transactions,
aggregate_root,
events,
upsert(conflict = "slug")
)]
#[projection(Card: id, name)]
pub struct Widget {
#[id]
pub id: uuid::Uuid,
#[field(create, update, response)]
#[filter(like)]
#[sort]
pub name: String,
#[field(create, response)]
#[column(unique)]
pub slug: String,
#[owner]
#[field(create, response)]
pub owner_id: uuid::Uuid,
#[version]
#[field(response)]
#[auto]
pub version: i32,
#[field(response)]
#[auto]
pub created_at: chrono::DateTime<chrono::Utc>,
#[field(skip)]
pub deleted_at: Option<chrono::DateTime<chrono::Utc>>,
}
};
assert_within("fully annotated entity", tokens(&input), 9_200);
}