import 'package:dio/dio.dart'; import 'package:eatvio_app/features/chat/repositories/chat_repository.dart'; import 'package:eatvio_app/features/diary/entities/diary_future_diet_day_entity.dart'; import 'package:eatvio_app/features/diary/models/diary_day_model.dart'; import 'package:eatvio_app/features/diary/models/nutrition_model.dart'; import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart'; import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart'; import 'package:eatvio_app/features/diary/repositories/diary_repository.dart'; import 'package:eatvio_app/features/diets/repositories/diet_repository.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/features/glossary/models/glossary_model.dart'; import 'package:eatvio_app/features/glossary/repositories/glossary_repository.dart'; import 'package:eatvio_app/features/profile/repositories/profile_repository.dart'; import 'package:eatvio_app/features/settings/models/profile_settings_model.dart'; import 'package:eatvio_app/features/settings/repositories/service_repository.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'diary_cubit_test.mocks.dart'; @GenerateNiceMocks([ MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), ]) void main() { group('DiaryCubit', () { DiaryCubit? diaryCubit; late MockDiaryRepository mockDiaryRepository; late MockGlossaryRepository mockGlossaryRepository; late MockProfileRepository mockProfileRepository; late MockDietRepository mockDietRepository; late MockChatRepository mockChatRepository; late MockSettingsRepository mockSettingsRepository; const testDiaryDay = DiaryDayModel( id: 1, date: '2024-01-15', closed: 0, comment: '', typeOfDiary: TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: false, diaryState: null), meals: [], chosenPlanId: null, dayOfChosenDiet: null, diet: null, ); const testNutrition = NutritionDataModel( dailyNutritionIntake: NutritionModel(energy: 2000.0, proteins: 150.0, fats: 80.0, carbohydrates: 250.0), dailyNutritionRecommendation: NutritionModel(energy: 2200.0, proteins: 160.0, fats: 90.0, carbohydrates: 270.0), ); setUp(() { mockDiaryRepository = MockDiaryRepository(); mockGlossaryRepository = MockGlossaryRepository(); mockProfileRepository = MockProfileRepository(); mockDietRepository = MockDietRepository(); mockChatRepository = MockChatRepository(); mockSettingsRepository = MockSettingsRepository(); }); tearDown(() async { if (diaryCubit != null && !diaryCubit!.isClosed) { await Future.delayed(const Duration(milliseconds: 100)); diaryCubit!.close(); diaryCubit = null; } }); test('начальное состояние - loading', () { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); expect(diaryCubit!.state, const DiaryState.loading()); }); test('setSelectedDay - успешно меняет выбранный день', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); final result = await diaryCubit!.setSelectedDay(DateTime(2024, 1, 15)); expect(result, true); await Future.delayed(const Duration(milliseconds: 100)); expect(diaryCubit!.state, isA()); }); test('fetchDiaryV2 - загружает дневник по ID', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when(mockDiaryRepository.getDiaryDay(any)).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); final result = await diaryCubit!.fetchDiaryV2(needLoading: true, diaryId: 1); expect(result, true); await Future.delayed(const Duration(milliseconds: 100)); expect(diaryCubit!.state, isA()); }); test('fetchDiaryV2 - обрабатывает ошибку 422 при создании дня', () async { when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenThrow( DioException( requestOptions: RequestOptions(path: ''), response: Response(requestOptions: RequestOptions(path: ''), statusCode: 422), ), ); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); final result = await diaryCubit!.fetchDiaryV2(needLoading: true); expect(result, true); await Future.delayed(const Duration(milliseconds: 100)); expect(diaryCubit!.state, isA()); }); test('setSelectedMeal - меняет выбранный прием пищи', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.fetchDiaryV2(needLoading: true); await Future.delayed(const Duration(milliseconds: 100)); diaryCubit!.setSelectedMeal(2); expect(diaryCubit!.selectedMeal, 2); expect(diaryCubit!.state, isA()); }); test('setDiaryForDietOnly - устанавливает дневник только для диеты', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); const diet = Diet( id: 1, slug: 'test-diet', name: 'Test Diet', image: '', duration: 7, state: DietState.active, type: DietType(), details: '', dailySchedule: { 1: { 1: {1: DailySchedule(name: 'Яблоко', portion: Portion.grams, quantity: 1)}, }, }, author: Author(authorSlug: 'test', authorName: 'Test', authorProfileIcon: '', authorIsMe: false), totalLikes: 0, totalViews: 0, totalComments: 0, wasLikedByMe: false, isFavorite: false, dailyNutrition: [], ); when(mockDietRepository.getDiet(1)).thenAnswer((_) async => diet); final result = await diaryCubit!.setDiaryForDietOnly( const DiaryFutureDietDayEntity( date: '2024-01-15', typeOfDiary: TypeOfDiaryModel(hasChosenDiet: true, hasChosenPlan: false, diaryState: null), meals: [], dayOfChosenDiet: 1, diet: DiaryDietModel(id: 1, duration: 7, name: 'Test Diet'), ), ); expect(result, true); expect(diaryCubit!.state, isA()); }); test('setDiaryForDietOnly - возвращает false если нет выбранной диеты', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); final result = await diaryCubit!.setDiaryForDietOnly( const DiaryFutureDietDayEntity( date: '2024-01-15', typeOfDiary: TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: false, diaryState: null), meals: [], dayOfChosenDiet: null, diet: null, ), ); expect(result, false); }); test('finishDiaryDay - завершает день дневника', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when( mockDiaryRepository.finishDiaryDay(diaryId: anyNamed('diaryId'), wakeUp: anyNamed('wakeUp'), retire: anyNamed('retire'), comment: anyNamed('comment')), ).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.fetchDiaryV2(needLoading: true); await Future.delayed(const Duration(milliseconds: 100)); await diaryCubit!.finishDiaryDay(diaryId: 1, wakeUp: '07:00', retire: '23:00'); await Future.delayed(const Duration(milliseconds: 100)); }); test('addProductToMeal - добавляет продукт в прием пищи', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when( mockDiaryRepository.addPortionToMeal( diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), productName: anyNamed('productName'), portion: anyNamed('portion'), quantity: anyNamed('quantity'), productNutritionalValueId: anyNamed('productNutritionalValueId'), ), ).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.fetchDiaryV2(needLoading: true); await Future.delayed(const Duration(milliseconds: 100)); await diaryCubit!.addProductToMeal(diaryId: 1, mealId: 1, productName: 'Яблоко', portion: '100г', quantity: 2); await Future.delayed(const Duration(milliseconds: 100)); }); test('markEaten - отмечает продукт как съеденный', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when( mockDiaryRepository.markEaten(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), portionId: anyNamed('portionId')), ).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.fetchDiaryV2(needLoading: true); await Future.delayed(const Duration(milliseconds: 100)); await diaryCubit!.markEaten(diaryId: 1, mealId: 1, portionId: 5); await Future.delayed(const Duration(milliseconds: 100)); }); test('getGlossaryListByQuery - получает список глоссариев по запросу', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when(mockGlossaryRepository.getGlossaryListByQuery(any)).thenAnswer( (_) async => [ const GlossaryModel( id: 1, name: 'Яблоко', grInPortion: 100, energyOn100Gr: 52.0, proteinsOn100Gr: 0.3, fatsOn100Gr: 0.2, carbohydratesOn100Gr: 14.0, energyOnPortion: 52.0, proteinsOnPortion: 0.3, fatsOnPortion: 0.2, carbohydratesOnPortion: 14.0, ), ], ); final result = await diaryCubit!.getGlossaryListByQuery('яблоко'); expect(result, isA>()); expect(result.length, 1); expect(result.first.name, 'Яблоко'); }); test('fillSatiety - заполняет сытость', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when( mockDiaryRepository.fillSatiety(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), satiety: anyNamed('satiety')), ).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.fetchDiaryV2(needLoading: true); await Future.delayed(const Duration(milliseconds: 100)); await diaryCubit!.fillSatiety(diaryId: 1, satiety: 5); await Future.delayed(const Duration(milliseconds: 100)); }); test('fillMood - заполняет настроение', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when( mockDiaryRepository.fillMood(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), mood: anyNamed('mood')), ).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.fetchDiaryV2(needLoading: true); await Future.delayed(const Duration(milliseconds: 100)); await diaryCubit!.fillMood(diaryId: 1, mood: 4); await Future.delayed(const Duration(milliseconds: 100)); }); test('fillComment - заполняет комментарий', () { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); diaryCubit!.fillComment('Хороший день'); expect(diaryCubit!.comment, 'Хороший день'); }); test('updateCurrentDiary - обновляет текущий дневник', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.updateCurrentDiary(); await Future.delayed(const Duration(milliseconds: 100)); verify(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).called(1); }); test('updateCurrentDiary - обрабатывает ошибку', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenThrow(Exception('Ошибка')); await diaryCubit!.updateCurrentDiary(); await Future.delayed(const Duration(milliseconds: 100)); }); test('getNutrition - получает данные о питании', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); final result = await diaryCubit!.getNutrition(1); expect(result, testNutrition); verify(mockDiaryRepository.getNutritionData(1)).called(1); }); test('updateProductInMeal - обновляет продукт в приеме пищи', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when( mockDiaryRepository.updateProductInMeal( diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), portionId: anyNamed('portionId'), productName: anyNamed('productName'), portion: anyNamed('portion'), quantity: anyNamed('quantity'), productNutritionalValueId: anyNamed('productNutritionalValueId'), portionState: anyNamed('portionState'), ), ).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.fetchDiaryV2(needLoading: true); await Future.delayed(const Duration(milliseconds: 100)); await diaryCubit!.updateProductInMeal( diaryId: 1, mealId: 1, portionId: 5, productName: 'Яблоко', portion: '150г', quantity: 3, portionState: PortionState.eaten, ); await Future.delayed(const Duration(milliseconds: 100)); verify( mockDiaryRepository.updateProductInMeal( diaryId: 1, mealId: 1, portionId: 5, productName: 'Яблоко', portion: '150г', quantity: 3, productNutritionalValueId: anyNamed('productNutritionalValueId'), portionState: PortionState.eaten, ), ).called(1); }); test('unmarkEaten - снимает отметку о съеденном', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when( mockDiaryRepository.unmarkEaten(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), portionId: anyNamed('portionId')), ).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.fetchDiaryV2(needLoading: true); await Future.delayed(const Duration(milliseconds: 100)); await diaryCubit!.unmarkEaten(diaryId: 1, mealId: 1, portionId: 5); await Future.delayed(const Duration(milliseconds: 100)); verify(mockDiaryRepository.unmarkEaten(diaryId: 1, mealId: 1, portionId: 5)).called(1); }); test('restore - восстанавливает продукт', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when( mockDiaryRepository.restore(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), portionId: anyNamed('portionId')), ).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.fetchDiaryV2(needLoading: true); await Future.delayed(const Duration(milliseconds: 100)); await diaryCubit!.restore(diaryId: 1, mealId: 1, portionId: 5); await Future.delayed(const Duration(milliseconds: 100)); verify(mockDiaryRepository.restore(diaryId: 1, mealId: 1, portionId: 5)).called(1); }); test('deleteProductFromMeal - удаляет продукт из приема пищи', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when( mockDiaryRepository.deleteProductFromMeal(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), portionId: anyNamed('portionId')), ).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.fetchDiaryV2(needLoading: true); await Future.delayed(const Duration(milliseconds: 100)); await diaryCubit!.deleteProductFromMeal(diaryId: 1, mealId: 1, portionId: 5); await Future.delayed(const Duration(milliseconds: 100)); verify(mockDiaryRepository.deleteProductFromMeal(diaryId: 1, mealId: 1, portionId: 5)).called(1); }); test('sendProductToModeration - отправляет продукт на модерацию', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); const moderationModel = GlossaryModerationModel( glossary: GlossaryModel( id: 1, name: 'Новый продукт', grInPortion: 100, energyOn100Gr: 100.0, proteinsOn100Gr: 10.0, fatsOn100Gr: 5.0, carbohydratesOn100Gr: 15.0, energyOnPortion: 100.0, proteinsOnPortion: 10.0, fatsOnPortion: 5.0, carbohydratesOnPortion: 15.0, ), ); when( mockDiaryRepository.sendProductToModeration( name: anyNamed('name'), energy: anyNamed('energy'), proteins: anyNamed('proteins'), fats: anyNamed('fats'), carbohydrates: anyNamed('carbohydrates'), ), ).thenAnswer((_) async => moderationModel); final result = await diaryCubit!.sendProductToModeration(name: 'Новый продукт', energy: 100.0, proteins: 10.0, fats: 5.0, carbohydrates: 15.0); expect(result, moderationModel); verify(mockDiaryRepository.sendProductToModeration(name: 'Новый продукт', energy: 100.0, proteins: 10.0, fats: 5.0, carbohydrates: 15.0)).called(1); }); test('sendProductToModeration - возвращает null при ошибке', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when( mockDiaryRepository.sendProductToModeration( name: anyNamed('name'), energy: anyNamed('energy'), proteins: anyNamed('proteins'), fats: anyNamed('fats'), carbohydrates: anyNamed('carbohydrates'), ), ).thenThrow(Exception('Ошибка')); final result = await diaryCubit!.sendProductToModeration(name: 'Новый продукт', energy: 100.0, proteins: 10.0, fats: 5.0, carbohydrates: 15.0); expect(result, isNull); }); test('fillTime - заполняет время приема пищи', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when( mockDiaryRepository.fillTime(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), time: anyNamed('time')), ).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.fetchDiaryV2(needLoading: true); await Future.delayed(const Duration(milliseconds: 100)); await diaryCubit!.fillTime(diaryId: 1, time: '12:00'); await Future.delayed(const Duration(milliseconds: 100)); verify(mockDiaryRepository.fillTime(diaryId: 1, mealId: 1, time: '12:00')).called(1); }); test('fillWakeup - заполняет время пробуждения', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when(mockDiaryRepository.fillWakeup(diaryId: anyNamed('diaryId'), time: anyNamed('time'))).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.fetchDiaryV2(needLoading: true); await Future.delayed(const Duration(milliseconds: 100)); await diaryCubit!.fillWakeup(diaryId: 1, time: '07:00'); await Future.delayed(const Duration(milliseconds: 100)); verify(mockDiaryRepository.fillWakeup(diaryId: 1, time: '07:00')).called(1); }); test('fillRetire - заполняет время отхода ко сну', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when(mockDiaryRepository.fillRetire(diaryId: anyNamed('diaryId'), time: anyNamed('time'))).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.fetchDiaryV2(needLoading: true); await Future.delayed(const Duration(milliseconds: 100)); await diaryCubit!.fillRetire(diaryId: 1, time: '23:00'); await Future.delayed(const Duration(milliseconds: 100)); verify(mockDiaryRepository.fillRetire(diaryId: 1, time: '23:00')).called(1); }); test('getDiary - создает новый день дневника', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); final result = await diaryCubit!.getDiary(); expect(result, isNotNull); verify(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).called(1); verify(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).called(1); }); test('getDiary - обрабатывает ошибку 422 и получает существующий день', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenThrow( DioException( requestOptions: RequestOptions(path: ''), response: Response(requestOptions: RequestOptions(path: ''), statusCode: 422), ), ); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); final result = await diaryCubit!.getDiary(); expect(result, isNotNull); verify(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).called(1); verify(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).called(1); }); test('getDiary - возвращает null при другой ошибке', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenThrow( DioException( requestOptions: RequestOptions(path: ''), response: Response(requestOptions: RequestOptions(path: ''), statusCode: 500), ), ); final result = await diaryCubit!.getDiary(); expect(result, isNull); }); // Тест для fetchDiaryV2 когда diaryEntity == null пропущен, // так как toEntity() возвращает null только в специфических случаях, // которые сложно воспроизвести в unit-тестах test('fetchDiaryV2 - обрабатывает случай когда diaryDay == null', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenThrow( DioException( requestOptions: RequestOptions(path: ''), response: Response(requestOptions: RequestOptions(path: ''), statusCode: 500), ), ); final result = await diaryCubit!.fetchDiaryV2(needLoading: false); expect(result, true); expect(diaryCubit!.state, isA()); }); // Тест для uploadPhotos пропущен, так как требует реального изображения для ImageCompressUtility test('deletePhoto - удаляет фотографию', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); const photo = DiaryPhotoModel(id: 1, originalName: 'test.jpg', path: 'path/to/test.jpg', size: 100); when( mockDiaryRepository.deletePhoto(photo: anyNamed('photo'), diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId')), ).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay); when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition); when(mockSettingsRepository.getProfileSettings()).thenAnswer( (_) async => const ProfileSettingsModel( isMoodFillable: true, isBedtimeFillable: true, isPublicProfile: true, newUpdatesNotifications: null, diaryReminderNotifications: null, ), ); await diaryCubit!.fetchDiaryV2(needLoading: true); await Future.delayed(const Duration(milliseconds: 100)); await diaryCubit!.deletePhoto(photo: photo, diaryId: 1); await Future.delayed(const Duration(milliseconds: 100)); verify(mockDiaryRepository.deletePhoto(photo: photo, diaryId: 1, mealId: 1)).called(1); }); test('setSelectedDay - возвращает true даже если getDiary возвращает null', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenThrow( DioException( requestOptions: RequestOptions(path: ''), response: Response(requestOptions: RequestOptions(path: ''), statusCode: 500), ), ); final result = await diaryCubit!.setSelectedDay(DateTime(2024, 1, 20)); // fetchDiaryV2 возвращает true когда getDiary() == null, так как эмитит состояние ошибки expect(result, true); expect(diaryCubit!.state, isA()); }); test('fetchDiaryV2 - обрабатывает случай когда diaryEntity == null и нет диеты', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); // toEntity() возвращает null когда id == null const diaryDayWithoutEntity = DiaryDayModel( id: null, date: '2024-01-15', closed: 0, comment: '', typeOfDiary: TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: false, diaryState: null), meals: [], chosenPlanId: null, dayOfChosenDiet: null, diet: null, ); when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => diaryDayWithoutEntity); final result = await diaryCubit!.fetchDiaryV2(needLoading: false); // Если diaryEntity == null (id == null) и нет диеты, fetchDiaryV2 возвращает false // и эмитит предыдущее состояние (loading) expect(result, false); expect(diaryCubit!.state, const DiaryState.loading()); }); test('fetchDiaryV2 - обрабатывает случай когда diaryEntity == null но есть диета', () async { diaryCubit = DiaryCubit( diaryRepository: mockDiaryRepository, glossaryRepository: mockGlossaryRepository, profileRepository: mockProfileRepository, dietRepository: mockDietRepository, chatRepository: mockChatRepository, settingsRepository: mockSettingsRepository, ); // id должен быть null, чтобы toEntity() вернул null и код пошел по ветке setDiaryForDietOnly const diaryDayWithDiet = DiaryDayModel( id: null, date: '2024-01-15', closed: 0, comment: '', typeOfDiary: TypeOfDiaryModel(hasChosenDiet: true, hasChosenPlan: false, diaryState: null), meals: [], chosenPlanId: null, dayOfChosenDiet: 1, diet: DiaryDietModel(id: 1, duration: 7, name: 'Test Diet'), ); when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenAnswer((_) async => Future.value()); when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => diaryDayWithDiet); when(mockDietRepository.getDiet(1)).thenAnswer( (_) async => const Diet( id: 1, slug: 'test-diet', name: 'Test Diet', image: '', duration: 7, state: DietState.active, type: DietType(), details: '', dailySchedule: { 1: { 1: {1: DailySchedule(name: 'Яблоко', portion: Portion.grams, quantity: 1)}, }, }, author: Author(authorSlug: 'test', authorName: 'Test', authorProfileIcon: '', authorIsMe: false), totalLikes: 0, totalViews: 0, totalComments: 0, wasLikedByMe: false, isFavorite: false, dailyNutrition: [], ), ); final result = await diaryCubit!.fetchDiaryV2(needLoading: false); await Future.delayed(const Duration(milliseconds: 100)); expect(result, true); // setDiaryForDietOnly сначала эмитит loading, затем loadedTomorrowWithDiet expect(diaryCubit!.state, isA()); }); }); }