100 lines
4.3 KiB
Dart
100 lines
4.3 KiB
Dart
import 'package:cookit/src/bundle/bundle_service.dart';
|
|||
|
|
import 'package:cookit/src/database/database.dart';
|
||
|
|
import 'package:cookit/src/planning/day.dart';
|
||
|
|
import 'package:cookit/src/planning/plan_repository.dart';
|
||
|
|
import 'package:cookit/src/planning/plan_share_service.dart';
|
||
|
|
import 'package:cookit/src/recipes/course_repository.dart';
|
||
|
|
import 'package:cookit/src/recipes/photo_store.dart';
|
||
|
|
import 'package:cookit/src/recipes/recipe_repository.dart';
|
||
|
|
import 'package:cookit/src/recipes/unit_repository.dart';
|
||
|
|
import 'package:flutter_test/flutter_test.dart';
|
||
|
|
|
||
|
|
import '../support/fixtures.dart';
|
||
|
|
import '../support/test_database.dart';
|
||
|
|
|
||
|
|
/// One cook's collection and Week Plan.
|
||
|
|
class Phone {
|
||
|
|
Phone._(this.db, this.photos)
|
||
|
|
: recipes = RecipeRepository(db, photos),
|
||
|
|
courses = CourseRepository(db),
|
||
|
|
units = UnitRepository(db),
|
||
|
|
plan = PlanRepository(db) {
|
||
|
|
bundles = BundleService(recipes, courses, units, photos);
|
||
|
|
shares = PlanShareService(recipes, courses, units, photos, plan, bundles);
|
||
|
|
}
|
||
|
|
|
||
|
|
static Future<Phone> create() async {
|
||
|
|
final phone = Phone._(testDatabase(), await tempPhotoStore());
|
||
|
|
addTearDown(() async {
|
||
|
|
await phone.db.close();
|
||
|
|
await phone.photos.directory.delete(recursive: true);
|
||
|
|
});
|
||
|
|
return phone;
|
||
|
|
}
|
||
|
|
|
||
|
|
final AppDatabase db;
|
||
|
|
final PhotoStore photos;
|
||
|
|
final RecipeRepository recipes;
|
||
|
|
final CourseRepository courses;
|
||
|
|
final UnitRepository units;
|
||
|
|
final PlanRepository plan;
|
||
|
|
late final BundleService bundles;
|
||
|
|
late final PlanShareService shares;
|
||
|
|
|
||
|
|
Future<String> meal(String name) async => (await plan.allMeals()).firstWhere((m) => m.name == name).id;
|
||
|
|
}
|
||
|
|
|
||
|
|
void main() {
|
||
|
|
final monday = DateTime.utc(2026, 10, 19);
|
||
|
|
|
||
|
|
test('a shared week reuses known Recipes, adds new ones and its Meals, and keeps what is planned', () async {
|
||
|
|
final mine = await Phone.create();
|
||
|
|
final theirs = await Phone.create();
|
||
|
|
|
||
|
|
// Mine: three Recipes planned across the week, plus a note and a Meal they don't have.
|
||
|
|
await mine.recipes.saveRecipe(recipe(id: 'shared', name: 'Focaccia'));
|
||
|
|
await mine.recipes.saveRecipe(recipe(id: 'mine-pizza', name: 'Pizza'));
|
||
|
|
await mine.recipes.saveRecipe(recipe(id: 'new', name: 'Gulasch'));
|
||
|
|
await mine.plan.addMeal('Frühstück');
|
||
|
|
await mine.plan.addEntry(monday, await mine.meal('Abend'), recipeId: 'shared');
|
||
|
|
await mine.plan.addEntry(addDays(monday, 1), await mine.meal('Abend'), recipeId: 'mine-pizza');
|
||
|
|
await mine.plan.addEntry(addDays(monday, 2), await mine.meal('Mittag'), recipeId: 'new');
|
||
|
|
await mine.plan.addEntry(addDays(monday, 3), await mine.meal('Frühstück'), note: 'Bäcker');
|
||
|
|
await mine.plan.addEntry(addDays(monday, 8), await mine.meal('Abend'), recipeId: 'new'); // next week: not sent
|
||
|
|
|
||
|
|
// Theirs: the same Focaccia (same id), their own Pizza (same name), and a plan of their own.
|
||
|
|
await theirs.recipes.saveRecipe(recipe(id: 'shared', name: 'Focaccia'));
|
||
|
|
await theirs.recipes.saveRecipe(recipe(id: 'their-pizza', name: 'pizza '));
|
||
|
|
await theirs.plan.addEntry(monday, await theirs.meal('Mittag'), note: 'Reste');
|
||
|
|
|
||
|
|
final week = SharedWeek(await theirs.bundles.read(await mine.shares.weekFile(monday)));
|
||
|
|
final preview = await theirs.shares.preview(week);
|
||
|
|
expect((preview.entries, preview.newRecipes, preview.existingEntries), (4, 1, 1));
|
||
|
|
|
||
|
|
await theirs.shares.adopt(week);
|
||
|
|
|
||
|
|
final recipes = await theirs.recipes.allRecipes();
|
||
|
|
expect(recipes.map((r) => r.id), unorderedEquals(['shared', 'their-pizza', 'new']));
|
||
|
|
final meals = {for (final m in await theirs.plan.allMeals()) m.id: m.name};
|
||
|
|
final entries = await theirs.plan.allEntries();
|
||
|
|
expect(
|
||
|
|
[for (final e in entries) (e.day, meals[e.mealId], e.recipeId ?? e.note)],
|
||
|
|
unorderedEquals([
|
||
|
|
(monday, 'Mittag', 'Reste'),
|
||
|
|
(monday, 'Abend', 'shared'),
|
||
|
|
(addDays(monday, 1), 'Abend', 'their-pizza'),
|
||
|
|
(addDays(monday, 2), 'Mittag', 'new'),
|
||
|
|
(addDays(monday, 3), 'Frühstück', 'Bäcker'),
|
||
|
|
]),
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('only a bundle shared from the Week Plan carries a week', () async {
|
||
|
|
final mine = await Phone.create();
|
||
|
|
await mine.recipes.saveRecipe(recipe());
|
||
|
|
final contents = await mine.bundles.read(await mine.bundles.exportBundle());
|
||
|
|
expect(contents.plan, isNull);
|
||
|
|
final week = await mine.bundles.read(await mine.shares.weekFile(monday));
|
||
|
|
expect(week.plan, isNotNull);
|
||
|
|
});
|
||
|
|
}
|