diff --git a/api/src/domain/ingredient/fetch_by_key.rs b/api/src/domain/ingredient/fetch_by_key.rs index 2f7eac6..20cd7a4 100644 --- a/api/src/domain/ingredient/fetch_by_key.rs +++ b/api/src/domain/ingredient/fetch_by_key.rs @@ -25,11 +25,11 @@ pub fn execute( #[cfg(test)] mod tests { use super::*; - use crate::domain::misc_types::Lang; + use crate::{domain::misc_types::Lang, repo::ingredient::InMemoryIngredientRepo}; #[test] fn should_return_ingredient() { - let repo = crate::repo::ingredient::InMemoryIngredientRepo::new(); + let repo = InMemoryIngredientRepo::new(); let res = execute(&repo, String::from("apple"), RequestOpts::default()); match res { @@ -44,7 +44,7 @@ mod tests { #[test] fn should_return_ingredient_with_choosed_lang() { - let repo = crate::repo::ingredient::InMemoryIngredientRepo::new(); + let repo = InMemoryIngredientRepo::new(); let res = execute( &repo, String::from("apple"), @@ -65,7 +65,7 @@ mod tests { #[test] fn should_return_ingredient_with_fallback_lang() { - let repo = crate::repo::ingredient::InMemoryIngredientRepo::new(); + let repo = InMemoryIngredientRepo::new(); let res = execute( &repo, String::from("orange"), @@ -86,7 +86,7 @@ mod tests { #[test] fn should_throw_not_found_error() { - let repo = crate::repo::ingredient::InMemoryIngredientRepo::new(); + let repo = InMemoryIngredientRepo::new(); let res = execute(&repo, String::from("wildberries"), RequestOpts::default()); match res { diff --git a/api/src/domain/ingredient/fetch_list.rs b/api/src/domain/ingredient/fetch_list.rs index f767208..2188e9a 100644 --- a/api/src/domain/ingredient/fetch_list.rs +++ b/api/src/domain/ingredient/fetch_list.rs @@ -15,15 +15,19 @@ pub fn execute(repo: &impl IngredientRepo, opts: RequestOpts) -> Vec { + [banana, apple, orange, salt, sugar] => { + assert_eq!(banana.key, String::from("banana")); + assert_eq!(banana.lang, Lang::Rus); + assert_eq!(banana.name, String::from("Банан")); + assert_eq!(apple.key, String::from("apple")); assert_eq!(apple.lang, Lang::Rus); assert_eq!(apple.name, String::from("Яблоко")); @@ -46,7 +50,7 @@ mod tests { #[test] fn should_return_preferred_lang_with_fallback() { - let repo = crate::repo::ingredient::InMemoryIngredientRepo::new(); + let repo = InMemoryIngredientRepo::new(); let res = execute( &repo, RequestOpts { @@ -56,7 +60,11 @@ mod tests { ); match res.as_slice() { - [apple, orange, salt, sugar] => { + [banana, apple, orange, salt, sugar] => { + assert_eq!(banana.key, String::from("banana")); + assert_eq!(banana.lang, Lang::Eng); + assert_eq!(banana.name, String::from("Banana")); + assert_eq!(apple.key, String::from("apple")); assert_eq!(apple.lang, Lang::Eng); assert_eq!(apple.name, String::from("Apple")); @@ -79,7 +87,7 @@ mod tests { #[test] fn should_return_filtered_by_keys() { - let repo = crate::repo::ingredient::InMemoryIngredientRepo::new(); + let repo = InMemoryIngredientRepo::new(); let res = execute( &repo, RequestOpts { diff --git a/api/src/domain/recipe/fetch_list.rs b/api/src/domain/recipe/fetch_list.rs index 90f528f..4600de3 100644 --- a/api/src/domain/recipe/fetch_list.rs +++ b/api/src/domain/recipe/fetch_list.rs @@ -5,3 +5,54 @@ use super::types; pub fn execute(repo: &impl RecipeRepo) -> Vec { repo.get_recipes() } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + domain::{misc_types::Lang, recipe::types::RecipeIngredientMeasure}, + repo::recipe::InMemoryRecipeRepo, + }; + + #[test] + fn should_return_all_recipes() { + let repo = InMemoryRecipeRepo::new(); + let res = execute(&repo); + + match res.as_slice() { + [salad, pizza_base] => { + assert_eq!(salad.key, String::from("fruit_salad")); + assert_eq!(salad.lang, Lang::Rus); + assert_eq!(salad.name, String::from("Фруктовый салат")); + assert_eq!( + salad.instructions, + vec![ + "Нарезать бананы кружочками", + "Нарезать яблоки и апельсины кубиками", + "Все ингредиенты перемешать", + ] + ); + + match salad.ingredients.as_slice() { + [banana, apple, orange] => { + assert_eq!(banana.ingredient.key, "banana"); + assert_eq!(banana.measure, RecipeIngredientMeasure::Gram(150)); + assert_eq!(apple.ingredient.key, "apple"); + assert_eq!(apple.measure, RecipeIngredientMeasure::Gram(150)); + assert_eq!(orange.ingredient.key, "orange"); + assert_eq!(orange.measure, RecipeIngredientMeasure::Gram(150)); + } + _ => unreachable!(), + } + + assert_eq!(pizza_base.key, String::from("thin_crispy_pizza_base")); + assert_eq!(pizza_base.lang, Lang::Rus); + assert_eq!( + pizza_base.name, + String::from("Тонкая хрустящая основа для пиццы") + ); + } + _ => unreachable!(), + } + } +} diff --git a/api/src/domain/recipe/types.rs b/api/src/domain/recipe/types.rs index 05bb566..909e300 100644 --- a/api/src/domain/recipe/types.rs +++ b/api/src/domain/recipe/types.rs @@ -2,11 +2,11 @@ use crate::domain::{ingredient::types::Ingredient, misc_types::Lang}; #[derive(Debug, Clone, Serialize)] pub struct Recipe { - key: String, - lang: Lang, - name: String, - instructions: Vec, - ingredients: Vec, + pub key: String, + pub lang: Lang, + pub name: String, + pub instructions: Vec, + pub ingredients: Vec, } impl From<(&db::data::Recipe, Lang, Vec)> for Recipe { @@ -46,12 +46,12 @@ impl From<(&db::data::Recipe, Lang, Vec)> for Recipe { #[derive(Debug, Clone, Serialize)] pub struct RecipeIngredient { #[serde(flatten)] - ingredient: Ingredient, + pub ingredient: Ingredient, #[serde(flatten)] - measure: RecipeIngredientMeasure, + pub measure: RecipeIngredientMeasure, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] #[serde(tag = "measure", content = "amount")] pub enum RecipeIngredientMeasure { #[serde(rename = "g")] diff --git a/api/src/repo/ingredient.rs b/api/src/repo/ingredient.rs index 7dab51c..f0d75fb 100644 --- a/api/src/repo/ingredient.rs +++ b/api/src/repo/ingredient.rs @@ -69,6 +69,13 @@ impl InMemoryIngredientRepo { pub fn new() -> Self { Self { ingredients: vec![ + db::data::Ingredient { + key: "banana", + translates: db::data::IngredientTranslate { + rus: "Банан", + eng: Some("Banana"), + }, + }, db::data::Ingredient { key: "apple", translates: db::data::IngredientTranslate { diff --git a/api/src/repo/recipe.rs b/api/src/repo/recipe.rs index fa39842..d7335b6 100644 --- a/api/src/repo/recipe.rs +++ b/api/src/repo/recipe.rs @@ -21,3 +21,110 @@ impl RecipeRepo for StaticRecipeRepo { .collect() } } + +#[cfg(test)] +pub struct InMemoryRecipeRepo { + recipes: Vec, +} + +#[cfg(test)] +impl InMemoryRecipeRepo { + pub fn new() -> Self { + use db::data as Db; + use Db::RecipeIngredientMeasure as DbRIM; + + Self { + recipes: vec![ + Db::Recipe { + key: "fruit_salad", + steps: 0, + ingredients: vec![ + Db::RecipeIngredient { + key: "banana", + measure: DbRIM::Gram(150), + }, + Db::RecipeIngredient { + key: "apple", + measure: DbRIM::Gram(150), + }, + Db::RecipeIngredient { + key: "orange", + measure: DbRIM::Gram(150), + }, + ], + translates: Db::RecipeTranslates { + rus: Db::RecipeTranslate { + name: "Фруктовый салат", + instructions: vec![ + "Нарезать бананы кружочками", + "Нарезать яблоки и апельсины кубиками", + "Все ингредиенты перемешать", + ], + }, + eng: None, + }, + }, + Db::Recipe { + key: "thin_crispy_pizza_base", + steps: 7, + ingredients: vec![ + Db::RecipeIngredient { + key: "salt", + measure: DbRIM::Gram(5), + }, + Db::RecipeIngredient { + key: "sugar", + measure: DbRIM::Gram(4), + }, + Db::RecipeIngredient { + key: "wheat_flour", + measure: DbRIM::Gram(500), + }, + Db::RecipeIngredient { + key: "dry_yeast", + measure: DbRIM::Gram(7), + }, + Db::RecipeIngredient { + key: "olive_oil", + measure: DbRIM::MilliLiter(25), + }, + Db::RecipeIngredient { + key: "water", + measure: DbRIM::MilliLiter(250), + }, + ], + translates: Db::RecipeTranslates { + rus: Db::RecipeTranslate { + name: "Тонкая хрустящая основа для пиццы", + instructions: vec![ + "Растворить дрожжи в воде, подогретой до температуры тела.", + "Добавить соль, сахар, оливковое масло и хорошо перемешать до однородной консистенции.", + "Добавить муку и замесить тесто. Вымешивать не менее 15 минут.", + "Разделить тесто на 3 порции, каждую завернуть в пищевую плёнку и дать настояться около 30 минут.", + "Растянуть один кусок теста до тонкого состояния и аккуратно переложить на смазанный растительным маслом противень.", + "Смазать соусом, чтобы тесто не осталось жидким и чтобы начинка не скользила по нему, и поставить в предварительно разогретую до максимальной температуры (не меньше 250 градусов) на 5-10 минут. В результате тесто хорошо пропечется и станет хрустящим.", + "Теперь на основу можно выкладывать начинку на ваш вкус и запекать до момента, когда сыр растает.", + ], + }, + eng: None, + }, + }, + ], + } + } +} + +#[cfg(test)] +impl RecipeRepo for InMemoryRecipeRepo { + fn get_recipes(&self) -> Vec { + let ings_repo = crate::repo::ingredient::InMemoryIngredientRepo::new(); + let ings = ings_repo.get_ingredients(Default::default()); + + let langs = [Lang::default()].repeat(self.recipes.len()); + self.recipes + .iter() + .zip(langs) + .map(|(rec, lang)| From::from((rec, lang, ings.clone()))) + .collect() + } +}