From 90ef3a9bafe0927bf53320129ba17bff6fb6ee20 Mon Sep 17 00:00:00 2001 From: CHAE Date: Mon, 30 Oct 2023 19:58:06 +0900 Subject: [PATCH 1/4] =?UTF-8?q?:sparkles:=20Feat:=20FoodRepository=20?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#42)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../diareat/diareat/food/repository/FavoriteFoodRepository.java | 1 + .../com/diareat/diareat/food/repository/FoodRepository.java | 2 +- src/main/java/com/diareat/diareat/util/api/ResponseCode.java | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/diareat/diareat/food/repository/FavoriteFoodRepository.java b/src/main/java/com/diareat/diareat/food/repository/FavoriteFoodRepository.java index 549a7cb..1bd1248 100644 --- a/src/main/java/com/diareat/diareat/food/repository/FavoriteFoodRepository.java +++ b/src/main/java/com/diareat/diareat/food/repository/FavoriteFoodRepository.java @@ -7,4 +7,5 @@ public interface FavoriteFoodRepository extends JpaRepository { List findAllByUserId(Long userId); + boolean existsByFoodId(Long foodId); // 이미 즐겨찾기에 추가된 음식인지 확인하기 위함 } diff --git a/src/main/java/com/diareat/diareat/food/repository/FoodRepository.java b/src/main/java/com/diareat/diareat/food/repository/FoodRepository.java index 5cd6d90..7625379 100644 --- a/src/main/java/com/diareat/diareat/food/repository/FoodRepository.java +++ b/src/main/java/com/diareat/diareat/food/repository/FoodRepository.java @@ -8,5 +8,5 @@ public interface FoodRepository extends JpaRepository { List findAllByUserIdAndDate(Long userId, LocalDate date); //유저가 특정 날짜에 먹은 음식 반환 - List findAllByUserIdAndDateBetween(Long userId, LocalDate startDate, LocalDate endDate); //유저가 특정 기간 내에 먹은 음식 반환 + List findAllByUserIdAndDateBetween(Long userId, LocalDate startDate, LocalDate endDate); // 유저가 특정 기간 내에 먹은 음식 반환 } diff --git a/src/main/java/com/diareat/diareat/util/api/ResponseCode.java b/src/main/java/com/diareat/diareat/util/api/ResponseCode.java index 63eae5b..3185dd9 100644 --- a/src/main/java/com/diareat/diareat/util/api/ResponseCode.java +++ b/src/main/java/com/diareat/diareat/util/api/ResponseCode.java @@ -28,7 +28,7 @@ public enum ResponseCode { USER_NAME_ALREADY_EXIST(HttpStatus.CONFLICT, false, "이미 존재하는 닉네임입니다."), FOLLOWED_ALREADY(HttpStatus.CONFLICT, false, "이미 팔로우한 사용자입니다."), UNFOLLOWED_ALREADY(HttpStatus.CONFLICT, false, "이미 언팔로우한 사용자입니다."), - FOOD_ALREADY_EXIST(HttpStatus.CONFLICT, false, "이미 즐겨찾기에 존재하는 음식입니다."), + FAVORITE_ALREADY_EXIST(HttpStatus.CONFLICT, false, "이미 즐겨찾기에 존재하는 음식입니다."), // 500 Internal Server Error INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, false, "서버에 오류가 발생하였습니다."), From 8124c3be52f6e3695ea04dc3de4849f784462fe0 Mon Sep 17 00:00:00 2001 From: CHAE Date: Mon, 30 Oct 2023 19:59:10 +0900 Subject: [PATCH 2/4] =?UTF-8?q?:sparkles:=20Feat:=20FoodService=20?= =?UTF-8?q?=EC=A3=BC=EA=B0=84=20=EB=9E=AD=ED=82=B9=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#42)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../diareat/food/service/FoodService.java | 113 +++++++++++++++--- 1 file changed, 99 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/diareat/diareat/food/service/FoodService.java b/src/main/java/com/diareat/diareat/food/service/FoodService.java index d9b5a58..cadc46a 100644 --- a/src/main/java/com/diareat/diareat/food/service/FoodService.java +++ b/src/main/java/com/diareat/diareat/food/service/FoodService.java @@ -7,6 +7,8 @@ import com.diareat.diareat.food.repository.FoodRepository; import com.diareat.diareat.user.domain.BaseNutrition; import com.diareat.diareat.user.domain.User; +import com.diareat.diareat.user.dto.ResponseRankUserDto; +import com.diareat.diareat.user.repository.FollowRepository; import com.diareat.diareat.user.repository.UserRepository; import com.diareat.diareat.util.api.ResponseCode; import com.diareat.diareat.util.exception.FavoriteException; @@ -16,9 +18,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.DayOfWeek; import java.time.LocalDate; -import java.util.Comparator; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; @RequiredArgsConstructor @@ -27,7 +29,7 @@ public class FoodService { private final FoodRepository foodRepository; // 유저:음식은 1:다 private final FavoriteFoodRepository favoriteFoodRepository; // 유저:즐찾음식은 1:다 - + private final FollowRepository followRepository; private final UserRepository userRepository; // 촬영 후, 음식 정보 저장 @@ -65,9 +67,9 @@ public void deleteFood(Long foodId) { // 즐겨찾기에 음식 저장 @Transactional public Long saveFavoriteFood(CreateFavoriteFoodDto createFavoriteFoodDto) { - User user = getUserById(createFavoriteFoodDto.getUserId()); - + if (favoriteFoodRepository.existsByFoodId(createFavoriteFoodDto.getFoodId())) + throw new FavoriteException(ResponseCode.FAVORITE_ALREADY_EXIST); FavoriteFood favoriteFood = FavoriteFood.createFavoriteFood(createFavoriteFoodDto.getName(), user, createFavoriteFoodDto.getBaseNutrition()); return favoriteFoodRepository.save(favoriteFood).getId(); } @@ -169,22 +171,75 @@ public ResponseFoodRankDto getWorstFoodByWeek(Long userId) { return ResponseFoodRankDto.of(userId, worst3FoodDtoList, endDate, false); } - private User getUserById(Long userId){ + // 잔여 기능 구현 부분 + + // 유저의 구체적인 점수 현황과 Best3, Worst3 조회 + + // 유저의 일기 분석 그래프 데이터 및 식습관 totalScore 조회 + + + @Transactional(readOnly = true) + // 유저의 식습관 점수를 기반으로 한 주간 랭킹 조회 + public List getUserRankByWeek(Long userId) { + List rankUserDtos = new ArrayList<>(); + List users = followRepository.findAllByFromUser(userId); // 유저의 팔로우 유저 명단 + rankUserDtos.add(calculateUserScoreThisWeek(getUserById(userId), LocalDate.now().with(DayOfWeek.MONDAY), LocalDate.now())); + if (users.isEmpty()) { // 팔로우한 유저가 없는 경우 본인의 점수 및 정보만 반환함 + return rankUserDtos; + } + + // 팔로우한 유저들의 점수를 계산하여 rankUserDtos에 추가 + rankUserDtos.forEach(rankUserDto -> + users.forEach(user -> + rankUserDtos.add(calculateUserScoreThisWeek(user, LocalDate.now().with(DayOfWeek.MONDAY), LocalDate.now())))); + + // 식습관 총점 기준 내림차순 정렬 + rankUserDtos.sort(Comparator.comparing(ResponseRankUserDto::getTotalScore).reversed()); + return rankUserDtos; + } + + + private User getUserById(Long userId) { return userRepository.findById(userId) .orElseThrow(() -> new UserException(ResponseCode.USER_NOT_FOUND)); } - private Food getFoodById(Long foodId){ + private Food getFoodById(Long foodId) { return foodRepository.findById(foodId) .orElseThrow(() -> new FoodException(ResponseCode.FOOD_NOT_FOUND)); } - private FavoriteFood getFavoriteFoodById(Long foodId){ + private FavoriteFood getFavoriteFoodById(Long foodId) { return favoriteFoodRepository.findById(foodId) .orElseThrow(() -> new FoodException(ResponseCode.FOOD_NOT_FOUND)); } - private ResponseNutritionSumByDateDto calculateNutritionSumAndRatio(Long userId, List foodList, LocalDate checkDate, int nutritionSumType){ + private ResponseRankUserDto calculateUserScoreThisWeek(User targetUser, LocalDate startDate, LocalDate endDate) { + Map> maps = getNutritionSumByDateMap(targetUser.getId(), startDate, endDate); + double kcalScore = 0.0; + double carbohydrateScore = 0.0; + double proteinScore = 0.0; + double fatScore = 0.0; + double totalScore; + + for (LocalDate date : maps.keySet()) { + // 해당 날짜에 먹은 음식들의 영양성분 총합 계산 + int totalKcal = maps.get(date).stream().mapToInt(BaseNutrition::getKcal).sum(); + int totalCarbohydrate = maps.get(date).stream().mapToInt(BaseNutrition::getCarbohydrate).sum(); + int totalProtein = maps.get(date).stream().mapToInt(BaseNutrition::getProtein).sum(); + int totalFat = maps.get(date).stream().mapToInt(BaseNutrition::getFat).sum(); + + // 기준섭취량 대비 섭취 비율에 매핑되는 식습관 점수 계산 + proteinScore += calculateNutriRatioAndScore(totalProtein, targetUser.getBaseNutrition().getProtein(), 0); + fatScore += calculateNutriRatioAndScore(totalFat, targetUser.getBaseNutrition().getFat(), 1); + carbohydrateScore += calculateNutriRatioAndScore(totalCarbohydrate, targetUser.getBaseNutrition().getCarbohydrate(), 1); + kcalScore += calculateNutriRatioAndScore(totalKcal, targetUser.getBaseNutrition().getKcal(), 1); + } + totalScore = (kcalScore + carbohydrateScore + proteinScore + fatScore); + return ResponseRankUserDto.of(targetUser.getId(), targetUser.getName(), targetUser.getImage(), kcalScore, carbohydrateScore, proteinScore, fatScore, totalScore); + } + + private ResponseNutritionSumByDateDto calculateNutritionSumAndRatio(Long userId, List foodList, LocalDate checkDate, int nutritionSumType) { User targetUser = getUserById(userId); int totalKcal = 0; int totalCarbohydrate = 0; @@ -199,12 +254,12 @@ private ResponseNutritionSumByDateDto calculateNutritionSumAndRatio(Long userId, totalFat += targetFoodNutrition.getFat(); } - double ratioKcal = Math.round((((double) totalKcal /(double) targetUser.getBaseNutrition().getKcal())*100.0)*10.0)/10.0; - double ratioCarbohydrate = Math.round((((double) totalCarbohydrate /(double) targetUser.getBaseNutrition().getCarbohydrate())*100.0)*10.0)/10.0; - double ratioProtein = Math.round((((double) totalProtein /(double) targetUser.getBaseNutrition().getProtein())*100.0)*10.0)/10.0; - double ratioFat =Math.round((((double) totalFat /(double) targetUser.getBaseNutrition().getFat())*100.0)*10.0)/10.0; + double ratioKcal = Math.round((((double) totalKcal / (double) targetUser.getBaseNutrition().getKcal()) * 100.0) * 10.0) / 10.0; + double ratioCarbohydrate = Math.round((((double) totalCarbohydrate / (double) targetUser.getBaseNutrition().getCarbohydrate()) * 100.0) * 10.0) / 10.0; + double ratioProtein = Math.round((((double) totalProtein / (double) targetUser.getBaseNutrition().getProtein()) * 100.0) * 10.0) / 10.0; + double ratioFat = Math.round((((double) totalFat / (double) targetUser.getBaseNutrition().getFat()) * 100.0) * 10.0) / 10.0; - return ResponseNutritionSumByDateDto.of(userId, checkDate, nutritionSumType, totalKcal,totalCarbohydrate, totalProtein, totalFat, ratioKcal, ratioCarbohydrate, ratioProtein, ratioFat); + return ResponseNutritionSumByDateDto.of(userId, checkDate, nutritionSumType, totalKcal, totalCarbohydrate, totalProtein, totalFat, ratioKcal, ratioCarbohydrate, ratioProtein, ratioFat); } private void validateUser(Long userId) { @@ -222,6 +277,36 @@ private void validateFavoriteFood(Long favoriteFoodId) { throw new FavoriteException(ResponseCode.FAVORITE_NOT_FOUND); } + // 1주일동안 먹은 음식들의 영양성분 총합을 요일을 Key로 한 Map을 통해 반환 + private HashMap> getNutritionSumByDateMap(Long userId, LocalDate startDate, LocalDate endDate) { + HashMap> maps = new HashMap<>(); + List foodList = foodRepository.findAllByUserIdAndDateBetween(userId, startDate, endDate); + for (Food food : foodList) { + if (maps.containsKey(food.getDate())) { + maps.get(food.getDate()).add(food.getBaseNutrition()); + } else { + List baseNutritions = new ArrayList<>(); + baseNutritions.add(food.getBaseNutrition()); + maps.put(food.getDate(), baseNutritions); + } + } + return maps; + } + + // 영양성분 총합 대비 기준섭취량 비율을 계산하여 성분별 식습관 점수를 반환 + private double calculateNutriRatioAndScore(double total, double standard, int type) { + double ratio = Math.round(((total / standard) * 100.0) * 10.0) / 10.0; + if (type == 0) { // 단백질 + if (ratio <= 100.0) return ratio; + else if (ratio <= 150) return 100; + else return (-2 * ratio + 400 < 0) ? 0 : (-2 * ratio + 400); + } else { // 칼탄지 + double gradient = 1.11; // (9분의 10) + if (ratio <= 90.0) return ratio * gradient; + else if (ratio <= 110) return 100; + else return (-gradient * (ratio - 200) < 0) ? 0 : (-gradient * (ratio - 200)); + } + } /** * 메서드 구현 유의사항 From 8c483142959088a2117385fb56d6b96996796464 Mon Sep 17 00:00:00 2001 From: CHAE Date: Mon, 30 Oct 2023 19:59:39 +0900 Subject: [PATCH 3/4] =?UTF-8?q?:sparkles:=20Feat:=20FoodService=20?= =?UTF-8?q?=EC=9E=94=EC=97=AC=20=EA=B8=B0=EB=8A=A5=20Dto=20=EA=B5=AC?= =?UTF-8?q?=EC=B6=95=20(#42)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../diareat/food/dto/ResponseAnalysisDto.java | 25 +++++++++++++++++ .../food/dto/ResponseScoreBestWorstDto.java | 23 +++++++++++++++ .../food/dto/ResponseSimpleFoodDto.java | 28 +++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 src/main/java/com/diareat/diareat/food/dto/ResponseAnalysisDto.java create mode 100644 src/main/java/com/diareat/diareat/food/dto/ResponseScoreBestWorstDto.java create mode 100644 src/main/java/com/diareat/diareat/food/dto/ResponseSimpleFoodDto.java diff --git a/src/main/java/com/diareat/diareat/food/dto/ResponseAnalysisDto.java b/src/main/java/com/diareat/diareat/food/dto/ResponseAnalysisDto.java new file mode 100644 index 0000000..071206b --- /dev/null +++ b/src/main/java/com/diareat/diareat/food/dto/ResponseAnalysisDto.java @@ -0,0 +1,25 @@ +package com.diareat.diareat.food.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; + +@Getter +@AllArgsConstructor +public class ResponseAnalysisDto { // 그래프 + 점수에 사용되는 DTO + + private double totalScore; + private List calorieLastSevenDays; // 최근 7일간의 칼로리 (7개 과거부터 나열) + private List calorieLastFourWeek; // 최근 4주간의 칼로리 (4개 과거부터 나열) + private List carbohydrateLastSevenDays; // 최근 7일간의 탄수화물 + private List carbohydrateLastFourWeek; // 최근 4주간의 탄수화물 + private List proteinLastSevenDays; // 최근 7일간의 단백질 + private List proteinLastFourWeek; // 최근 4주간의 단백질 + private List fatLastSevenDays; // 최근 7일간의 지방 + private List fatLastFourWeek; // 최근 4주간의 지방 + + public static ResponseAnalysisDto of(double totalScore, List calorieLastSevenDays, List calorieLastFourWeek, List carbohydrateLastSevenDays, List carbohydrateLastFourWeek, List proteinLastSevenDays, List proteinLastFourWeek, List fatLastSevenDays, List fatLastFourWeek) { + return new ResponseAnalysisDto(totalScore, calorieLastSevenDays, calorieLastFourWeek, carbohydrateLastSevenDays, carbohydrateLastFourWeek, proteinLastSevenDays, proteinLastFourWeek, fatLastSevenDays, fatLastFourWeek); + } +} diff --git a/src/main/java/com/diareat/diareat/food/dto/ResponseScoreBestWorstDto.java b/src/main/java/com/diareat/diareat/food/dto/ResponseScoreBestWorstDto.java new file mode 100644 index 0000000..0e00c9d --- /dev/null +++ b/src/main/java/com/diareat/diareat/food/dto/ResponseScoreBestWorstDto.java @@ -0,0 +1,23 @@ +package com.diareat.diareat.food.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; + +@Getter +@AllArgsConstructor +public class ResponseScoreBestWorstDto { // 일기 분석 자세히보기에 사용되는 DTO + + private double calorieScore; + private double carbohydrateScore; + private double proteinScore; + private double fatScore; + private double totalScore; + private List best; + private List worst; + + public static ResponseScoreBestWorstDto of(double calorieScore, double carbohydrateScore, double proteinScore, double fatScore, double totalScore, List best, List worst) { + return new ResponseScoreBestWorstDto(calorieScore, carbohydrateScore, proteinScore, fatScore, totalScore, best, worst); + } +} diff --git a/src/main/java/com/diareat/diareat/food/dto/ResponseSimpleFoodDto.java b/src/main/java/com/diareat/diareat/food/dto/ResponseSimpleFoodDto.java new file mode 100644 index 0000000..7238afa --- /dev/null +++ b/src/main/java/com/diareat/diareat/food/dto/ResponseSimpleFoodDto.java @@ -0,0 +1,28 @@ +package com.diareat.diareat.food.dto; + +import com.diareat.diareat.food.domain.Food; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.time.LocalDate; + +@Getter +@AllArgsConstructor +public class ResponseSimpleFoodDto { // Best 3 and Worst 3에 사용될 객체 + + private String name; + private double calorie; + private double carbohydrate; + private double protein; + private double fat; + private LocalDate date; + + public static ResponseSimpleFoodDto of(String name, double calorie, double carbohydrate, double protein, double fat, LocalDate date) { + return new ResponseSimpleFoodDto(name, calorie, carbohydrate, protein, fat, date); + } + + public static ResponseSimpleFoodDto from(Food food) { + return new ResponseSimpleFoodDto(food.getName(), food.getBaseNutrition().getKcal(), food.getBaseNutrition().getCarbohydrate(), + food.getBaseNutrition().getProtein(), food.getBaseNutrition().getFat(), food.getDate()); + } +} From 113074b86416cb5cc5018c51b2cded40b1484057 Mon Sep 17 00:00:00 2001 From: CHAE Date: Tue, 31 Oct 2023 01:10:51 +0900 Subject: [PATCH 4/4] =?UTF-8?q?:white=5Fcheck=5Fmark:=20Test:=20=EB=B2=84?= =?UTF-8?q?=EA=B7=B8=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EB=9E=AD=ED=82=B9?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20(#42)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../diareat/food/service/FoodService.java | 11 +++-- .../diareat/service/FoodServiceTest.java | 46 +++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/diareat/diareat/food/service/FoodService.java b/src/main/java/com/diareat/diareat/food/service/FoodService.java index cadc46a..ea55b59 100644 --- a/src/main/java/com/diareat/diareat/food/service/FoodService.java +++ b/src/main/java/com/diareat/diareat/food/service/FoodService.java @@ -189,9 +189,10 @@ public List getUserRankByWeek(Long userId) { } // 팔로우한 유저들의 점수를 계산하여 rankUserDtos에 추가 - rankUserDtos.forEach(rankUserDto -> - users.forEach(user -> - rankUserDtos.add(calculateUserScoreThisWeek(user, LocalDate.now().with(DayOfWeek.MONDAY), LocalDate.now())))); + for (User user : users) { + ResponseRankUserDto userDto = calculateUserScoreThisWeek(user, LocalDate.now().with(DayOfWeek.MONDAY), LocalDate.now()); + rankUserDtos.add(userDto); + } // 식습관 총점 기준 내림차순 정렬 rankUserDtos.sort(Comparator.comparing(ResponseRankUserDto::getTotalScore).reversed()); @@ -297,12 +298,12 @@ private HashMap> getNutritionSumByDateMap(Long us private double calculateNutriRatioAndScore(double total, double standard, int type) { double ratio = Math.round(((total / standard) * 100.0) * 10.0) / 10.0; if (type == 0) { // 단백질 - if (ratio <= 100.0) return ratio; + if (ratio < 100.0) return ratio; else if (ratio <= 150) return 100; else return (-2 * ratio + 400 < 0) ? 0 : (-2 * ratio + 400); } else { // 칼탄지 double gradient = 1.11; // (9분의 10) - if (ratio <= 90.0) return ratio * gradient; + if (ratio < 90.0) return ratio * gradient; else if (ratio <= 110) return 100; else return (-gradient * (ratio - 200) < 0) ? 0 : (-gradient * (ratio - 200)); } diff --git a/src/test/java/com/diareat/diareat/service/FoodServiceTest.java b/src/test/java/com/diareat/diareat/service/FoodServiceTest.java index 31b9e8e..cf29add 100644 --- a/src/test/java/com/diareat/diareat/service/FoodServiceTest.java +++ b/src/test/java/com/diareat/diareat/service/FoodServiceTest.java @@ -8,6 +8,8 @@ import com.diareat.diareat.food.service.FoodService; import com.diareat.diareat.user.domain.BaseNutrition; import com.diareat.diareat.user.domain.User; +import com.diareat.diareat.user.dto.ResponseRankUserDto; +import com.diareat.diareat.user.repository.FollowRepository; import com.diareat.diareat.user.repository.UserRepository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -23,6 +25,7 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -43,6 +46,9 @@ class FoodServiceTest { @Mock UserRepository userRepository; + @Mock + FollowRepository followRepository; + @DisplayName("음식 정보 저장") @Test void testSaveAndGetFood() { // 음식 정보 저장 및 해당 날짜 음식 리스트 불러오기 @@ -309,4 +315,44 @@ void getWorst3FoodsTest() { assertEquals("Food4", top3Foods.get(1).getName()); assertEquals("Food5", top3Foods.get(2).getName()); } + + @Test + void getUserRankByWeek() { + // given + User user1 = User.createUser("testUser1", "testImage","testPassword", 180, 80, 0, 18, BaseNutrition.createNutrition(1000,100,100,100)); + User user2 = User.createUser("testUser2", "testImage","testPassword", 180, 80, 0, 18, BaseNutrition.createNutrition(1000,100,100,100)); + user1.setId(1L); + user2.setId(2L); + + Food food1 = Food.createFood( "Food1", user1, BaseNutrition.createNutrition(1000, 100 ,100, 100)); + Food food2 = Food.createFood( "Food2", user2, BaseNutrition.createNutrition(2000, 110 ,50, 90)); + + given(userRepository.findById(user1.getId())).willReturn(Optional.of(user1)); + given(followRepository.findAllByFromUser(user1.getId())).willReturn(List.of(user2)); + given(foodRepository.findAllByUserIdAndDateBetween(eq(1L), any(LocalDate.class), any(LocalDate.class))).willReturn(List.of(food1)); + given(foodRepository.findAllByUserIdAndDateBetween(eq(2L), any(LocalDate.class), any(LocalDate.class))).willReturn(List.of(food2)); + + // when + List response = foodService.getUserRankByWeek(user1.getId()); + + // then + assertEquals(2, response.size()); + assertEquals("testUser1", response.get(0).getName()); + assertEquals("testUser2", response.get(1).getName()); + assertEquals(100, response.get(0).getCalorieScore()); + assertEquals(100, response.get(0).getCarbohydrateScore()); + assertEquals(100, response.get(0).getProteinScore()); + assertEquals(100, response.get(0).getFatScore()); + assertEquals(400, response.get(0).getTotalScore()); + + assertEquals(0, response.get(1).getCalorieScore()); + assertEquals(100, response.get(1).getCarbohydrateScore()); + assertEquals(50, response.get(1).getProteinScore()); + assertEquals(100, response.get(1).getFatScore()); + assertEquals(250, response.get(1).getTotalScore()); + verify(userRepository, times(1)).findById(user1.getId()); + verify(followRepository, times(1)).findAllByFromUser(user1.getId()); + verify(foodRepository, times(1)).findAllByUserIdAndDateBetween(eq(1L), any(LocalDate.class), any(LocalDate.class)); + verify(foodRepository, times(1)).findAllByUserIdAndDateBetween(eq(2L), any(LocalDate.class), any(LocalDate.class)); + } }