#[cfg(feature = "db")]
mod factory_tests {
#[cfg(feature = "test-support")]
use diesel::prelude::*;
#[cfg(feature = "test-support")]
use diesel_async::AsyncPgConnection;
#[cfg(feature = "test-support")]
use diesel_async::RunQueryDsl;
#[cfg(feature = "test-support")]
use diesel_async::pooled_connection::deadpool::Pool;
diesel::table! {
factory_items (id) {
id -> Int8,
name -> Text,
score -> Int4,
active -> Bool,
tag -> Nullable<Text>,
}
}
#[autumn_web::model(table = "factory_items")]
pub struct FactoryItem {
#[id]
pub id: i64,
pub name: String,
pub score: i32,
pub active: bool,
pub tag: Option<String>,
}
#[test]
fn factory_build_with_defaults() {
let item = FactoryItem::factory().build();
assert_eq!(item.name, "");
assert_eq!(item.score, 0);
assert!(!item.active);
assert_eq!(item.tag, None);
}
#[test]
fn factory_build_override_single_field() {
let item = FactoryItem::factory().name("Widget").build();
assert_eq!(item.name, "Widget");
assert_eq!(item.score, 0);
assert!(!item.active);
}
#[test]
fn factory_build_override_multiple_fields() {
let item = FactoryItem::factory()
.name("Gadget")
.score(99)
.active(true)
.tag(Some("featured".to_string()))
.build();
assert_eq!(item.name, "Gadget");
assert_eq!(item.score, 99);
assert!(item.active);
assert_eq!(item.tag, Some("featured".to_string()));
}
#[test]
fn factory_build_is_independent() {
let a = FactoryItem::factory().name("Alpha").build();
let b = FactoryItem::factory().name("Beta").build();
assert_eq!(a.name, "Alpha");
assert_eq!(b.name, "Beta");
}
#[test]
fn factory_default_impl() {
let f1 = FactoryItemFactory::default();
let f2 = FactoryItemFactory::default();
let i1 = f1.build();
let i2 = f2.build();
assert_eq!(i1.name, i2.name);
assert_eq!(i1.score, i2.score);
}
#[test]
fn factory_build_returns_new_model() {
let _: NewFactoryItem = FactoryItem::factory().build();
}
#[test]
fn factory_string_setter_accepts_str_slice() {
let item = FactoryItem::factory().name("direct slice").build();
assert_eq!(item.name, "direct slice");
}
#[cfg(feature = "test-support")]
async fn setup_table(pool: &Pool<AsyncPgConnection>) {
let mut conn = pool.get().await.unwrap();
diesel::sql_query(
"CREATE TABLE IF NOT EXISTS factory_items (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL DEFAULT '',
score INT NOT NULL DEFAULT 0,
active BOOL NOT NULL DEFAULT FALSE,
tag TEXT
)",
)
.execute(&mut *conn)
.await
.unwrap();
diesel::sql_query("TRUNCATE factory_items RESTART IDENTITY")
.execute(&mut *conn)
.await
.unwrap();
}
#[cfg(feature = "test-support")]
#[tokio::test]
#[ignore = "requires Docker (testcontainers)"]
async fn factory_create_persists_and_returns_record() {
let db: &autumn_web::test::TestDb = autumn_web::test::TestDb::shared().await;
setup_table(&db.pool()).await;
let item = FactoryItem::factory()
.name("Persisted")
.score(7)
.active(true)
.create(&db.pool())
.await;
assert!(item.id > 0, "id should be populated by the database");
assert_eq!(item.name, "Persisted");
assert_eq!(item.score, 7);
assert!(item.active);
}
#[cfg(feature = "test-support")]
#[tokio::test]
#[ignore = "requires Docker (testcontainers)"]
async fn factory_create_default_then_query() {
let db: &autumn_web::test::TestDb = autumn_web::test::TestDb::shared().await;
setup_table(&db.pool()).await;
let created = FactoryItem::factory()
.name("QueryMe")
.create(&db.pool())
.await;
let mut conn = db.pool().get().await.unwrap();
let fetched: FactoryItem = factory_items::table
.find(created.id)
.select(FactoryItem::as_select())
.first(&mut *conn)
.await
.unwrap();
assert_eq!(fetched.name, "QueryMe");
assert_eq!(fetched.id, created.id);
}
#[cfg(feature = "test-support")]
#[tokio::test]
#[ignore = "requires Docker (testcontainers)"]
async fn factory_create_multiple_independent_records() {
let db: &autumn_web::test::TestDb = autumn_web::test::TestDb::shared().await;
setup_table(&db.pool()).await;
let a = FactoryItem::factory()
.name("Alpha")
.score(1)
.create(&db.pool())
.await;
let b = FactoryItem::factory()
.name("Beta")
.score(2)
.create(&db.pool())
.await;
assert_ne!(a.id, b.id, "each create() should produce a distinct record");
assert_eq!(a.name, "Alpha");
assert_eq!(b.name, "Beta");
}
#[test]
fn factory_composition_via_field_override() {
let item_for_user_42 = FactoryItem::factory()
.score(42) .build();
assert_eq!(item_for_user_42.score, 42);
}
}
#[cfg(feature = "db")]
mod composition_tests {
#[cfg(feature = "test-support")]
use diesel_async::RunQueryDsl;
diesel::table! {
comp_users (id) {
id -> Int8,
name -> Text,
}
}
diesel::table! {
comp_posts (id) {
id -> Int8,
title -> Text,
user_id -> Int8,
}
}
#[autumn_web::model(table = "comp_users")]
pub struct CompUser {
#[id]
pub id: i64,
pub name: String,
}
#[autumn_web::model(table = "comp_posts")]
pub struct CompPost {
#[id]
pub id: i64,
pub title: String,
#[factory_assoc(CompUser)]
pub user_id: i64,
}
#[test]
fn assoc_field_defaults_to_zero_in_build() {
let p = CompPost::factory().build();
assert_eq!(p.user_id, 0); }
#[test]
fn assoc_field_explicit_id_setter() {
let p = CompPost::factory().user_id(99_i64).build();
assert_eq!(p.user_id, 99);
}
#[test]
fn assoc_field_pre_built_instance_setter() {
let user = CompUser {
id: 42,
name: "Alice".into(),
};
let p = CompPost::factory().user(&user).build();
assert_eq!(p.user_id, 42);
assert_eq!(user.id, 42);
}
#[cfg(feature = "test-support")]
async fn setup(
pool: &diesel_async::pooled_connection::deadpool::Pool<diesel_async::AsyncPgConnection>,
) {
let mut conn = pool.get().await.unwrap();
diesel::sql_query(
"CREATE TABLE IF NOT EXISTS comp_users (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL DEFAULT ''
)",
)
.execute(&mut *conn)
.await
.unwrap();
diesel::sql_query(
"CREATE TABLE IF NOT EXISTS comp_posts (
id BIGSERIAL PRIMARY KEY,
title TEXT NOT NULL DEFAULT '',
user_id BIGINT NOT NULL DEFAULT 0
)",
)
.execute(&mut *conn)
.await
.unwrap();
diesel::sql_query("TRUNCATE comp_posts, comp_users RESTART IDENTITY CASCADE")
.execute(&mut *conn)
.await
.unwrap();
}
#[cfg(feature = "test-support")]
#[tokio::test]
#[ignore = "requires Docker (testcontainers)"]
async fn factory_auto_creates_associated_model() {
let db: &autumn_web::test::TestDb = autumn_web::test::TestDb::shared().await;
setup(&db.pool()).await;
let post = CompPost::factory()
.title("Auto-composed post")
.create(&db.pool())
.await;
assert!(post.id > 0);
assert!(post.user_id > 0, "factory should have auto-created a user");
assert_eq!(post.title, "Auto-composed post");
}
#[cfg(feature = "test-support")]
#[tokio::test]
#[ignore = "requires Docker (testcontainers)"]
async fn factory_uses_pre_built_user_when_supplied() {
let db: &autumn_web::test::TestDb = autumn_web::test::TestDb::shared().await;
setup(&db.pool()).await;
let user = CompUser::factory().name("Alice").create(&db.pool()).await;
let post = CompPost::factory()
.title("Alice's post")
.user(&user)
.create(&db.pool())
.await;
assert_eq!(post.user_id, user.id);
}
#[cfg(feature = "test-support")]
#[tokio::test]
#[ignore = "requires Docker (testcontainers)"]
async fn factory_explicit_user_id_skips_auto_create() {
let db: &autumn_web::test::TestDb = autumn_web::test::TestDb::shared().await;
setup(&db.pool()).await;
let user = CompUser::factory().name("Bob").create(&db.pool()).await;
let post = CompPost::factory()
.title("Bob's post")
.user_id(user.id)
.create(&db.pool())
.await;
assert_eq!(post.user_id, user.id);
}
}