diff --git a/src/main.rs b/src/main.rs index 2208e27..b4c237e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -135,7 +135,7 @@ async fn main() -> Result<(), Box> { // WebAuthn config from env vars. RP_ID must match the host users access the site from. let rp_id = env::var("RP_ID").unwrap_or_else(|_| { - let host = public_base_url + public_base_url .trim_start_matches("http://") .trim_start_matches("https://") .split('/') @@ -144,8 +144,7 @@ async fn main() -> Result<(), Box> { .split(':') .next() .unwrap_or("localhost") - .to_owned(); - host + .to_owned() }); let rp_name = env::var("RP_NAME").unwrap_or_else(|_| "Sustenance".into()); let origin = diff --git a/src/ports.rs b/src/ports.rs index 493035d..75f2d76 100644 --- a/src/ports.rs +++ b/src/ports.rs @@ -153,6 +153,10 @@ pub trait ItemRepository: Send + Sync { item_id: i64, checked: bool, ) -> DomainResult; + /// Update the mutable fields of an item. The bare field list mirrors the + /// edit form's inputs; clippy flags the argument count, which is justified + /// here by the flat domain signature. + #[allow(clippy::too_many_arguments)] async fn update_item( &self, txn: &mut SqliteConnection, @@ -276,6 +280,9 @@ pub trait MealIngredientRepository: Send + Sync { note: String, category_id: Option, ) -> DomainResult; + /// Update the mutable fields of a meal ingredient. Same flat signature + /// rationale as `ItemRepository::update_item`. + #[allow(clippy::too_many_arguments)] async fn update_ingredient( &self, txn: &mut SqliteConnection, diff --git a/src/services.rs b/src/services.rs index 48bd228..ec09353 100644 --- a/src/services.rs +++ b/src/services.rs @@ -345,6 +345,9 @@ pub struct MealService { } impl MealService { + /// Builds the meal service from its dependencies. The argument count is + /// intentional: it assembles the service's repository/notifier graph. + #[allow(clippy::too_many_arguments)] pub fn new( db: SqliteDatabase, meals: Arc, diff --git a/src/sqlite.rs b/src/sqlite.rs index 04c6395..6bb6fd2 100644 --- a/src/sqlite.rs +++ b/src/sqlite.rs @@ -1539,7 +1539,7 @@ mod tests { let users = SqliteUserRepository; let email = email.to_owned(); db.run(move |txn| { - let users = users.clone(); + let users = users; Box::pin(async move { users .create_user(txn, email, "Test User".into(), "hash".into()) @@ -1554,7 +1554,7 @@ mod tests { let lists = SqliteListRepository; let name = name.to_owned(); db.run(move |txn| { - let lists = lists.clone(); + let lists = lists; Box::pin(async move { lists.create_list(txn, name).await }) }) .await @@ -1565,7 +1565,7 @@ mod tests { let items = SqliteItemRepository; let name_for_insert = name.to_owned(); db.run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items .add_item( @@ -1583,7 +1583,7 @@ mod tests { .unwrap(); let items = SqliteItemRepository; db.run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items.items(txn, list_id).await }) }) .await @@ -1596,7 +1596,7 @@ mod tests { async fn get_items(db: &SqliteDatabase, list_id: i64) -> Vec { let items = SqliteItemRepository; db.run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items.items(txn, list_id).await }) }) .await @@ -1606,7 +1606,7 @@ mod tests { async fn get_categories(db: &SqliteDatabase) -> Vec { let categories = SqliteCategoryRepository; db.run(move |txn| { - let categories = categories.clone(); + let categories = categories; Box::pin(async move { categories.categories(txn).await }) }) .await @@ -1631,7 +1631,7 @@ mod tests { let users = SqliteUserRepository; let result = db .run(move |txn| { - let users = users.clone(); + let users = users; Box::pin(async move { users .create_user( @@ -1654,7 +1654,7 @@ mod tests { let users = SqliteUserRepository; let found = db .run(move |txn| { - let users = users.clone(); + let users = users; Box::pin(async move { users .find_user_by_email(txn, "alice@example.com".into()) @@ -1675,7 +1675,7 @@ mod tests { let users = SqliteUserRepository; let found = db .run(move |txn| { - let users = users.clone(); + let users = users; Box::pin(async move { users .find_user_by_email(txn, "ALICE@EXAMPLE.COM".into()) @@ -1693,7 +1693,7 @@ mod tests { let users = SqliteUserRepository; let found = db .run(move |txn| { - let users = users.clone(); + let users = users; Box::pin(async move { users .find_user_by_email(txn, "nobody@example.com".into()) @@ -1711,7 +1711,7 @@ mod tests { let users = SqliteUserRepository; let empty = db .run(move |txn| { - let users = users.clone(); + let users = users; Box::pin(async move { users.has_users(txn).await }) }) .await @@ -1721,7 +1721,7 @@ mod tests { create_user(&db, "alice@example.com").await; let has = db .run(move |txn| { - let users = users.clone(); + let users = users; Box::pin(async move { users.has_users(txn).await }) }) .await @@ -1738,7 +1738,7 @@ mod tests { let sessions = SqliteSessionRepository; let (token, csrf) = db .run(move |txn| { - let sessions = sessions.clone(); + let sessions = sessions; Box::pin(async move { sessions.create_session(txn, user.id).await }) }) .await @@ -1748,7 +1748,7 @@ mod tests { let session = db .run(move |txn| { - let sessions = sessions.clone(); + let sessions = sessions; Box::pin(async move { sessions.session_user(txn, token.clone()).await }) }) .await @@ -1764,7 +1764,7 @@ mod tests { let sessions = SqliteSessionRepository; let session = db .run(move |txn| { - let sessions = sessions.clone(); + let sessions = sessions; Box::pin(async move { sessions.session_user(txn, "bogus".into()).await }) }) .await @@ -1779,7 +1779,7 @@ mod tests { let sessions = SqliteSessionRepository; let (token, _) = db .run(move |txn| { - let sessions = sessions.clone(); + let sessions = sessions; Box::pin(async move { sessions.create_session(txn, user.id).await }) }) .await @@ -1787,7 +1787,7 @@ mod tests { let token_for_delete = token.clone(); db.run(move |txn| { - let sessions = sessions.clone(); + let sessions = sessions; Box::pin(async move { sessions.delete_session(txn, token_for_delete).await }) }) .await @@ -1795,7 +1795,7 @@ mod tests { let session = db .run(move |txn| { - let sessions = sessions.clone(); + let sessions = sessions; Box::pin(async move { sessions.session_user(txn, token).await }) }) .await @@ -1825,7 +1825,7 @@ mod tests { let lists = SqliteListRepository; let summaries = db .run(move |txn| { - let lists = lists.clone(); + let lists = lists; Box::pin(async move { lists.list_summaries(txn).await }) }) .await @@ -1843,7 +1843,7 @@ mod tests { let list_id = list.id; db.run(move |txn| { - let lists = lists.clone(); + let lists = lists; Box::pin(async move { lists.set_archived(txn, list_id, true).await }) }) .await @@ -1851,7 +1851,7 @@ mod tests { let summaries = db .run(move |txn| { - let lists = lists.clone(); + let lists = lists; Box::pin(async move { lists.list_summaries(txn).await }) }) .await @@ -1860,7 +1860,7 @@ mod tests { let archived = db .run(move |txn| { - let lists = lists.clone(); + let lists = lists; Box::pin(async move { lists.list_archived_summaries(txn).await }) }) .await @@ -1878,13 +1878,13 @@ mod tests { let list_id = list.id; db.run(move |txn| { - let lists = lists.clone(); + let lists = lists; Box::pin(async move { lists.set_archived(txn, list_id, true).await }) }) .await .unwrap(); db.run(move |txn| { - let lists = lists.clone(); + let lists = lists; Box::pin(async move { lists.set_archived(txn, list_id, false).await }) }) .await @@ -1892,7 +1892,7 @@ mod tests { let summaries = db .run(move |txn| { - let lists = lists.clone(); + let lists = lists; Box::pin(async move { lists.list_summaries(txn).await }) }) .await @@ -1907,7 +1907,7 @@ mod tests { let lists = SqliteListRepository; let result = db .run(move |txn| { - let lists = lists.clone(); + let lists = lists; Box::pin(async move { lists.set_archived(txn, 9999, true).await }) }) .await; @@ -1921,7 +1921,7 @@ mod tests { let lists = SqliteListRepository; let found = db .run(move |txn| { - let lists = lists.clone(); + let lists = lists; Box::pin(async move { lists.get_list(txn, list.id).await }) }) .await @@ -1930,7 +1930,7 @@ mod tests { let missing = db .run(move |txn| { - let lists = lists.clone(); + let lists = lists; Box::pin(async move { lists.get_list(txn, 9999).await }) }) .await @@ -1946,7 +1946,7 @@ mod tests { let categories = SqliteCategoryRepository; let id = db .run(move |txn| { - let categories = categories.clone(); + let categories = categories; Box::pin(async move { categories.create_category(txn, "Bakery".into()).await }) }) .await @@ -1963,7 +1963,7 @@ mod tests { let categories = SqliteCategoryRepository; let result = db .run(move |txn| { - let categories = categories.clone(); + let categories = categories; Box::pin(async move { categories.create_category(txn, "Produce".into()).await }) }) .await; @@ -1975,7 +1975,7 @@ mod tests { async fn get_meal_categories(db: &SqliteDatabase) -> Vec { let categories = SqliteMealCategoryRepository; db.run(move |txn| { - let categories = categories.clone(); + let categories = categories; Box::pin(async move { categories.meal_categories(txn).await }) }) .await @@ -2004,7 +2004,7 @@ mod tests { let categories = SqliteMealCategoryRepository; let id = db .run(move |txn| { - let categories = categories.clone(); + let categories = categories; Box::pin(async move { categories .create_meal_category(txn, "Breakfast".into()) @@ -2024,7 +2024,7 @@ mod tests { let categories = SqliteMealCategoryRepository; let result = db .run(move |txn| { - let categories = categories.clone(); + let categories = categories; Box::pin(async move { categories.create_meal_category(txn, "Beef".into()).await }) }) .await; @@ -2037,7 +2037,7 @@ mod tests { let categories = SqliteMealCategoryRepository; let category_id = db .run(move |txn| { - let categories = categories.clone(); + let categories = categories; Box::pin(async move { categories .create_meal_category(txn, "Breakfast".into()) @@ -2049,7 +2049,7 @@ mod tests { let meal = create_meal(&db, "Pancakes").await; let meals = SqliteMealRepository; db.run(move |txn| { - let meals = meals.clone(); + let meals = meals; Box::pin(async move { meals .update_meal( @@ -2066,7 +2066,7 @@ mod tests { .unwrap(); db.run(move |txn| { - let categories = categories.clone(); + let categories = categories; Box::pin(async move { categories.delete_meal_category(txn, category_id).await }) }) .await @@ -2074,7 +2074,7 @@ mod tests { let fetched = db .run(move |txn| { - let meals = meals.clone(); + let meals = meals; Box::pin(async move { meals.get_meal(txn, meal.id).await }) }) .await @@ -2092,7 +2092,7 @@ mod tests { let items = SqliteItemRepository; let revision = db .run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items .add_item( @@ -2126,7 +2126,7 @@ mod tests { let items = SqliteItemRepository; let result = db .run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items .add_item( @@ -2167,7 +2167,7 @@ mod tests { ]; let revision = db .run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items.add_items_bulk(txn, list.id, new_items).await }) }) .await @@ -2188,7 +2188,7 @@ mod tests { let items = SqliteItemRepository; let revision = db .run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items .update_item( @@ -2221,7 +2221,7 @@ mod tests { let items = SqliteItemRepository; let result = db .run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items .update_item( @@ -2248,7 +2248,7 @@ mod tests { let items = SqliteItemRepository; let revision = db .run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items.delete_item(txn, list.id, item.id).await }) }) .await @@ -2264,7 +2264,7 @@ mod tests { let items = SqliteItemRepository; let result = db .run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items.delete_item(txn, list.id, 9999).await }) }) .await; @@ -2278,7 +2278,7 @@ mod tests { let items = SqliteItemRepository; let result = db .run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items.set_item_checked(txn, list.id, 9999, true).await }) }) .await; @@ -2294,7 +2294,7 @@ mod tests { let invitations = SqliteInvitationRepository; let expires = db .run(move |txn| { - let invitations = invitations.clone(); + let invitations = invitations; Box::pin(async move { invitations .create_invitation(txn, user.id, "token-1".into()) @@ -2307,7 +2307,7 @@ mod tests { let valid = db .run(move |txn| { - let invitations = invitations.clone(); + let invitations = invitations; Box::pin(async move { invitations.invitation(txn, "token-1".into()).await }) }) .await @@ -2321,7 +2321,7 @@ mod tests { let invitations = SqliteInvitationRepository; let valid = db .run(move |txn| { - let invitations = invitations.clone(); + let invitations = invitations; Box::pin(async move { invitations.invitation(txn, "bogus".into()).await }) }) .await @@ -2335,7 +2335,7 @@ mod tests { let user = create_user(&db, "alice@example.com").await; let invitations = SqliteInvitationRepository; db.run(move |txn| { - let invitations = invitations.clone(); + let invitations = invitations; Box::pin(async move { invitations .create_invitation(txn, user.id, "token-1".into()) @@ -2346,7 +2346,7 @@ mod tests { .unwrap(); db.run(move |txn| { - let invitations = invitations.clone(); + let invitations = invitations; Box::pin(async move { invitations.accept_invitation(txn, "token-1".into()).await }) }) .await @@ -2354,7 +2354,7 @@ mod tests { let valid = db .run(move |txn| { - let invitations = invitations.clone(); + let invitations = invitations; Box::pin(async move { invitations.invitation(txn, "token-1".into()).await }) }) .await @@ -2368,7 +2368,7 @@ mod tests { let invitations = SqliteInvitationRepository; let result = db .run(move |txn| { - let invitations = invitations.clone(); + let invitations = invitations; Box::pin(async move { invitations.accept_invitation(txn, "bogus".into()).await }) }) .await; @@ -2384,13 +2384,13 @@ mod tests { let item = add_item(&db, list.id, "Coffee").await; let items = SqliteItemRepository; db.run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items.set_item_checked(txn, list.id, item.id, true).await }) }) .await .unwrap(); db.run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items.set_item_checked(txn, list.id, item.id, true).await }) }) .await @@ -2411,7 +2411,7 @@ mod tests { let first_item = get_items(&db, list.id).await.remove(0); db.run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items .set_item_checked(txn, list.id, first_item.id, true) @@ -2433,7 +2433,7 @@ mod tests { let meals = SqliteMealRepository; let name = name.to_owned(); db.run(move |txn| { - let meals = meals.clone(); + let meals = meals; Box::pin(async move { meals.create_meal(txn, name, String::new(), None).await }) }) .await @@ -2449,7 +2449,7 @@ mod tests { let ingredients = SqliteMealIngredientRepository; let name_for_insert = name.to_owned(); db.run(move |txn| { - let ingredients = ingredients.clone(); + let ingredients = ingredients; Box::pin(async move { ingredients .add_ingredient( @@ -2467,7 +2467,7 @@ mod tests { .unwrap(); let ingredients = SqliteMealIngredientRepository; db.run(move |txn| { - let ingredients = ingredients.clone(); + let ingredients = ingredients; Box::pin(async move { ingredients.ingredients_for_meal(txn, meal_id).await }) }) .await @@ -2494,7 +2494,7 @@ mod tests { let meals = SqliteMealRepository; let meals = db .run(move |txn| { - let meals = meals.clone(); + let meals = meals; Box::pin(async move { meals.list_meals(txn, "").await }) }) .await @@ -2511,12 +2511,8 @@ mod tests { create_meal(&db, "Chicken Curry").await; let meals = SqliteMealRepository; let names = |posted_query: &str| { - let meals = meals.clone(); let posted_query = posted_query.to_owned(); - db.run(move |txn| { - let meals = meals.clone(); - Box::pin(async move { meals.list_meals(txn, &posted_query).await }) - }) + db.run(move |txn| Box::pin(async move { meals.list_meals(txn, &posted_query).await })) }; let matched = names("pasta").await.unwrap(); let matched_names = matched.iter().map(|m| m.name.as_str()).collect::>(); @@ -2531,12 +2527,8 @@ mod tests { create_meal(&db, "Salad").await; let meals = SqliteMealRepository; let names = |posted_query: &str| { - let meals = meals.clone(); let posted_query = posted_query.to_owned(); - db.run(move |txn| { - let meals = meals.clone(); - Box::pin(async move { meals.list_meals(txn, &posted_query).await }) - }) + db.run(move |txn| Box::pin(async move { meals.list_meals(txn, &posted_query).await })) }; // A bare `%` must not act as a wildcard matching every meal: it only // matches meals that contain a literal `%` character. @@ -2558,7 +2550,7 @@ mod tests { let meals = SqliteMealRepository; let fetched = db .run(move |txn| { - let meals = meals.clone(); + let meals = meals; Box::pin(async move { meals.get_meal(txn, meal.id).await }) }) .await @@ -2580,7 +2572,7 @@ mod tests { let meals = SqliteMealRepository; let found = db .run(move |txn| { - let meals = meals.clone(); + let meals = meals; Box::pin(async move { meals.get_meal(txn, 9999).await }) }) .await @@ -2594,7 +2586,7 @@ mod tests { let meal = create_meal(&db, "Pasta").await; let meals = SqliteMealRepository; db.run(move |txn| { - let meals = meals.clone(); + let meals = meals; Box::pin(async move { meals .update_meal( @@ -2611,7 +2603,7 @@ mod tests { .unwrap(); let fetched = db .run(move |txn| { - let meals = meals.clone(); + let meals = meals; Box::pin(async move { meals.get_meal(txn, meal.id).await }) }) .await @@ -2627,7 +2619,7 @@ mod tests { let meals = SqliteMealRepository; let result = db .run(move |txn| { - let meals = meals.clone(); + let meals = meals; Box::pin(async move { meals .update_meal(txn, 9999, "X".into(), String::new(), None) @@ -2645,14 +2637,14 @@ mod tests { add_ingredient(&db, meal.id, "Penne", None).await; let meals = SqliteMealRepository; db.run(move |txn| { - let meals = meals.clone(); + let meals = meals; Box::pin(async move { meals.delete_meal(txn, meal.id).await }) }) .await .unwrap(); let found = db .run(move |txn| { - let meals = meals.clone(); + let meals = meals; Box::pin(async move { meals.get_meal(txn, meal.id).await }) }) .await @@ -2666,7 +2658,7 @@ mod tests { let meals = SqliteMealRepository; let result = db .run(move |txn| { - let meals = meals.clone(); + let meals = meals; Box::pin(async move { meals.delete_meal(txn, 9999).await }) }) .await; @@ -2680,7 +2672,7 @@ mod tests { let ingredients = SqliteMealIngredientRepository; let result = db .run(move |txn| { - let ingredients = ingredients.clone(); + let ingredients = ingredients; Box::pin(async move { ingredients .add_ingredient( @@ -2705,7 +2697,7 @@ mod tests { let ingredient = add_ingredient(&db, meal.id, "Penne", None).await; let ingredients = SqliteMealIngredientRepository; db.run(move |txn| { - let ingredients = ingredients.clone(); + let ingredients = ingredients; Box::pin(async move { ingredients .update_ingredient( @@ -2724,7 +2716,7 @@ mod tests { .unwrap(); let fetched = db .run(move |txn| { - let ingredients = ingredients.clone(); + let ingredients = ingredients; Box::pin(async move { ingredients.ingredients_for_meal(txn, meal.id).await }) }) .await @@ -2740,7 +2732,7 @@ mod tests { let ingredient = add_ingredient(&db, meal.id, "Penne", None).await; let ingredients = SqliteMealIngredientRepository; db.run(move |txn| { - let ingredients = ingredients.clone(); + let ingredients = ingredients; Box::pin(async move { ingredients .delete_ingredient(txn, meal.id, ingredient.id) @@ -2751,7 +2743,7 @@ mod tests { .unwrap(); let remaining = db .run(move |txn| { - let ingredients = ingredients.clone(); + let ingredients = ingredients; Box::pin(async move { ingredients.ingredients_for_meal(txn, meal.id).await }) }) .await @@ -2766,7 +2758,7 @@ mod tests { let ingredients = SqliteMealIngredientRepository; let result = db .run(move |txn| { - let ingredients = ingredients.clone(); + let ingredients = ingredients; Box::pin(async move { ingredients.delete_ingredient(txn, meal.id, 9999).await }) }) .await; @@ -2781,7 +2773,7 @@ mod tests { let meal_id = meal.id; let id = db .run(move |txn| { - let list_meals = list_meals.clone(); + let list_meals = list_meals; Box::pin( async move { list_meals.add_meal(txn, list_id, Some(meal_id), name).await }, ) @@ -2806,7 +2798,7 @@ mod tests { let list_meals = SqliteListMealRepository; let meals = db .run(move |txn| { - let list_meals = list_meals.clone(); + let list_meals = list_meals; Box::pin(async move { list_meals.list_meals(txn, list.id).await }) }) .await @@ -2829,7 +2821,7 @@ mod tests { let ingredients = SqliteMealIngredientRepository; let ingredient_rows = db .run(move |txn| { - let ingredients = ingredients.clone(); + let ingredients = ingredients; Box::pin(async move { ingredients.ingredients_for_meal(txn, meal.id).await }) }) .await @@ -2845,7 +2837,7 @@ mod tests { }) .collect(); db.run(move |txn| { - let items = items.clone(); + let items = items; Box::pin(async move { items.add_items_bulk(txn, list.id, new_items).await }) }) .await @@ -2855,7 +2847,7 @@ mod tests { let list_meals = SqliteListMealRepository; let revision = db .run(move |txn| { - let list_meals = list_meals.clone(); + let list_meals = list_meals; Box::pin(async move { list_meals.remove_meal(txn, list.id, list_meal.id).await }) }) .await @@ -2864,7 +2856,7 @@ mod tests { let meals = db .run(move |txn| { - let list_meals = list_meals.clone(); + let list_meals = list_meals; Box::pin(async move { list_meals.list_meals(txn, list.id).await }) }) .await @@ -2880,7 +2872,7 @@ mod tests { let list_meals = SqliteListMealRepository; let result = db .run(move |txn| { - let list_meals = list_meals.clone(); + let list_meals = list_meals; Box::pin(async move { list_meals.remove_meal(txn, list.id, 9999).await }) }) .await; @@ -2899,7 +2891,7 @@ mod tests { let list_meals = SqliteListMealRepository; let (copied, revision) = db .run(move |txn| { - let list_meals = list_meals.clone(); + let list_meals = list_meals; Box::pin(async move { list_meals .copy_meals_to_list(txn, source.id, dest.id, &[list_meal.id]) @@ -2919,7 +2911,7 @@ mod tests { // The source meal is untouched. let source_meals = db .run(move |txn| { - let list_meals = list_meals.clone(); + let list_meals = list_meals; Box::pin(async move { list_meals.list_meals(txn, source.id).await }) }) .await @@ -2939,7 +2931,7 @@ mod tests { // becomes NULL. let meals = SqliteMealRepository; db.run(move |txn| { - let meals = meals.clone(); + let meals = meals; Box::pin(async move { meals.delete_meal(txn, meal.id).await }) }) .await @@ -2948,7 +2940,7 @@ mod tests { let list_meals = SqliteListMealRepository; let (copied, _) = db .run(move |txn| { - let list_meals = list_meals.clone(); + let list_meals = list_meals; Box::pin(async move { list_meals .copy_meals_to_list(txn, source.id, dest.id, &[list_meal.id]) @@ -2970,7 +2962,7 @@ mod tests { let list_meals = SqliteListMealRepository; let result = db .run(move |txn| { - let list_meals = list_meals.clone(); + let list_meals = list_meals; Box::pin(async move { list_meals .copy_meals_to_list(txn, source.id, dest.id, &[9999]) @@ -2991,7 +2983,7 @@ mod tests { let created = db .run(move |txn| { - let passkeys = passkeys.clone(); + let passkeys = passkeys; Box::pin(async move { passkeys .create_passkey(txn, user.id, "cred-1".into(), "{}".into(), 0) @@ -3006,7 +2998,7 @@ mod tests { let found = db .run(move |txn| { - let passkeys = passkeys.clone(); + let passkeys = passkeys; Box::pin(async move { passkeys.find_by_credential_id(txn, "cred-1".into()).await }) }) .await @@ -3016,7 +3008,7 @@ mod tests { let listed = db .run(move |txn| { - let passkeys = passkeys.clone(); + let passkeys = passkeys; Box::pin(async move { passkeys.list_for_user(txn, user.id).await }) }) .await @@ -3024,7 +3016,7 @@ mod tests { assert_eq!(listed.len(), 1); db.run(move |txn| { - let passkeys = passkeys.clone(); + let passkeys = passkeys; Box::pin(async move { passkeys.delete_passkey(txn, user.id, created.id).await }) }) .await @@ -3032,7 +3024,7 @@ mod tests { let after = db .run(move |txn| { - let passkeys = passkeys.clone(); + let passkeys = passkeys; Box::pin(async move { passkeys.list_for_user(txn, user.id).await }) }) .await @@ -3046,7 +3038,7 @@ mod tests { let user = create_user(&db, "alice@example.com").await; let passkeys = SqlitePasskeyRepository; db.run(move |txn| { - let passkeys = passkeys.clone(); + let passkeys = passkeys; Box::pin(async move { passkeys .create_passkey(txn, user.id, "cred-1".into(), "{}".into(), 0) @@ -3058,7 +3050,7 @@ mod tests { let result = db .run(move |txn| { - let passkeys = passkeys.clone(); + let passkeys = passkeys; Box::pin(async move { passkeys .create_passkey(txn, user.id, "cred-1".into(), "{}".into(), 0) @@ -3076,7 +3068,7 @@ mod tests { let passkeys = SqlitePasskeyRepository; let result = db .run(move |txn| { - let passkeys = passkeys.clone(); + let passkeys = passkeys; Box::pin(async move { passkeys.delete_passkey(txn, user.id, 9999).await }) }) .await; @@ -3093,7 +3085,7 @@ mod tests { let created = db .run(move |txn| { - let cards = cards.clone(); + let cards = cards; Box::pin(async move { cards .create_card( @@ -3116,7 +3108,7 @@ mod tests { let listed = db .run(move |txn| { - let cards = cards.clone(); + let cards = cards; Box::pin(async move { cards.list_cards(txn, user.id).await }) }) .await @@ -3125,7 +3117,7 @@ mod tests { assert_eq!(listed[0].id, created.id); db.run(move |txn| { - let cards = cards.clone(); + let cards = cards; Box::pin(async move { cards.delete_card(txn, user.id, created.id).await }) }) .await @@ -3133,7 +3125,7 @@ mod tests { let after = db .run(move |txn| { - let cards = cards.clone(); + let cards = cards; Box::pin(async move { cards.list_cards(txn, user.id).await }) }) .await @@ -3149,7 +3141,7 @@ mod tests { let cards = SqliteRewardsCardRepository; db.run(move |txn| { - let cards = cards.clone(); + let cards = cards; Box::pin(async move { cards .create_card( @@ -3167,7 +3159,7 @@ mod tests { let bobs = db .run(move |txn| { - let cards = cards.clone(); + let cards = cards; Box::pin(async move { cards.list_cards(txn, bob.id).await }) }) .await @@ -3177,7 +3169,7 @@ mod tests { // Bob cannot delete Alice's card. let result = db .run(move |txn| { - let cards = cards.clone(); + let cards = cards; Box::pin(async move { cards.delete_card(txn, bob.id, 1).await }) }) .await; @@ -3191,7 +3183,7 @@ mod tests { let cards = SqliteRewardsCardRepository; let result = db .run(move |txn| { - let cards = cards.clone(); + let cards = cards; Box::pin(async move { cards.delete_card(txn, user.id, 9999).await }) }) .await; @@ -3207,7 +3199,7 @@ mod tests { let created = db .run(move |txn| { - let cards = cards.clone(); + let cards = cards; Box::pin(async move { cards .create_card( @@ -3226,7 +3218,7 @@ mod tests { // The owner can fetch their card. let found = db .run(move |txn| { - let cards = cards.clone(); + let cards = cards; Box::pin(async move { cards.get_card(txn, alice.id, created.id).await }) }) .await @@ -3237,7 +3229,7 @@ mod tests { // Another user cannot fetch it. let not_found = db .run(move |txn| { - let cards = cards.clone(); + let cards = cards; Box::pin(async move { cards.get_card(txn, bob.id, created.id).await }) }) .await @@ -3247,7 +3239,7 @@ mod tests { // A missing id returns None. let missing = db .run(move |txn| { - let cards = cards.clone(); + let cards = cards; Box::pin(async move { cards.get_card(txn, alice.id, 9999).await }) }) .await diff --git a/src/views.rs b/src/views.rs index 128f53f..9c471df 100644 --- a/src/views.rs +++ b/src/views.rs @@ -802,116 +802,6 @@ fn render_markdown(source: &str) -> Markup { } } -#[cfg(test)] -mod tests { - use super::*; - - /// Extracts the rendered SVG width from `viewBox="0 0 "`. - fn svg_width(svg: &str) -> u32 { - let viewbox = svg - .split("viewBox=\"") - .nth(1) - .expect("expected viewBox") - .split('"') - .next() - .unwrap(); - let width = viewbox.split_whitespace().nth(2).expect("expected width"); - width.parse().expect("expected numeric width") - } - - #[test] - fn render_markdown_turns_bullets_into_list_html() { - let html = render_markdown("- one\n- two\n").into_string(); - assert!(html.contains("
    "), "expected
      , got: {html}"); - assert!(html.contains("
    • "), "expected
    • , got: {html}"); - assert!(!html.contains("* one"), "raw bullet leaked through: {html}"); - } - - #[test] - fn render_markdown_renders_emphasis() { - let html = render_markdown("**bold** and *italic*").into_string(); - assert!(html.contains(""), "expected , got: {html}"); - assert!(html.contains(""), "expected , got: {html}"); - } - - #[test] - fn format_date_renders_human_readable_date() { - // 2026-08-07T00:00:00Z in Unix seconds. - let ts = 1_786_060_800; - assert_eq!(format_date(ts), "7 Aug 2026"); - } - - #[test] - fn barcode_svg_renders_code128_svg() { - let html = barcode_svg("code128", "601123456789").into_string(); - assert!(html.contains(""), "expected closing svg, got: {html}"); - } - - #[test] - fn code128_uses_set_c_for_even_digit_numbers() { - // Set C (Ć) packs two digits per symbol, so an even-length digit-only - // number should be encoded with set C rather than set B. - assert_eq!(code128_input("601123456789"), "Ć601123456789"); - // Non-numeric data falls back to set B. - assert_eq!(code128_input("ABC123"), "ƁABC123"); - assert_eq!(code128_input(""), "Ɓ"); - } - - #[test] - fn code128_odd_digit_numbers_lead_with_set_b_then_switch_to_set_c() { - // 21-digit number: first digit in set B, then set C for the rest. - assert_eq!( - code128_input("606171584511340224537"), - "Ɓ6Ć06171584511340224537" - ); - } - - #[test] - fn code128_set_c_renders_shorter_than_set_b() { - let number = "601123456789"; - let set_c = barcode_svg("code128", number).into_string(); - // Force set B by using a non-numeric character so the digit-only - // fast path doesn't kick in. - let set_b = barcode_svg("code128", &format!("{number} ")).into_string(); - let width_c = svg_width(&set_c); - let width_b = svg_width(&set_b); - assert!( - width_c < width_b, - "expected set C ({width_c}) narrower than set B ({width_b})" - ); - } - - #[test] - fn code128_odd_digit_number_renders_shorter_than_pure_set_b() { - let number = "606171584511340224537"; - let mixed = barcode_svg("code128", number).into_string(); - // Force pure set B by appending a non-numeric character. - let set_b = barcode_svg("code128", &format!("{number} ")).into_string(); - let width_mixed = svg_width(&mixed); - let width_b = svg_width(&set_b); - assert!( - width_mixed < width_b, - "expected mixed ({width_mixed}) narrower than set B ({width_b})" - ); - } - - #[test] - fn barcode_svg_renders_code39_svg() { - let html = barcode_svg("code39", "ABC123").into_string(); - assert!(html.contains(" Markup { .generate(&encoded) .ok() }), - _ => barcoders::sym::code128::Code128::new(&code128_input(number)) + _ => barcoders::sym::code128::Code128::new(code128_input(number)) .ok() .map(|code| code.encode()) .and_then(|encoded| { @@ -1628,7 +1518,7 @@ fn code128_input(number: &str) -> String { return format!("Ɓ{number}"); } let len = number.chars().count(); - if len % 2 == 0 { + if len.is_multiple_of(2) { format!("Ć{number}") } else { let (first, rest) = number.split_at(1); @@ -1723,3 +1613,113 @@ fn initials(name: &str) -> String { .collect::() .to_uppercase() } + +#[cfg(test)] +mod tests { + use super::*; + + /// Extracts the rendered SVG width from `viewBox="0 0 "`. + fn svg_width(svg: &str) -> u32 { + let viewbox = svg + .split("viewBox=\"") + .nth(1) + .expect("expected viewBox") + .split('"') + .next() + .unwrap(); + let width = viewbox.split_whitespace().nth(2).expect("expected width"); + width.parse().expect("expected numeric width") + } + + #[test] + fn render_markdown_turns_bullets_into_list_html() { + let html = render_markdown("- one\n- two\n").into_string(); + assert!(html.contains("
        "), "expected
          , got: {html}"); + assert!(html.contains("
        • "), "expected
        • , got: {html}"); + assert!(!html.contains("* one"), "raw bullet leaked through: {html}"); + } + + #[test] + fn render_markdown_renders_emphasis() { + let html = render_markdown("**bold** and *italic*").into_string(); + assert!(html.contains(""), "expected , got: {html}"); + assert!(html.contains(""), "expected , got: {html}"); + } + + #[test] + fn format_date_renders_human_readable_date() { + // 2026-08-07T00:00:00Z in Unix seconds. + let ts = 1_786_060_800; + assert_eq!(format_date(ts), "7 Aug 2026"); + } + + #[test] + fn barcode_svg_renders_code128_svg() { + let html = barcode_svg("code128", "601123456789").into_string(); + assert!(html.contains(""), "expected closing svg, got: {html}"); + } + + #[test] + fn code128_uses_set_c_for_even_digit_numbers() { + // Set C (Ć) packs two digits per symbol, so an even-length digit-only + // number should be encoded with set C rather than set B. + assert_eq!(code128_input("601123456789"), "Ć601123456789"); + // Non-numeric data falls back to set B. + assert_eq!(code128_input("ABC123"), "ƁABC123"); + assert_eq!(code128_input(""), "Ɓ"); + } + + #[test] + fn code128_odd_digit_numbers_lead_with_set_b_then_switch_to_set_c() { + // 21-digit number: first digit in set B, then set C for the rest. + assert_eq!( + code128_input("606171584511340224537"), + "Ɓ6Ć06171584511340224537" + ); + } + + #[test] + fn code128_set_c_renders_shorter_than_set_b() { + let number = "601123456789"; + let set_c = barcode_svg("code128", number).into_string(); + // Force set B by using a non-numeric character so the digit-only + // fast path doesn't kick in. + let set_b = barcode_svg("code128", &format!("{number} ")).into_string(); + let width_c = svg_width(&set_c); + let width_b = svg_width(&set_b); + assert!( + width_c < width_b, + "expected set C ({width_c}) narrower than set B ({width_b})" + ); + } + + #[test] + fn code128_odd_digit_number_renders_shorter_than_pure_set_b() { + let number = "606171584511340224537"; + let mixed = barcode_svg("code128", number).into_string(); + // Force pure set B by appending a non-numeric character. + let set_b = barcode_svg("code128", &format!("{number} ")).into_string(); + let width_mixed = svg_width(&mixed); + let width_b = svg_width(&set_b); + assert!( + width_mixed < width_b, + "expected mixed ({width_mixed}) narrower than set B ({width_b})" + ); + } + + #[test] + fn barcode_svg_renders_code39_svg() { + let html = barcode_svg("code39", "ABC123").into_string(); + assert!(html.contains("