You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
226 lines
6.8 KiB
226 lines
6.8 KiB
import 'dart:io';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:path/path.dart' as path;
|
|
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
|
import '../../../lib/data/local/local_storage_service.dart';
|
|
import '../../../lib/data/recipes/recipe_service.dart';
|
|
import '../../../lib/data/recipes/models/recipe_model.dart';
|
|
|
|
void main() {
|
|
// Initialize Flutter bindings for path_provider to work in tests
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
// Initialize FFI for testing
|
|
setUpAll(() {
|
|
sqfliteFfiInit();
|
|
databaseFactory = databaseFactoryFfi;
|
|
});
|
|
|
|
group('RecipeService', () {
|
|
late LocalStorageService localStorageService;
|
|
late RecipeService recipeService;
|
|
late String testDbPath;
|
|
|
|
setUp(() async {
|
|
// Create a temporary directory for test database
|
|
final tempDir = await Directory.systemTemp.createTemp('recipe_test_');
|
|
testDbPath = path.join(tempDir.path, 'test_recipes.db');
|
|
final localStorageDbPath = path.join(tempDir.path, 'test_local_storage.db');
|
|
final cacheDir = Directory(path.join(tempDir.path, 'cache'));
|
|
|
|
localStorageService = LocalStorageService(
|
|
testDbPath: localStorageDbPath,
|
|
testCacheDir: cacheDir,
|
|
);
|
|
await localStorageService.initialize(
|
|
sessionDbPath: localStorageDbPath,
|
|
sessionCacheDir: cacheDir,
|
|
);
|
|
|
|
recipeService = RecipeService(
|
|
localStorage: localStorageService,
|
|
testDbPath: testDbPath,
|
|
);
|
|
await recipeService.initialize(sessionDbPath: testDbPath);
|
|
});
|
|
|
|
tearDown(() async {
|
|
// Clean up test database
|
|
try {
|
|
final dbFile = File(testDbPath);
|
|
if (await dbFile.exists()) {
|
|
await dbFile.delete();
|
|
}
|
|
} catch (e) {
|
|
// Ignore cleanup errors
|
|
}
|
|
});
|
|
|
|
test('creates a recipe successfully', () async {
|
|
final recipe = RecipeModel(
|
|
id: 'test-recipe-1',
|
|
title: 'Test Recipe',
|
|
description: 'A test recipe',
|
|
tags: ['test', 'recipe'],
|
|
rating: 4,
|
|
isFavourite: true,
|
|
imageUrls: ['https://example.com/image.jpg'],
|
|
);
|
|
|
|
final created = await recipeService.createRecipe(recipe);
|
|
|
|
expect(created.id, equals(recipe.id));
|
|
expect(created.title, equals(recipe.title));
|
|
expect(created.description, equals(recipe.description));
|
|
expect(created.tags, equals(recipe.tags));
|
|
expect(created.rating, equals(recipe.rating));
|
|
expect(created.isFavourite, equals(recipe.isFavourite));
|
|
expect(created.imageUrls, equals(recipe.imageUrls));
|
|
expect(created.createdAt, greaterThan(0));
|
|
expect(created.updatedAt, greaterThan(0));
|
|
});
|
|
|
|
test('gets a recipe by ID', () async {
|
|
final recipe = RecipeModel(
|
|
id: 'test-recipe-2',
|
|
title: 'Test Recipe 2',
|
|
tags: ['test'],
|
|
);
|
|
|
|
await recipeService.createRecipe(recipe);
|
|
final retrieved = await recipeService.getRecipe('test-recipe-2');
|
|
|
|
expect(retrieved, isNotNull);
|
|
expect(retrieved!.id, equals(recipe.id));
|
|
expect(retrieved.title, equals(recipe.title));
|
|
});
|
|
|
|
test('returns null for non-existent recipe', () async {
|
|
final retrieved = await recipeService.getRecipe('non-existent');
|
|
expect(retrieved, isNull);
|
|
});
|
|
|
|
test('updates a recipe successfully', () async {
|
|
final recipe = RecipeModel(
|
|
id: 'test-recipe-3',
|
|
title: 'Original Title',
|
|
tags: ['original'],
|
|
);
|
|
|
|
await recipeService.createRecipe(recipe);
|
|
|
|
final updated = recipe.copyWith(
|
|
title: 'Updated Title',
|
|
tags: ['updated'],
|
|
rating: 5,
|
|
);
|
|
|
|
final result = await recipeService.updateRecipe(updated);
|
|
|
|
expect(result.title, equals('Updated Title'));
|
|
expect(result.tags, equals(['updated']));
|
|
expect(result.rating, equals(5));
|
|
expect(result.updatedAt, greaterThan(recipe.updatedAt));
|
|
});
|
|
|
|
test('deletes a recipe (marks as deleted)', () async {
|
|
final recipe = RecipeModel(
|
|
id: 'test-recipe-4',
|
|
title: 'Recipe to Delete',
|
|
tags: ['delete'],
|
|
);
|
|
|
|
await recipeService.createRecipe(recipe);
|
|
await recipeService.deleteRecipe('test-recipe-4');
|
|
|
|
// Recipe should not be found (soft delete)
|
|
final retrieved = await recipeService.getRecipe('test-recipe-4');
|
|
expect(retrieved, isNull);
|
|
|
|
// But should exist when including deleted
|
|
final allRecipes = await recipeService.getAllRecipes(includeDeleted: true);
|
|
final deletedRecipe = allRecipes.firstWhere((r) => r.id == 'test-recipe-4');
|
|
expect(deletedRecipe.isDeleted, isTrue);
|
|
});
|
|
|
|
test('gets all recipes', () async {
|
|
await recipeService.createRecipe(RecipeModel(
|
|
id: 'recipe-1',
|
|
title: 'Recipe 1',
|
|
tags: ['tag1'],
|
|
));
|
|
await recipeService.createRecipe(RecipeModel(
|
|
id: 'recipe-2',
|
|
title: 'Recipe 2',
|
|
tags: ['tag2'],
|
|
));
|
|
|
|
final allRecipes = await recipeService.getAllRecipes();
|
|
|
|
expect(allRecipes.length, equals(2));
|
|
expect(allRecipes.map((r) => r.id), containsAll(['recipe-1', 'recipe-2']));
|
|
});
|
|
|
|
test('gets recipes by tag', () async {
|
|
await recipeService.createRecipe(RecipeModel(
|
|
id: 'recipe-tag1',
|
|
title: 'Recipe with Tag1',
|
|
tags: ['tag1', 'common'],
|
|
));
|
|
await recipeService.createRecipe(RecipeModel(
|
|
id: 'recipe-tag2',
|
|
title: 'Recipe with Tag2',
|
|
tags: ['tag2', 'common'],
|
|
));
|
|
|
|
final tag1Recipes = await recipeService.getRecipesByTag('tag1');
|
|
expect(tag1Recipes.length, equals(1));
|
|
expect(tag1Recipes.first.id, equals('recipe-tag1'));
|
|
|
|
final commonRecipes = await recipeService.getRecipesByTag('common');
|
|
expect(commonRecipes.length, equals(2));
|
|
});
|
|
|
|
test('gets favourite recipes', () async {
|
|
await recipeService.createRecipe(RecipeModel(
|
|
id: 'favourite-1',
|
|
title: 'Favourite Recipe 1',
|
|
tags: ['favourite'],
|
|
isFavourite: true,
|
|
));
|
|
await recipeService.createRecipe(RecipeModel(
|
|
id: 'not-favourite',
|
|
title: 'Not Favourite',
|
|
tags: ['normal'],
|
|
isFavourite: false,
|
|
));
|
|
|
|
final favourites = await recipeService.getFavouriteRecipes();
|
|
|
|
expect(favourites.length, equals(1));
|
|
expect(favourites.first.id, equals('favourite-1'));
|
|
});
|
|
|
|
test('throws exception when updating non-existent recipe', () async {
|
|
final recipe = RecipeModel(
|
|
id: 'non-existent',
|
|
title: 'Non Existent',
|
|
tags: [],
|
|
);
|
|
|
|
expect(
|
|
() => recipeService.updateRecipe(recipe),
|
|
throwsA(isA<Exception>()),
|
|
);
|
|
});
|
|
|
|
test('throws exception when deleting non-existent recipe', () async {
|
|
expect(
|
|
() => recipeService.deleteRecipe('non-existent'),
|
|
throwsA(isA<Exception>()),
|
|
);
|
|
});
|
|
});
|
|
}
|
|
|