diff --git a/backend/src/main/java/reviewme/DatabaseInitializer.java b/backend/src/main/java/reviewme/DatabaseInitializer.java index 71c18843b..08f920553 100644 --- a/backend/src/main/java/reviewme/DatabaseInitializer.java +++ b/backend/src/main/java/reviewme/DatabaseInitializer.java @@ -53,10 +53,10 @@ public void setup() { long growthOptionId = optionItemRepository.save(new OptionItem("๐ŸŒฑ์„ฑ์žฅ ๋งˆ์ธ๋“œ์…‹ (์˜ˆ: ์ƒˆ๋กœ์šด ๋ถ„์•ผ๋‚˜ ์ž˜ ๋ชจ๋ฅด๋Š” ๋ถ„์•ผ์— ๋„์ „ํ•˜๋Š” ๋งˆ์Œ, ๊พธ์ค€ํ•œ ๋…ธ๋ ฅ์œผ๋กœ ํ”„๋กœ์ ํŠธ ์ด์ „๋ณด๋‹ค ์„ฑ์žฅํ•˜๋Š” ๋ชจ์Šต)",categoryOptionGroupId,5, OptionType.CATEGORY )).getId(); // ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜ ๋Šฅ๋ ฅ ์„น์…˜ - long checkBoxCommunicationQuestionId = questionRepository.save(new Question(true, QuestionType.CHECKBOX, "์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜, ํ˜‘์—… ๋Šฅ๋ ฅ์—์„œ ์–ด๋–ค ๋ถ€๋ถ„์ด ์ธ์ƒ ๊นŠ์—ˆ๋Š”์ง€ ์„ ํƒํ•ด์ฃผ์„ธ์š”.", null, 1)).getId(); + long checkboxCommunicationQuestionId = questionRepository.save(new Question(true, QuestionType.CHECKBOX, "์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜, ํ˜‘์—… ๋Šฅ๋ ฅ์—์„œ ์–ด๋–ค ๋ถ€๋ถ„์ด ์ธ์ƒ ๊นŠ์—ˆ๋Š”์ง€ ์„ ํƒํ•ด์ฃผ์„ธ์š”.", null, 1)).getId(); long textCommunicationQuestionId = questionRepository.save(new Question(true, QuestionType.TEXT, CATEGORY_TEXT_QUESTION, "์ƒํ™ฉ์„ ์ž์„ธํ•˜๊ฒŒ ๊ธฐ๋กํ• ์ˆ˜๋ก ${revieweeName}์—๊ฒŒ ๋„์›€์ด ๋ผ์š”. ${revieweeName} ๋•๋ถ„์— ํŒ€์ด ์›ํ™œํ•œ ์†Œํ†ต์„ ์ด๋ค˜๊ฑฐ๋‚˜, ํ•จ๊ป˜ ์ผํ•˜๋ฉด์„œ ๋ฐฐ์šธ ์ ์ด ์žˆ์—ˆ๋Š”์ง€ ๋– ์˜ฌ๋ ค ๋ณด์„ธ์š”.", 2)).getId(); - long communicationSectionId = sectionRepository.save(new Section(VisibleType.CONDITIONAL, List.of(checkBoxCommunicationQuestionId, textCommunicationQuestionId), communicationOptionId, "์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜ ๋Šฅ๋ ฅ", CATEGORY_HEADER, 2)).getId(); - long communicationOptionGroupId = optionGroupRepository.save(new OptionGroup(checkBoxCommunicationQuestionId, KEYWORD_CHECKBOX_MIN_COUNT, KEYWORD_CHECKBOX_MAX_COUNT)).getId(); + long communicationSectionId = sectionRepository.save(new Section(VisibleType.CONDITIONAL, List.of(checkboxCommunicationQuestionId, textCommunicationQuestionId), communicationOptionId, "์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜ ๋Šฅ๋ ฅ", CATEGORY_HEADER, 2)).getId(); + long communicationOptionGroupId = optionGroupRepository.save(new OptionGroup(checkboxCommunicationQuestionId, KEYWORD_CHECKBOX_MIN_COUNT, KEYWORD_CHECKBOX_MAX_COUNT)).getId(); optionItemRepository.save(new OptionItem("๋ฐ˜๋Œ€ ์˜๊ฒฌ์„ ๋‚ด๋”๋ผ๋„ ๋“ฃ๋Š” ์‚ฌ๋žŒ์ด ๊ธฐ๋ถ„ ๋‚˜์˜์ง€ ์•Š๊ฒŒ ์ด์•ผ๊ธฐํ•ด์š”.",communicationOptionGroupId,1, OptionType.KEYWORD )); optionItemRepository.save(new OptionItem("ํŒ€์›๋“ค์˜ ์˜๊ฒฌ์„ ์ž˜ ๋ชจ์•„์„œ ํšŒ์˜๊ฐ€ ๋งค๋„๋Ÿฝ๊ฒŒ ์ง„ํ–‰๋˜๋„๋ก ํ•ด์š”.",communicationOptionGroupId,2, OptionType.KEYWORD )); optionItemRepository.save(new OptionItem("ํŒ€์˜ ๋ถ„์œ„๊ธฐ๋ฅผ ์ฃผ๋„ํ•ด์š”.",communicationOptionGroupId,3, OptionType.KEYWORD )); @@ -66,10 +66,10 @@ public void setup() { optionItemRepository.save(new OptionItem("์„œ๋กœ ๋‹ค๋ฅธ ๋ถ„์•ผ๊ฐ„์˜ ์†Œํ†ต๋„ ์ค‘์š”ํ•˜๊ฒŒ ์ƒ๊ฐํ•ด์š”.",communicationOptionGroupId,7, OptionType.KEYWORD )); // ๋ฌธ์ œํ•ด๊ฒฐ ๋Šฅ๋ ฅ ์„น์…˜ - long checkBoxProblemSolvingQuestionId = questionRepository.save(new Question(true, QuestionType.CHECKBOX, "๋ฌธ์ œํ•ด๊ฒฐ ๋Šฅ๋ ฅ์—์„œ ์–ด๋А ๋ถ€๋ถ„์ด ์ธ์ƒ ๊นŠ์—ˆ๋Š”์ง€ ์„ ํƒํ•ด์ฃผ์„ธ์š”.", null, 1)).getId(); + long checkboxProblemSolvingQuestionId = questionRepository.save(new Question(true, QuestionType.CHECKBOX, "๋ฌธ์ œํ•ด๊ฒฐ ๋Šฅ๋ ฅ์—์„œ ์–ด๋А ๋ถ€๋ถ„์ด ์ธ์ƒ ๊นŠ์—ˆ๋Š”์ง€ ์„ ํƒํ•ด์ฃผ์„ธ์š”.", null, 1)).getId(); long textProblemSolvingQuestionId = questionRepository.save(new Question(true, QuestionType.TEXT, CATEGORY_TEXT_QUESTION, "์ƒํ™ฉ์„ ์ž์„ธํ•˜๊ฒŒ ๊ธฐ๋กํ• ์ˆ˜๋ก ${revieweeName}์—๊ฒŒ ๋„์›€์ด ๋ผ์š”. ์–ด๋–ค ๋ฌธ์ œ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ–ˆ๊ณ , ${revieweeName/๊ฐ€:์ด} ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ–ˆ๋Š”์ง€ ๊ทธ ๊ณผ์ •์„ ๋– ์˜ฌ๋ ค ๋ณด์„ธ์š”.", 2)).getId(); - long problemSolvingSectionId = sectionRepository.save(new Section(VisibleType.CONDITIONAL, List.of(checkBoxProblemSolvingQuestionId, textProblemSolvingQuestionId), problemSolvingOptionId, "๋ฌธ์ œํ•ด๊ฒฐ ๋Šฅ๋ ฅ", CATEGORY_HEADER, 3)).getId(); - long problemSolvingOptionGroupId = optionGroupRepository.save(new OptionGroup(checkBoxProblemSolvingQuestionId, KEYWORD_CHECKBOX_MIN_COUNT, KEYWORD_CHECKBOX_MAX_COUNT)).getId(); + long problemSolvingSectionId = sectionRepository.save(new Section(VisibleType.CONDITIONAL, List.of(checkboxProblemSolvingQuestionId, textProblemSolvingQuestionId), problemSolvingOptionId, "๋ฌธ์ œํ•ด๊ฒฐ ๋Šฅ๋ ฅ", CATEGORY_HEADER, 3)).getId(); + long problemSolvingOptionGroupId = optionGroupRepository.save(new OptionGroup(checkboxProblemSolvingQuestionId, KEYWORD_CHECKBOX_MIN_COUNT, KEYWORD_CHECKBOX_MAX_COUNT)).getId(); optionItemRepository.save(new OptionItem("ํฐ ๋ฌธ์ œ๋ฅผ ์ž‘์€ ๋‹จ์œ„๋กœ ์ชผ๊ฐœ์„œ ๋‹จ๊ณ„๋ณ„๋กœ ํ•ด๊ฒฐํ•ด๋‚˜๊ฐ€์š”.",problemSolvingOptionGroupId,1, OptionType.KEYWORD )); optionItemRepository.save(new OptionItem("๋‚ฏ์„  ๋ฌธ์ œ๋ฅผ ๋งŒ๋‚˜๋„ ๋‹นํ™ฉํ•˜์ง€ ์•Š๊ณ  ์ฐจ๋ถ„ํ•˜๊ฒŒ ํ’€์–ด๋‚˜๊ฐ€์š”.",problemSolvingOptionGroupId,2, OptionType.KEYWORD )); optionItemRepository.save(new OptionItem("๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์œ„ํ•ด GPT๋“ฑ์˜ ์ž์›์„ ์ ๊ทน์ ์œผ๋กœ ํ™œ์šฉํ•ด์š”.",problemSolvingOptionGroupId,3, OptionType.KEYWORD )); @@ -80,10 +80,10 @@ public void setup() { optionItemRepository.save(new OptionItem("๋ฌธ์ œ ์›์ธ๊ณผ ํ•ด๊ฒฐ์ฑ…์— ๋Œ€ํ•œ ๊ฐ€์„ค์„ ์„ธ์šฐ๊ณ  ์ง์ ‘ ์‹คํ—˜ํ•ด๋ด์š”.",problemSolvingOptionGroupId,8, OptionType.KEYWORD )); // ์‹œ๊ฐ„ ๊ด€๋ฆฌ ๋Šฅ๋ ฅ ์„น์…˜ - long checkBoxTimeManagingQuestionId = questionRepository.save(new Question(true, QuestionType.CHECKBOX, "์‹œ๊ฐ„ ๊ด€๋ฆฌ ๋Šฅ๋ ฅ์—์„œ ์–ด๋А ๋ถ€๋ถ„์ด ์ธ์ƒ ๊นŠ์—ˆ๋Š”์ง€ ์„ ํƒํ•ด์ฃผ์„ธ์š”.", null, 1)).getId(); + long checkboxTimeManagingQuestionId = questionRepository.save(new Question(true, QuestionType.CHECKBOX, "์‹œ๊ฐ„ ๊ด€๋ฆฌ ๋Šฅ๋ ฅ์—์„œ ์–ด๋А ๋ถ€๋ถ„์ด ์ธ์ƒ ๊นŠ์—ˆ๋Š”์ง€ ์„ ํƒํ•ด์ฃผ์„ธ์š”.", null, 1)).getId(); long textTimeManagingQuestionId = questionRepository.save(new Question(true, QuestionType.TEXT, CATEGORY_TEXT_QUESTION, "์ƒํ™ฉ์„ ์ž์„ธํ•˜๊ฒŒ ๊ธฐ๋กํ• ์ˆ˜๋ก ${revieweeName}์—๊ฒŒ ๋„์›€์ด ๋ผ์š”. ${revieweeName} ๋•๋ถ„์— ํŒ€์ด ํšจ์œจ์ ์œผ๋กœ ์‹œ๊ฐ„๊ด€๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ์—ˆ๋Š”์ง€ ๋– ์˜ฌ๋ ค ๋ณด์„ธ์š”.", 2)).getId(); - long timeManagingSectionId = sectionRepository.save(new Section(VisibleType.CONDITIONAL, List.of(checkBoxTimeManagingQuestionId, textTimeManagingQuestionId), timeManagingOptionId, "์‹œ๊ฐ„๊ด€๋ฆฌ ๋Šฅ๋ ฅ", CATEGORY_HEADER, 4)).getId(); - long timeManagingOptionGroupId = optionGroupRepository.save(new OptionGroup(checkBoxTimeManagingQuestionId, KEYWORD_CHECKBOX_MIN_COUNT, KEYWORD_CHECKBOX_MAX_COUNT)).getId(); + long timeManagingSectionId = sectionRepository.save(new Section(VisibleType.CONDITIONAL, List.of(checkboxTimeManagingQuestionId, textTimeManagingQuestionId), timeManagingOptionId, "์‹œ๊ฐ„๊ด€๋ฆฌ ๋Šฅ๋ ฅ", CATEGORY_HEADER, 4)).getId(); + long timeManagingOptionGroupId = optionGroupRepository.save(new OptionGroup(checkboxTimeManagingQuestionId, KEYWORD_CHECKBOX_MIN_COUNT, KEYWORD_CHECKBOX_MAX_COUNT)).getId(); optionItemRepository.save(new OptionItem("ํ”„๋กœ์ ํŠธ์˜ ์ผ์ •๊ณผ ์ฃผ์š” ๋งˆ์ผ์Šคํ†ค์„ ์„ค์ •ํ•˜์—ฌ ์ฒด๊ณ„์ ์œผ๋กœ ์ผ์ •์„ ๊ด€๋ฆฌํ•ด์š”.",timeManagingOptionGroupId,1, OptionType.KEYWORD )); optionItemRepository.save(new OptionItem("์ผ์ •์— ๋”ฐ๋ผ ๋งˆ๊ฐ ๊ธฐํ•œ์„ ์ž˜ ์ง€์ผœ์š”.",timeManagingOptionGroupId,2, OptionType.KEYWORD )); optionItemRepository.save(new OptionItem("์—…๋ฌด์˜ ์ค‘์š”๋„์™€ ๊ธด๊ธ‰์„ฑ์„ ๊ณ ๋ คํ•˜์—ฌ ์šฐ์„  ์ˆœ์œ„๋ฅผ ์ •ํ•˜๊ณ , ๊ทธ์— ๋”ฐ๋ผ ์ž‘์—…์„ ๋ถ„๋ฐฐํ•ด์š”.",timeManagingOptionGroupId,3, OptionType.KEYWORD )); @@ -91,10 +91,10 @@ public void setup() { optionItemRepository.save(new OptionItem("ํšŒ์˜ ์‹œ๊ฐ„๊ณผ ๊ฐ™์€ ์•ฝ์†๋œ ์‹œ๊ฐ„์„ ์ž˜ ์ง€์ผœ์š”.",timeManagingOptionGroupId,5, OptionType.KEYWORD )); // ๊ธฐ์ˆ  ์—ญ๋Ÿ‰ ์„น์…˜ - long checkBoxTechnicalQuestionId = questionRepository.save(new Question(true, QuestionType.CHECKBOX, "๊ธฐ์ˆ  ์—ญ๋Ÿ‰, ์ „๋ฌธ ์ง€์‹์—์„œ ์–ด๋–ค ๋ถ€๋ถ„์ด ์ธ์ƒ ๊นŠ์—ˆ๋Š”์ง€ ์„ ํƒํ•ด์ฃผ์„ธ์š”.", null, 1)).getId(); + long checkboxTechnicalQuestionId = questionRepository.save(new Question(true, QuestionType.CHECKBOX, "๊ธฐ์ˆ  ์—ญ๋Ÿ‰, ์ „๋ฌธ ์ง€์‹์—์„œ ์–ด๋–ค ๋ถ€๋ถ„์ด ์ธ์ƒ ๊นŠ์—ˆ๋Š”์ง€ ์„ ํƒํ•ด์ฃผ์„ธ์š”.", null, 1)).getId(); long textTechnicalQuestionId = questionRepository.save(new Question(true, QuestionType.TEXT, CATEGORY_TEXT_QUESTION, "์ƒํ™ฉ์„ ์ž์„ธํ•˜๊ฒŒ ๊ธฐ๋กํ• ์ˆ˜๋ก ${revieweeName}์—๊ฒŒ ๋„์›€์ด ๋ผ์š”. ${revieweeName} ๋•๋ถ„์— ๊ธฐ์ˆ ์  ์—ญ๋Ÿ‰, ์ „๋ฌธ ์ง€์‹์ ์œผ๋กœ ๋„์›€์„ ๋ฐ›์€ ๊ฒฝํ—˜์„ ๋– ์˜ฌ๋ ค ๋ณด์„ธ์š”.", 2)).getId(); - long technicalSectionId = sectionRepository.save(new Section(VisibleType.CONDITIONAL, List.of(checkBoxTechnicalQuestionId, textTechnicalQuestionId), technicalOptionId, "๊ธฐ์ˆ  ์—ญ๋Ÿ‰", CATEGORY_HEADER, 5)).getId(); - long technicalOptionGroupId = optionGroupRepository.save(new OptionGroup(checkBoxTechnicalQuestionId, KEYWORD_CHECKBOX_MIN_COUNT, KEYWORD_CHECKBOX_MAX_COUNT)).getId(); + long technicalSectionId = sectionRepository.save(new Section(VisibleType.CONDITIONAL, List.of(checkboxTechnicalQuestionId, textTechnicalQuestionId), technicalOptionId, "๊ธฐ์ˆ  ์—ญ๋Ÿ‰", CATEGORY_HEADER, 5)).getId(); + long technicalOptionGroupId = optionGroupRepository.save(new OptionGroup(checkboxTechnicalQuestionId, KEYWORD_CHECKBOX_MIN_COUNT, KEYWORD_CHECKBOX_MAX_COUNT)).getId(); optionItemRepository.save(new OptionItem("๊ด€๋ จ ์–ธ์–ด / ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ / ํ”„๋ ˆ์ž„์›Œํฌ ์ง€์‹์ด ํ’๋ถ€ํ•ด์š”.",technicalOptionGroupId,1, OptionType.KEYWORD )); optionItemRepository.save(new OptionItem("์ธํ”„๋ผ ์ง€์‹์ด ํ’๋ถ€ํ•ด์š”.",technicalOptionGroupId,2, OptionType.KEYWORD )); optionItemRepository.save(new OptionItem("CS ์ง€์‹์ด ํ’๋ถ€ํ•ด์š”.",technicalOptionGroupId,3, OptionType.KEYWORD )); @@ -109,10 +109,10 @@ public void setup() { optionItemRepository.save(new OptionItem("์ง€์†์ ์ธ ํ•™์Šต๊ณผ ๊ณต์œ ๋ฅผ ํ†ตํ•ด ํŒ€์˜ ๊ธฐ์ˆ  ์ˆ˜์ค€์„ ๋†’์˜€์–ด์š”.",technicalOptionGroupId,12, OptionType.KEYWORD )); // ์„ฑ์žฅ ๋งˆ์ธ๋“œ์…‹ ์„น์…˜ - long checkBoxGrowthQuestionId = questionRepository.save(new Question(true, QuestionType.CHECKBOX, "์„ฑ์žฅ ๋งˆ์ธ๋“œ์…‹์—์„œ ์–ด๋–ค ๋ถ€๋ถ„์ด ์ธ์ƒ ๊นŠ์—ˆ๋Š”์ง€ ์„ ํƒํ•ด์ฃผ์„ธ์š”.", null, 1)).getId(); + long checkboxGrowthQuestionId = questionRepository.save(new Question(true, QuestionType.CHECKBOX, "์„ฑ์žฅ ๋งˆ์ธ๋“œ์…‹์—์„œ ์–ด๋–ค ๋ถ€๋ถ„์ด ์ธ์ƒ ๊นŠ์—ˆ๋Š”์ง€ ์„ ํƒํ•ด์ฃผ์„ธ์š”.", null, 1)).getId(); long textGrowthQuestionId = questionRepository.save(new Question(true, QuestionType.TEXT, CATEGORY_TEXT_QUESTION, "์ƒํ™ฉ์„ ์ž์„ธํ•˜๊ฒŒ ๊ธฐ๋กํ• ์ˆ˜๋ก ${revieweeName}์—๊ฒŒ ๋„์›€์ด ๋ผ์š”. ์ธ์ƒ๊นŠ์—ˆ๋˜ ${revieweeName}์˜ ์„ฑ์žฅ ๋งˆ์ธ๋“œ์…‹์„ ๋– ์˜ฌ๋ ค ๋ณด์„ธ์š”.", 2)).getId(); - long growthSectionId = sectionRepository.save(new Section(VisibleType.CONDITIONAL, List.of(checkBoxGrowthQuestionId, textGrowthQuestionId), growthOptionId, "์„ฑ์žฅ ๋งˆ์ธ๋“œ์…‹", CATEGORY_HEADER, 6)).getId(); - long growthOptionGroupId = optionGroupRepository.save(new OptionGroup(checkBoxGrowthQuestionId, KEYWORD_CHECKBOX_MIN_COUNT, KEYWORD_CHECKBOX_MAX_COUNT)).getId(); + long growthSectionId = sectionRepository.save(new Section(VisibleType.CONDITIONAL, List.of(checkboxGrowthQuestionId, textGrowthQuestionId), growthOptionId, "์„ฑ์žฅ ๋งˆ์ธ๋“œ์…‹", CATEGORY_HEADER, 6)).getId(); + long growthOptionGroupId = optionGroupRepository.save(new OptionGroup(checkboxGrowthQuestionId, KEYWORD_CHECKBOX_MIN_COUNT, KEYWORD_CHECKBOX_MAX_COUNT)).getId(); optionItemRepository.save(new OptionItem("์–ด๋–ค ์ƒํ™ฉ์—๋„ ๊ธ์ •์ ์ธ ํƒœ๋„๋กœ ์ž„ํ•ด์š”.",growthOptionGroupId,1, OptionType.KEYWORD )); optionItemRepository.save(new OptionItem("์ฃผ๋ณ€ ์‚ฌ๋žŒ๋“คํ•œํ…Œ ์งˆ๋ฌธํ•˜๋Š” ๊ฒƒ์„ ๋ถ€๋„๋Ÿฌ์›Œํ•˜์ง€ ์•Š์•„์š”.",growthOptionGroupId,2, OptionType.KEYWORD )); optionItemRepository.save(new OptionItem("์–ด๋ ค์›€์ด ์žˆ์–ด๋„ ๋๊นŒ์ง€ ํ•ด๋‚ด์š”.",growthOptionGroupId,3, OptionType.KEYWORD )); diff --git a/backend/src/main/java/reviewme/review/service/exception/CheckBoxAnswerIncludedNotProvidedOptionItemException.java b/backend/src/main/java/reviewme/review/service/exception/CheckboxAnswerIncludedNotProvidedOptionItemException.java similarity index 84% rename from backend/src/main/java/reviewme/review/service/exception/CheckBoxAnswerIncludedNotProvidedOptionItemException.java rename to backend/src/main/java/reviewme/review/service/exception/CheckboxAnswerIncludedNotProvidedOptionItemException.java index e902d3e2f..1a850bb61 100644 --- a/backend/src/main/java/reviewme/review/service/exception/CheckBoxAnswerIncludedNotProvidedOptionItemException.java +++ b/backend/src/main/java/reviewme/review/service/exception/CheckboxAnswerIncludedNotProvidedOptionItemException.java @@ -5,9 +5,9 @@ import reviewme.global.exception.BadRequestException; @Slf4j -public class CheckBoxAnswerIncludedNotProvidedOptionItemException extends BadRequestException { +public class CheckboxAnswerIncludedNotProvidedOptionItemException extends BadRequestException { - public CheckBoxAnswerIncludedNotProvidedOptionItemException(long questionId, + public CheckboxAnswerIncludedNotProvidedOptionItemException(long questionId, List providedOptionIds, List submittedOptionIds) { super("์ œ๊ณต๋˜๋Š” ์„ ํƒ์ง€์— ์—†๋Š” ์„ ํƒ์ง€๋ฅผ ์‘๋‹ตํ–ˆ์–ด์š”."); diff --git a/backend/src/main/java/reviewme/review/service/exception/OptionGroupNotFoundByQuestionIdException.java b/backend/src/main/java/reviewme/review/service/exception/OptionGroupNotFoundByQuestionIdException.java index 9039de3ae..f0b2899f8 100644 --- a/backend/src/main/java/reviewme/review/service/exception/OptionGroupNotFoundByQuestionIdException.java +++ b/backend/src/main/java/reviewme/review/service/exception/OptionGroupNotFoundByQuestionIdException.java @@ -8,6 +8,6 @@ public class OptionGroupNotFoundByQuestionIdException extends DataInconsistencyE public OptionGroupNotFoundByQuestionIdException(long questionId) { super("์„œ๋ฒ„ ๋‚ด๋ถ€์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”."); - log.error("User submitted checkBoxAnswer without provided options - questionId: {}", questionId, this); + log.error("User submitted checkboxAnswer without provided options - questionId: {}", questionId, this); } } diff --git a/backend/src/main/java/reviewme/review/service/mapper/ReviewDetailMapper.java b/backend/src/main/java/reviewme/review/service/mapper/ReviewDetailMapper.java index c2874c1c1..efbde5596 100644 --- a/backend/src/main/java/reviewme/review/service/mapper/ReviewDetailMapper.java +++ b/backend/src/main/java/reviewme/review/service/mapper/ReviewDetailMapper.java @@ -86,7 +86,7 @@ private SectionAnswerResponse mapToSectionResponse(Review review, Section sectio private QuestionAnswerResponse mapToQuestionResponse(Review review, Question question, Map optionGroupsByQuestion, Map> optionItemsByOptionGroup) { - if (question.isSelectable()) { + if (question.isCheckboxType()) { return mapToCheckboxQuestionResponse(review, question, optionGroupsByQuestion, optionItemsByOptionGroup); } else { return mapToTextQuestionResponse(review, question); diff --git a/backend/src/main/java/reviewme/review/service/mapper/ReviewGatherMapper.java b/backend/src/main/java/reviewme/review/service/mapper/ReviewGatherMapper.java index d53fd0905..85f7ceddd 100644 --- a/backend/src/main/java/reviewme/review/service/mapper/ReviewGatherMapper.java +++ b/backend/src/main/java/reviewme/review/service/mapper/ReviewGatherMapper.java @@ -51,7 +51,7 @@ private ReviewsGatheredByQuestionResponse mapToReviewsGatheredByQuestion(Questio @Nullable private List mapToTextResponse(Question question, List answers, List highlights) { - if (question.isSelectable()) { + if (question.isCheckboxType()) { return null; } Map> answerIdHighlights = highlights.stream() @@ -84,7 +84,7 @@ private List mapToHighlightResponse(List highlight @Nullable private List mapToVoteResponse(Question question, List answers) { - if (!question.isSelectable()) { + if (!question.isCheckboxType()) { return null; } diff --git a/backend/src/main/java/reviewme/review/service/mapper/ReviewListMapper.java b/backend/src/main/java/reviewme/review/service/mapper/ReviewListMapper.java index ab5ec4327..d0e4d74d1 100644 --- a/backend/src/main/java/reviewme/review/service/mapper/ReviewListMapper.java +++ b/backend/src/main/java/reviewme/review/service/mapper/ReviewListMapper.java @@ -48,13 +48,13 @@ private ReviewListElementResponse mapToReviewListElementResponse(Review review, private List mapToCategoryOptionResponse(Review review, List categoryOptionItems) { - Set checkBoxOptionIds = review.getAnswersByType(CheckboxAnswer.class) + Set checkboxOptionIds = review.getAnswersByType(CheckboxAnswer.class) .stream() .flatMap(answer -> answer.getSelectedOptionIds().stream()) .map(CheckboxAnswerSelectedOption::getSelectedOptionId) .collect(Collectors.toSet()); return categoryOptionItems.stream() - .filter(optionItem -> checkBoxOptionIds.contains(optionItem.getId())) + .filter(optionItem -> checkboxOptionIds.contains(optionItem.getId())) .map(optionItem -> new ReviewCategoryResponse(optionItem.getId(), optionItem.getContent())) .toList(); } diff --git a/backend/src/main/java/reviewme/review/service/validator/CheckboxTypedAnswerValidator.java b/backend/src/main/java/reviewme/review/service/validator/CheckboxTypedAnswerValidator.java index d6cd50eec..fac17743d 100644 --- a/backend/src/main/java/reviewme/review/service/validator/CheckboxTypedAnswerValidator.java +++ b/backend/src/main/java/reviewme/review/service/validator/CheckboxTypedAnswerValidator.java @@ -14,7 +14,7 @@ import reviewme.review.domain.Answer; import reviewme.review.domain.CheckboxAnswerSelectedOption; import reviewme.review.domain.CheckboxAnswer; -import reviewme.review.service.exception.CheckBoxAnswerIncludedNotProvidedOptionItemException; +import reviewme.review.service.exception.CheckboxAnswerIncludedNotProvidedOptionItemException; import reviewme.review.service.exception.OptionGroupNotFoundByQuestionIdException; import reviewme.review.service.exception.SelectedOptionItemCountOutOfRangeException; import reviewme.review.service.exception.SubmittedQuestionNotFoundException; @@ -53,7 +53,7 @@ private void validateOnlyIncludingProvidedOptionItem(CheckboxAnswer checkboxAnsw List answeredOptionItemIds = extractAnsweredOptionItemIds(checkboxAnswer); if (!new HashSet<>(providedOptionItemIds).containsAll(answeredOptionItemIds)) { - throw new CheckBoxAnswerIncludedNotProvidedOptionItemException( + throw new CheckboxAnswerIncludedNotProvidedOptionItemException( checkboxAnswer.getQuestionId(), providedOptionItemIds, answeredOptionItemIds ); } diff --git a/backend/src/main/java/reviewme/review/service/validator/ReviewValidator.java b/backend/src/main/java/reviewme/review/service/validator/ReviewValidator.java index 96fb55ec4..f107c0fd8 100644 --- a/backend/src/main/java/reviewme/review/service/validator/ReviewValidator.java +++ b/backend/src/main/java/reviewme/review/service/validator/ReviewValidator.java @@ -15,7 +15,6 @@ import reviewme.review.service.exception.SubmittedQuestionAndProvidedQuestionMismatchException; import reviewme.template.domain.Question; import reviewme.template.domain.Section; -import reviewme.template.domain.SectionQuestion; import reviewme.template.repository.QuestionRepository; import reviewme.template.repository.SectionRepository; @@ -76,7 +75,6 @@ private Set extractDisplayedQuestionIds(Review review) { return sections.stream() .filter(section -> section.isVisibleBySelectedOptionIds(selectedOptionIds)) .flatMap(section -> section.getQuestionIds().stream()) - .map(SectionQuestion::getQuestionId) .collect(Collectors.toSet()); } } diff --git a/backend/src/main/java/reviewme/template/domain/Question.java b/backend/src/main/java/reviewme/template/domain/Question.java index f4384d854..5f8f010fa 100644 --- a/backend/src/main/java/reviewme/template/domain/Question.java +++ b/backend/src/main/java/reviewme/template/domain/Question.java @@ -48,7 +48,7 @@ public Question(boolean required, QuestionType questionType, String content, Str this.position = position; } - public boolean isSelectable() { + public boolean isCheckboxType() { return questionType == QuestionType.CHECKBOX; } diff --git a/backend/src/main/java/reviewme/template/domain/Section.java b/backend/src/main/java/reviewme/template/domain/Section.java index b9fa82b16..c00145d6f 100644 --- a/backend/src/main/java/reviewme/template/domain/Section.java +++ b/backend/src/main/java/reviewme/template/domain/Section.java @@ -13,11 +13,14 @@ import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import java.util.Collection; +import java.util.HashSet; import java.util.List; import lombok.AccessLevel; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; +import reviewme.template.domain.exception.DuplicateQuestionIdException; +import reviewme.template.domain.exception.QuestionIdsNotExistException; @Entity @Table(name = "section") @@ -52,6 +55,7 @@ public class Section { public Section(VisibleType visibleType, List questionIds, Long onSelectedOptionId, String sectionName, String header, int position) { + validateQuestionIds(questionIds); this.visibleType = visibleType; this.questionIds = questionIds.stream() .map(SectionQuestion::new) @@ -62,6 +66,36 @@ public Section(VisibleType visibleType, List questionIds, this.position = position; } + private void validateQuestionIds(List questionIds) { + validateNotEmpty(questionIds); + validateNoDuplicates(questionIds); + } + + private void validateNotEmpty(List questionIds) { + if (questionIds == null || questionIds.isEmpty()) { + throw new QuestionIdsNotExistException(); + } + } + + private void validateNoDuplicates(List questionIds) { + int originalSize = questionIds.size(); + int deduplicatedSize = new HashSet<>(questionIds).size(); + + if (originalSize != deduplicatedSize) { + throw new DuplicateQuestionIdException(questionIds); + } + } + + public List getQuestionIds() { + return questionIds.stream() + .map(SectionQuestion::getQuestionId) + .toList(); + } + + public boolean isAlwaysVisible() { + return visibleType == VisibleType.ALWAYS; + } + public boolean isVisibleBySelectedOptionIds(Collection selectedOptionIds) { return visibleType == VisibleType.ALWAYS || selectedOptionIds.contains(onSelectedOptionId); } diff --git a/backend/src/main/java/reviewme/template/domain/Template.java b/backend/src/main/java/reviewme/template/domain/Template.java index 29b6f36d7..cda50f39e 100644 --- a/backend/src/main/java/reviewme/template/domain/Template.java +++ b/backend/src/main/java/reviewme/template/domain/Template.java @@ -9,11 +9,14 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; +import java.util.HashSet; import java.util.List; import lombok.AccessLevel; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; +import reviewme.template.domain.exception.DuplicateSectionIdException; +import reviewme.template.domain.exception.SectionIdsNotExistException; @Entity @Table(name = "template") @@ -31,8 +34,35 @@ public class Template { private List sectionIds; public Template(List sectionIds) { + validateSectionIds(sectionIds); this.sectionIds = sectionIds.stream() .map(TemplateSection::new) .toList(); } + + private void validateSectionIds(List sectionIds) { + validateNotEmpty(sectionIds); + validateNoDuplicates(sectionIds); + } + + private void validateNotEmpty(List sectionIds) { + if (sectionIds == null || sectionIds.isEmpty()) { + throw new SectionIdsNotExistException(); + } + } + + private void validateNoDuplicates(List sectionIds) { + int originalSize = sectionIds.size(); + int deduplicatedSize = new HashSet<>(sectionIds).size(); + + if (originalSize != deduplicatedSize) { + throw new DuplicateSectionIdException(sectionIds); + } + } + + public List getSectionIds() { + return sectionIds.stream() + .map(TemplateSection::getSectionId) + .toList(); + } } diff --git a/backend/src/main/java/reviewme/template/domain/exception/DuplicateQuestionIdException.java b/backend/src/main/java/reviewme/template/domain/exception/DuplicateQuestionIdException.java new file mode 100644 index 000000000..a4885475d --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/DuplicateQuestionIdException.java @@ -0,0 +1,14 @@ +package reviewme.template.domain.exception; + +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class DuplicateQuestionIdException extends BadRequestException { + + public DuplicateQuestionIdException(List questionIds) { + super("์„น์…˜์—๋Š” ์ค‘๋ณต๋œ ์งˆ๋ฌธ์ด ์žˆ์„ ์ˆ˜ ์—†์–ด์š”."); + log.info("Duplicate question ID found while creating Section - questionIds: {}", questionIds); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/exception/DuplicateSectionIdException.java b/backend/src/main/java/reviewme/template/domain/exception/DuplicateSectionIdException.java new file mode 100644 index 000000000..407a851ba --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/DuplicateSectionIdException.java @@ -0,0 +1,14 @@ +package reviewme.template.domain.exception; + +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class DuplicateSectionIdException extends BadRequestException { + + public DuplicateSectionIdException(List sectionIds) { + super("ํ…œํ”Œ๋ฆฟ์—๋Š” ์ค‘๋ณต๋œ ์„น์…˜์ด ์žˆ์„ ์ˆ˜ ์—†์–ด์š”."); + log.info("Duplicate section ID found while creating Template - sectionIds: {}", sectionIds); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/exception/OptionGroupNotExistException.java b/backend/src/main/java/reviewme/template/domain/exception/OptionGroupNotExistException.java new file mode 100644 index 000000000..49b0016a1 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/OptionGroupNotExistException.java @@ -0,0 +1,13 @@ +package reviewme.template.domain.exception; + +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class OptionGroupNotExistException extends BadRequestException { + + public OptionGroupNotExistException() { + super("์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์–ด์š”. ์„œ๋ฒ„์— ๋ฌธ์˜ํ•ด์ฃผ์„ธ์š”."); + log.info("No OptionGroup exists while creating OptionGroups"); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/exception/OptionItemNotExistException.java b/backend/src/main/java/reviewme/template/domain/exception/OptionItemNotExistException.java new file mode 100644 index 000000000..8984e2edc --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/OptionItemNotExistException.java @@ -0,0 +1,13 @@ +package reviewme.template.domain.exception; + +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class OptionItemNotExistException extends BadRequestException { + + public OptionItemNotExistException() { + super("์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์–ด์š”. ์„œ๋ฒ„์— ๋ฌธ์˜ํ•ด์ฃผ์„ธ์š”."); + log.info("No OptionItem exists while creating OptionItems"); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/exception/QuestionIdsNotExistException.java b/backend/src/main/java/reviewme/template/domain/exception/QuestionIdsNotExistException.java new file mode 100644 index 000000000..007fbc4e3 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/QuestionIdsNotExistException.java @@ -0,0 +1,13 @@ +package reviewme.template.domain.exception; + +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class QuestionIdsNotExistException extends BadRequestException { + + public QuestionIdsNotExistException() { + super("์„น์…˜์—๋Š” ํ•˜๋‚˜ ์ด์ƒ์˜ ์งˆ๋ฌธ์ด ์กด์žฌํ•ด์•ผ ํ•ด์š”."); + log.info("No question exists while creating Section"); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/exception/QuestionNotExistException.java b/backend/src/main/java/reviewme/template/domain/exception/QuestionNotExistException.java new file mode 100644 index 000000000..c0abef140 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/QuestionNotExistException.java @@ -0,0 +1,13 @@ +package reviewme.template.domain.exception; + +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class QuestionNotExistException extends BadRequestException { + + public QuestionNotExistException() { + super("์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์–ด์š”. ์„œ๋ฒ„์— ๋ฌธ์˜ํ•ด์ฃผ์„ธ์š”."); + log.info("No question exists while creating Questions"); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/exception/SectionIdsNotExistException.java b/backend/src/main/java/reviewme/template/domain/exception/SectionIdsNotExistException.java new file mode 100644 index 000000000..e81e63644 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/SectionIdsNotExistException.java @@ -0,0 +1,13 @@ +package reviewme.template.domain.exception; + +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class SectionIdsNotExistException extends BadRequestException { + + public SectionIdsNotExistException() { + super("ํ…œํ”Œ๋ฆฟ์—๋Š” ํ•˜๋‚˜ ์ด์ƒ์˜ ์„น์…˜์ด ์กด์žฌํ•ด์•ผ ํ•ด์š”."); + log.info("No section exists while creating Template"); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/exception/SectionNotExistException.java b/backend/src/main/java/reviewme/template/domain/exception/SectionNotExistException.java new file mode 100644 index 000000000..a11569dc4 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/SectionNotExistException.java @@ -0,0 +1,13 @@ +package reviewme.template.domain.exception; + +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class SectionNotExistException extends BadRequestException { + + public SectionNotExistException() { + super("์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์–ด์š”. ์„œ๋ฒ„์— ๋ฌธ์˜ํ•ด์ฃผ์„ธ์š”."); + log.info("No section exists while creating Sections"); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateCheckBoxQuestionFoundException.java b/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateCheckBoxQuestionFoundException.java new file mode 100644 index 000000000..eae089dc8 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateCheckBoxQuestionFoundException.java @@ -0,0 +1,15 @@ +package reviewme.template.domain.exception; + +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class StructuredTemplateCheckBoxQuestionFoundException extends BadRequestException { + + public StructuredTemplateCheckBoxQuestionFoundException(List questionIds) { + super("์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์–ด์š”. ์„œ๋ฒ„์— ๋ฌธ์˜ํ•ด์ฃผ์„ธ์š”."); + log.warn("CheckBox Type Question Found during Only Text Answer StructuredTemplate creation: questionIds: {}", + questionIds); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateInvisibleSectionFoundException.java b/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateInvisibleSectionFoundException.java new file mode 100644 index 000000000..7b70a1955 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateInvisibleSectionFoundException.java @@ -0,0 +1,31 @@ +package reviewme.template.domain.exception; + +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class StructuredTemplateInvisibleSectionFoundException extends BadRequestException { + + private static final String INTERNAL_SERVER_ERROR_MESSAGE = "์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์–ด์š”. ์„œ๋ฒ„์— ๋ฌธ์˜ํ•ด์ฃผ์„ธ์š”."; + + public StructuredTemplateInvisibleSectionFoundException(List invisibleSectionIds, List optionIds) { + super(INTERNAL_SERVER_ERROR_MESSAGE); + logWarning(invisibleSectionIds, optionIds); + } + + public StructuredTemplateInvisibleSectionFoundException(List invisibleSectionIds) { + super(INTERNAL_SERVER_ERROR_MESSAGE); + logWarning(invisibleSectionIds, null); + } + + private void logWarning(List invisibleSectionIds, List optionIds) { + if (optionIds != null) { + log.warn("Sections that cannot be exposed were found during StructuredTemplate creation: invisibleSectionIds: {}, optionIds: {}", + invisibleSectionIds, optionIds); + } else { + log.warn("Sections that cannot be exposed were found during StructuredTemplate creation: invisibleSectionIds: {}", + invisibleSectionIds); + } + } +} diff --git a/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateNotExistTemplateException.java b/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateNotExistTemplateException.java new file mode 100644 index 000000000..c1bdd8007 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateNotExistTemplateException.java @@ -0,0 +1,13 @@ +package reviewme.template.domain.exception; + +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class StructuredTemplateNotExistTemplateException extends BadRequestException { + + public StructuredTemplateNotExistTemplateException() { + super("์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์–ด์š”. ์„œ๋ฒ„์— ๋ฌธ์˜ํ•ด์ฃผ์„ธ์š”."); + log.warn("No template exists while creating StructuredTemplate"); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateOptionGroupValidationException.java b/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateOptionGroupValidationException.java new file mode 100644 index 000000000..d0bcca702 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateOptionGroupValidationException.java @@ -0,0 +1,16 @@ +package reviewme.template.domain.exception; + +import java.util.Collection; +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class StructuredTemplateOptionGroupValidationException extends BadRequestException { + + public StructuredTemplateOptionGroupValidationException(Collection checkboxQuestionIds, + Collection questionIdsOfOptionGroups) { + super("์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์–ด์š”. ์„œ๋ฒ„์— ๋ฌธ์˜ํ•ด์ฃผ์„ธ์š”."); + log.warn("OptionGroup validation failed while creating StructuredTemplate: checkboxQuestionIds: {}, questionIdsOfOptionGroups: {}", + checkboxQuestionIds, questionIdsOfOptionGroups); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateOptionItemsValidationException.java b/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateOptionItemsValidationException.java new file mode 100644 index 000000000..b605a9b45 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateOptionItemsValidationException.java @@ -0,0 +1,16 @@ +package reviewme.template.domain.exception; + +import java.util.Collection; +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class StructuredTemplateOptionItemsValidationException extends BadRequestException { + + public StructuredTemplateOptionItemsValidationException(Collection optionGroupIds, + Collection optionGroupIdsOfItems) { + super("์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์–ด์š”. ์„œ๋ฒ„์— ๋ฌธ์˜ํ•ด์ฃผ์„ธ์š”."); + log.warn("OptionItem validation failed while creating StructuredTemplate: optionGroupIds: {}, optionGroupIdsOfItems: {}", + optionGroupIds, optionGroupIdsOfItems); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateQuestionValidationException.java b/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateQuestionValidationException.java new file mode 100644 index 000000000..5e919ce6d --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateQuestionValidationException.java @@ -0,0 +1,16 @@ +package reviewme.template.domain.exception; + +import java.util.Collection; +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class StructuredTemplateQuestionValidationException extends BadRequestException { + + public StructuredTemplateQuestionValidationException(Collection questionIdsOfSections, + Collection questionIds) { + super("์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์–ด์š”. ์„œ๋ฒ„์— ๋ฌธ์˜ํ•ด์ฃผ์„ธ์š”."); + log.warn("Question validation failed while creating StructuredTemplate: questionIdsOfSections: {}, questionIds: {}", + questionIdsOfSections, questionIds); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateSectionValidationException.java b/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateSectionValidationException.java new file mode 100644 index 000000000..77ceb488a --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/exception/StructuredTemplateSectionValidationException.java @@ -0,0 +1,15 @@ +package reviewme.template.domain.exception; + +import java.util.Collection; +import lombok.extern.slf4j.Slf4j; +import reviewme.global.exception.BadRequestException; + +@Slf4j +public class StructuredTemplateSectionValidationException extends BadRequestException { + + public StructuredTemplateSectionValidationException(long templateId, Collection sectionIds) { + super("์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์–ด์š”. ์„œ๋ฒ„์— ๋ฌธ์˜ํ•ด์ฃผ์„ธ์š”."); + log.warn("Section validation failed while creating StructuredTemplate: templateId: {}, sectionIds: {}", + templateId, sectionIds); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/structured/OptionGroups.java b/backend/src/main/java/reviewme/template/domain/structured/OptionGroups.java new file mode 100644 index 000000000..f8ade9fe1 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/structured/OptionGroups.java @@ -0,0 +1,41 @@ +package reviewme.template.domain.structured; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import reviewme.template.domain.OptionGroup; +import reviewme.template.domain.exception.OptionGroupNotExistException; + +public class OptionGroups { + + private final List optionGroups; + + public OptionGroups(List optionGroups) { + validateOptionGroups(optionGroups); + this.optionGroups = optionGroups.stream() + .distinct() + .toList(); + } + + private void validateOptionGroups(List optionGroups) { + if (optionGroups == null || optionGroups.isEmpty()) { + throw new OptionGroupNotExistException(); + } + } + + public List getOptionGroupIds() { + return optionGroups.stream() + .map(OptionGroup::getId) + .toList(); + } + + public Set getQuestionIds() { + return optionGroups.stream() + .map(OptionGroup::getQuestionId) + .collect(Collectors.toSet()); + } + + public int size() { + return optionGroups.size(); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/structured/OptionItems.java b/backend/src/main/java/reviewme/template/domain/structured/OptionItems.java new file mode 100644 index 000000000..5b0f13f94 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/structured/OptionItems.java @@ -0,0 +1,38 @@ +package reviewme.template.domain.structured; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import reviewme.template.domain.OptionItem; +import reviewme.template.domain.exception.OptionItemNotExistException; + +public class OptionItems { + + private final List optionItems; + + public OptionItems(List optionItems) { + validateOptionItems(optionItems); + this.optionItems = optionItems.stream() + .distinct() + .toList(); + } + + private void validateOptionItems(List optionItems) { + if (optionItems == null || optionItems.isEmpty()) { + throw new OptionItemNotExistException(); + } + } + + public List getOptionItemIds() { + return optionItems.stream() + .map(OptionItem::getId) + .toList(); + } + + public Set getOptionGroupIds() { + return optionItems.stream() + .map(OptionItem::getOptionGroupId) + .distinct() + .collect(Collectors.toSet()); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/structured/Questions.java b/backend/src/main/java/reviewme/template/domain/structured/Questions.java new file mode 100644 index 000000000..5b153ebd8 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/structured/Questions.java @@ -0,0 +1,41 @@ +package reviewme.template.domain.structured; + +import java.util.List; +import reviewme.template.domain.Question; +import reviewme.template.domain.exception.QuestionNotExistException; + +public class Questions { + + private final List questions; + + public Questions(List questions) { + validateQuestions(questions); + this.questions = questions.stream() + .distinct() + .toList(); + } + + private void validateQuestions(List questions) { + if (questions == null || questions.isEmpty()) { + throw new QuestionNotExistException(); + } + } + + public List getQuestionIds() { + return questions.stream() + .map(Question::getId) + .toList(); + } + + public List getCheckboxQuestionIds() { + return questions.stream() + .filter(Question::isCheckboxType) + .map(Question::getId) + .toList(); + } + + public boolean hasCheckboxQuestion() { + return questions.stream() + .anyMatch(Question::isCheckboxType); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/structured/Sections.java b/backend/src/main/java/reviewme/template/domain/structured/Sections.java new file mode 100644 index 000000000..24b8afeae --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/structured/Sections.java @@ -0,0 +1,51 @@ +package reviewme.template.domain.structured; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import reviewme.template.domain.Section; +import reviewme.template.domain.exception.SectionNotExistException; + +public class Sections { + + private final List
sections; + + public Sections(List
sections) { + validateSections(sections); + this.sections = sections.stream() + .distinct() + .toList(); + } + + private void validateSections(List
sections) { + if (sections == null || sections.isEmpty()) { + throw new SectionNotExistException(); + } + } + + public List getSectionIds() { + return sections.stream() + .map(Section::getId) + .toList(); + } + + public Set getQuestionIds() { + return sections.stream() + .flatMap(section -> section.getQuestionIds().stream()) + .collect(Collectors.toSet()); + } + + public List getInvisibleSectionIds(List selectedOptionIds) { + return sections.stream() + .filter(section -> !section.isVisibleBySelectedOptionIds(selectedOptionIds)) + .map(Section::getId) + .toList(); + } + + public List getInvisibleSectionIds() { + return sections.stream() + .filter(section -> !section.isAlwaysVisible()) + .map(Section::getId) + .toList(); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/structured/StructuredTemplate.java b/backend/src/main/java/reviewme/template/domain/structured/StructuredTemplate.java new file mode 100644 index 000000000..fac5ddfb1 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/structured/StructuredTemplate.java @@ -0,0 +1,31 @@ +package reviewme.template.domain.structured; + +import lombok.Getter; +import reviewme.template.domain.Template; + +@Getter +public class StructuredTemplate { + + private final Template template; + private final Sections sections; + private final Questions questions; + private final OptionGroups optionGroups; + private final OptionItems optionItems; + + StructuredTemplate(Template template, Sections sections, Questions questions, OptionGroups optionGroups, + OptionItems optionItems) { + this.template = template; + this.sections = sections; + this.questions = questions; + this.optionGroups = optionGroups; + this.optionItems = optionItems; + } + + StructuredTemplate(Template template, Sections sections, Questions questions) { + this(template, sections, questions, null, null); + } + + public long getTemplateId() { + return template.getId(); + } +} diff --git a/backend/src/main/java/reviewme/template/domain/structured/StructuredTemplateFinder.java b/backend/src/main/java/reviewme/template/domain/structured/StructuredTemplateFinder.java new file mode 100644 index 000000000..697f644d0 --- /dev/null +++ b/backend/src/main/java/reviewme/template/domain/structured/StructuredTemplateFinder.java @@ -0,0 +1,41 @@ +package reviewme.template.domain.structured; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import reviewme.template.domain.Template; +import reviewme.template.repository.OptionGroupRepository; +import reviewme.template.repository.OptionItemRepository; +import reviewme.template.repository.QuestionRepository; +import reviewme.template.repository.SectionRepository; +import reviewme.template.repository.TemplateRepository; +import reviewme.template.service.exception.TemplateNotFoundException; + +@Component +@RequiredArgsConstructor +public class StructuredTemplateFinder { + + private final TemplateRepository templateRepository; + private final SectionRepository sectionRepository; + private final QuestionRepository questionRepository; + private final OptionGroupRepository optionGroupRepository; + private final OptionItemRepository optionItemRepository; + + public StructuredTemplate find(long templateId) { + Template template = templateRepository.findById(templateId) + .orElseThrow(() -> new TemplateNotFoundException(templateId)); + + Sections sections = new Sections(sectionRepository.findAllByTemplateId(template.getId())); + Questions questions = new Questions(questionRepository.findAllByTemplatedId(template.getId())); + + if (questions.hasCheckboxQuestion()) { + List questionIds = questions.getQuestionIds(); + OptionGroups optionGroups = new OptionGroups(optionGroupRepository.findAllByQuestionIds(questionIds)); + OptionItems optionItems = new OptionItems(optionItemRepository.findAllByQuestionIds(questionIds)); + + return new StructuredTemplate(template, sections, questions, optionGroups, optionItems); + } + + return new StructuredTemplate(template, sections, questions); + } +} diff --git a/backend/src/main/java/reviewme/template/repository/SectionRepository.java b/backend/src/main/java/reviewme/template/repository/SectionRepository.java index d40fa5a24..74b7a5d8a 100644 --- a/backend/src/main/java/reviewme/template/repository/SectionRepository.java +++ b/backend/src/main/java/reviewme/template/repository/SectionRepository.java @@ -12,8 +12,8 @@ public interface SectionRepository extends JpaRepository { @Query(""" SELECT s FROM Section s - JOIN TemplateSection ts - ON s.id = ts.sectionId + JOIN FETCH s.questionIds + JOIN TemplateSection ts ON s.id = ts.sectionId WHERE ts.templateId = :templateId ORDER BY s.position ASC """) diff --git a/backend/src/main/java/reviewme/template/service/StructuredTemplateService.java b/backend/src/main/java/reviewme/template/service/StructuredTemplateService.java new file mode 100644 index 000000000..c0bca48d2 --- /dev/null +++ b/backend/src/main/java/reviewme/template/service/StructuredTemplateService.java @@ -0,0 +1,19 @@ +package reviewme.template.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import reviewme.template.domain.structured.StructuredTemplate; +import reviewme.template.domain.structured.StructuredTemplateFinder; + +@Service +@RequiredArgsConstructor +public class StructuredTemplateService { + + private final StructuredTemplateFinder structuredTemplateFinder; + + @Transactional + public StructuredTemplate getStructuredTemplateById(long templateId) { + return structuredTemplateFinder.find(templateId); + } +} diff --git a/backend/src/main/java/reviewme/template/service/mapper/TemplateMapper.java b/backend/src/main/java/reviewme/template/service/mapper/TemplateMapper.java index 5225bd7e6..19a737b08 100644 --- a/backend/src/main/java/reviewme/template/service/mapper/TemplateMapper.java +++ b/backend/src/main/java/reviewme/template/service/mapper/TemplateMapper.java @@ -4,17 +4,15 @@ import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Component; +import reviewme.reviewgroup.domain.ReviewGroup; import reviewme.template.domain.OptionGroup; import reviewme.template.domain.OptionItem; import reviewme.template.domain.Question; +import reviewme.template.domain.Section; +import reviewme.template.domain.Template; import reviewme.template.repository.OptionGroupRepository; import reviewme.template.repository.OptionItemRepository; import reviewme.template.repository.QuestionRepository; -import reviewme.reviewgroup.domain.ReviewGroup; -import reviewme.template.domain.Section; -import reviewme.template.domain.SectionQuestion; -import reviewme.template.domain.Template; -import reviewme.template.domain.TemplateSection; import reviewme.template.repository.SectionRepository; import reviewme.template.repository.TemplateRepository; import reviewme.template.service.dto.response.OptionGroupResponse; @@ -31,8 +29,6 @@ @RequiredArgsConstructor public class TemplateMapper { - public static final String REVIEWEE_NAME_PLACEHOLDER = "{revieweeName}"; - private final TemplateRepository templateRepository; private final SectionRepository sectionRepository; private final QuestionRepository questionRepository; @@ -48,7 +44,7 @@ public TemplateResponse mapToTemplateResponse(ReviewGroup reviewGroup) { List sectionResponses = template.getSectionIds() .stream() - .map(this::mapToSectionResponse) + .map(sectionId -> mapToSectionResponse(template.getId(), sectionId)) .toList(); return new TemplateResponse( @@ -59,14 +55,12 @@ public TemplateResponse mapToTemplateResponse(ReviewGroup reviewGroup) { ); } - private SectionResponse mapToSectionResponse(TemplateSection templateSection) { - Section section = sectionRepository.findById(templateSection.getSectionId()) - .orElseThrow(() -> new SectionInTemplateNotFoundException( - templateSection.getTemplateId(), templateSection.getSectionId()) - ); + private SectionResponse mapToSectionResponse(long templateId, long sectionId) { + Section section = sectionRepository.findById(sectionId) + .orElseThrow(() -> new SectionInTemplateNotFoundException(templateId, sectionId)); List questionResponses = section.getQuestionIds() .stream() - .map(this::mapToQuestionResponse) + .map(questionId -> mapToQuestionResponse(section.getId(), questionId)) .toList(); return new SectionResponse( @@ -79,11 +73,9 @@ private SectionResponse mapToSectionResponse(TemplateSection templateSection) { ); } - private QuestionResponse mapToQuestionResponse(SectionQuestion sectionQuestion) { - Question question = questionRepository.findById(sectionQuestion.getQuestionId()) - .orElseThrow(() -> new QuestionInSectionNotFoundException( - sectionQuestion.getSectionId(), sectionQuestion.getQuestionId()) - ); + private QuestionResponse mapToQuestionResponse(long sectionId, long questionId) { + Question question = questionRepository.findById(questionId) + .orElseThrow(() -> new QuestionInSectionNotFoundException(sectionId, questionId)); OptionGroupResponse optionGroupResponse = optionGroupRepository.findByQuestionId(question.getId()) .map(this::mapToOptionGroupResponse) .orElse(null); diff --git a/backend/src/test/java/reviewme/review/domain/abstraction/ReviewTest.java b/backend/src/test/java/reviewme/review/domain/abstraction/ReviewTest.java index 47ead260f..35901fcc3 100644 --- a/backend/src/test/java/reviewme/review/domain/abstraction/ReviewTest.java +++ b/backend/src/test/java/reviewme/review/domain/abstraction/ReviewTest.java @@ -45,16 +45,16 @@ class ReviewTest { void ๋ฆฌ๋ทฐ์—_ํŠน์ •_์งˆ๋ฌธ์—_๋Œ€ํ•œ_๋‹ต๋ณ€์ด_์žˆ๋Š”์ง€_์—ฌ๋ถ€๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { // given long textQuestionId = 1L; - long checkBoxQuestionId = 2L; + long checkboxQuestionId = 2L; TextAnswer textAnswer = new TextAnswer(textQuestionId, "๋‹ต๋ณ€"); - CheckboxAnswer checkboxAnswer = new CheckboxAnswer(checkBoxQuestionId, List.of(1L)); + CheckboxAnswer checkboxAnswer = new CheckboxAnswer(checkboxQuestionId, List.of(1L)); Review review = new Review(1L, 1L, List.of(textAnswer, checkboxAnswer)); // when, then assertAll( () -> assertThat(review.hasAnsweredQuestion(textQuestionId)).isTrue(), - () -> assertThat(review.hasAnsweredQuestion(checkBoxQuestionId)).isTrue() + () -> assertThat(review.hasAnsweredQuestion(checkboxQuestionId)).isTrue() ); } } diff --git a/backend/src/test/java/reviewme/review/service/validator/CheckboxTypedAnswerValidatorTest.java b/backend/src/test/java/reviewme/review/service/validator/CheckboxTypedAnswerValidatorTest.java index 57e7dfd4b..4612f4624 100644 --- a/backend/src/test/java/reviewme/review/service/validator/CheckboxTypedAnswerValidatorTest.java +++ b/backend/src/test/java/reviewme/review/service/validator/CheckboxTypedAnswerValidatorTest.java @@ -15,7 +15,7 @@ import reviewme.template.repository.OptionItemRepository; import reviewme.template.repository.QuestionRepository; import reviewme.review.domain.CheckboxAnswer; -import reviewme.review.service.exception.CheckBoxAnswerIncludedNotProvidedOptionItemException; +import reviewme.review.service.exception.CheckboxAnswerIncludedNotProvidedOptionItemException; import reviewme.review.service.exception.OptionGroupNotFoundByQuestionIdException; import reviewme.review.service.exception.SelectedOptionItemCountOutOfRangeException; import reviewme.review.service.exception.SubmittedQuestionNotFoundException; @@ -25,7 +25,7 @@ class CheckboxTypedAnswerValidatorTest { @Autowired - private CheckboxTypedAnswerValidator checkBoxAnswerValidator; + private CheckboxTypedAnswerValidator checkboxAnswerValidator; @Autowired private QuestionRepository questionRepository; @@ -43,7 +43,7 @@ class CheckboxTypedAnswerValidatorTest { CheckboxAnswer checkboxAnswer = new CheckboxAnswer(notSavedQuestionId, List.of(1L)); // when, then - assertThatCode(() -> checkBoxAnswerValidator.validate(checkboxAnswer)) + assertThatCode(() -> checkboxAnswerValidator.validate(checkboxAnswer)) .isInstanceOf(SubmittedQuestionNotFoundException.class); } @@ -54,7 +54,7 @@ class CheckboxTypedAnswerValidatorTest { CheckboxAnswer checkboxAnswer = new CheckboxAnswer(savedQuestion.getId(), List.of(1L)); // when, then - assertThatCode(() -> checkBoxAnswerValidator.validate(checkboxAnswer)) + assertThatCode(() -> checkboxAnswerValidator.validate(checkboxAnswer)) .isInstanceOf(OptionGroupNotFoundByQuestionIdException.class); } @@ -69,8 +69,8 @@ class CheckboxTypedAnswerValidatorTest { List.of(savedOptionItem.getId() + 1L)); // when, then - assertThatCode(() -> checkBoxAnswerValidator.validate(checkboxAnswer)) - .isInstanceOf(CheckBoxAnswerIncludedNotProvidedOptionItemException.class); + assertThatCode(() -> checkboxAnswerValidator.validate(checkboxAnswer)) + .isInstanceOf(CheckboxAnswerIncludedNotProvidedOptionItemException.class); } @Test @@ -86,7 +86,7 @@ class CheckboxTypedAnswerValidatorTest { List.of(savedOptionItem1.getId())); // when, then - assertThatCode(() -> checkBoxAnswerValidator.validate(checkboxAnswer)) + assertThatCode(() -> checkboxAnswerValidator.validate(checkboxAnswer)) .isInstanceOf(SelectedOptionItemCountOutOfRangeException.class); } @@ -104,7 +104,7 @@ class CheckboxTypedAnswerValidatorTest { savedQuestion.getId(), List.of(savedOptionItem1.getId(), savedOptionItem2.getId())); // when, then - assertThatCode(() -> checkBoxAnswerValidator.validate(checkboxAnswer)) + assertThatCode(() -> checkboxAnswerValidator.validate(checkboxAnswer)) .isInstanceOf(SelectedOptionItemCountOutOfRangeException.class); } } diff --git a/backend/src/test/java/reviewme/reviewgroup/service/ReviewGroupServiceTest.java b/backend/src/test/java/reviewme/reviewgroup/service/ReviewGroupServiceTest.java index 6bdc22f44..ee57d3169 100644 --- a/backend/src/test/java/reviewme/reviewgroup/service/ReviewGroupServiceTest.java +++ b/backend/src/test/java/reviewme/reviewgroup/service/ReviewGroupServiceTest.java @@ -46,7 +46,7 @@ class ReviewGroupServiceTest { @Test void ์ฝ”๋“œ๊ฐ€_์ค‘๋ณต๋˜๋Š”_๊ฒฝ์šฐ_๋‹ค์‹œ_์ƒ์„ฑํ•œ๋‹ค() { // given - templateRepository.save(ํ…œํ”Œ๋ฆฟ(List.of())); + templateRepository.save(ํ…œํ”Œ๋ฆฟ(List.of(1L))); reviewGroupRepository.save(๋ฆฌ๋ทฐ_๊ทธ๋ฃน("0000", "1111")); given(randomCodeGenerator.generate(anyInt())) .willReturn("0000") // ReviewRequestCode diff --git a/backend/src/test/java/reviewme/template/domain/SectionTest.java b/backend/src/test/java/reviewme/template/domain/SectionTest.java index 0e3f1339b..b139f0ee5 100644 --- a/backend/src/test/java/reviewme/template/domain/SectionTest.java +++ b/backend/src/test/java/reviewme/template/domain/SectionTest.java @@ -1,14 +1,74 @@ package reviewme.template.domain; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; import static reviewme.fixture.SectionFixture.์กฐ๊ฑด๋ถ€๋กœ_๋ณด์ด๋Š”_์„น์…˜; import static reviewme.fixture.SectionFixture.ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜; import java.util.List; import org.junit.jupiter.api.Test; +import reviewme.template.domain.exception.DuplicateQuestionIdException; +import reviewme.template.domain.exception.QuestionIdsNotExistException; class SectionTest { + @Test + void ์„น์…˜_์ƒ์„ฑ์‹œ_์งˆ๋ฌธID๊ฐ€_์—†์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given, when, then + assertAll( + () -> assertThatThrownBy(() -> ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(null)).isInstanceOf(QuestionIdsNotExistException.class), + () -> assertThatThrownBy(() -> ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(List.of())).isInstanceOf(QuestionIdsNotExistException.class) + ); + } + + @Test + void ์„น์…˜_์ƒ์„ฑ์‹œ_์ค‘๋ณต๋œ_์งˆ๋ฌธID๊ฐ€_์žˆ์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + List questionIds = List.of(1L, 1L, 2L, 3L); + + // when, then + assertThatThrownBy(() -> ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(questionIds)) + .isInstanceOf(DuplicateQuestionIdException.class); + } + + @Test + void ์„น์…˜์˜_์งˆ๋ฌธID๋“ค์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + List questionIds = List.of(1L, 2L, 3L); + Section section = ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(questionIds); + + // when + List actual = section.getQuestionIds(); + + // then + assertThat(actual).containsExactlyInAnyOrderElementsOf(questionIds); + } + + @Test + void ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜์ผ_๊ฒฝ์šฐ_ture๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + Section section = ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(List.of(1L)); + + // when + boolean actual = section.isAlwaysVisible(); + + // then + assertThat(actual).isTrue(); + } + + @Test + void ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜์ด_์•„๋‹_๊ฒฝ์šฐ_false๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + Section section = ์กฐ๊ฑด๋ถ€๋กœ_๋ณด์ด๋Š”_์„น์…˜(List.of(1L), 2L); + + // when + boolean actual = section.isAlwaysVisible(); + + // then + assertThat(actual).isFalse(); + } + @Test void ์กฐ๊ฑด_์˜ต์…˜์„_์„ ํƒํ•˜๋ฉด_์„น์…˜์ด_๋ณด์ธ๋‹ค() { // given diff --git a/backend/src/test/java/reviewme/template/domain/TemplateTest.java b/backend/src/test/java/reviewme/template/domain/TemplateTest.java new file mode 100644 index 000000000..c57127268 --- /dev/null +++ b/backend/src/test/java/reviewme/template/domain/TemplateTest.java @@ -0,0 +1,45 @@ +package reviewme.template.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static reviewme.fixture.TemplateFixture.ํ…œํ”Œ๋ฆฟ; + +import java.util.List; +import org.junit.jupiter.api.Test; +import reviewme.template.domain.exception.DuplicateSectionIdException; +import reviewme.template.domain.exception.SectionIdsNotExistException; + +class TemplateTest { + + @Test + void ํ…œํ”Œ๋ฆฟ_์ƒ์„ฑ์‹œ_์„น์…˜ID๊ฐ€_์—†์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given, when, then + assertAll( + () -> assertThatThrownBy(() -> ํ…œํ”Œ๋ฆฟ(null)).isInstanceOf(SectionIdsNotExistException.class), + () -> assertThatThrownBy(() -> ํ…œํ”Œ๋ฆฟ(List.of())).isInstanceOf(SectionIdsNotExistException.class) + ); + } + + @Test + void ํ…œํ”Œ๋ฆฟ_์ƒ์„ฑ์‹œ_์ค‘๋ณต๋œ_์„น์…˜ID๊ฐ€_์žˆ์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + List sectionIds = List.of(1L, 1L, 2L, 3L); + + // when, then + assertThatThrownBy(() -> ํ…œํ”Œ๋ฆฟ(sectionIds)).isInstanceOf(DuplicateSectionIdException.class); + } + + @Test + void ํ…œํ”Œ๋ฆฟ์˜_์„น์…˜ID๋“ค์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + List sectionIds = List.of(1L, 2L, 3L); + Template template = ํ…œํ”Œ๋ฆฟ(sectionIds); + + // when + List actual = template.getSectionIds(); + + // then + assertThat(actual).containsExactlyInAnyOrderElementsOf(sectionIds); + } +} diff --git a/backend/src/test/java/reviewme/template/domain/structured/OptionGroupsTest.java b/backend/src/test/java/reviewme/template/domain/structured/OptionGroupsTest.java new file mode 100644 index 000000000..7946e13e5 --- /dev/null +++ b/backend/src/test/java/reviewme/template/domain/structured/OptionGroupsTest.java @@ -0,0 +1,67 @@ +package reviewme.template.domain.structured; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static reviewme.fixture.OptionGroupFixture.์„ ํƒ์ง€_๊ทธ๋ฃน; + +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import reviewme.support.ServiceTest; +import reviewme.template.domain.OptionGroup; +import reviewme.template.domain.exception.OptionGroupNotExistException; +import reviewme.template.repository.OptionGroupRepository; + +@ServiceTest +class OptionGroupsTest { + + @Autowired + private OptionGroupRepository optionGroupRepository; + + @Test + void ์กด์žฌํ•˜์ง€_์•Š๋Š”_์˜ต์…˜๊ทธ๋ฃน์œผ๋กœ_์ƒ์„ฑํ• _๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given, when, then + assertAll( + () -> assertThatThrownBy(() -> new OptionGroups(null)) + .isInstanceOf(OptionGroupNotExistException.class), + () -> assertThatThrownBy(() -> new OptionGroups(List.of())) + .isInstanceOf(OptionGroupNotExistException.class) + ); + } + + @Test + void ์˜ต์…˜๊ทธ๋ฃนID๋“ค์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + OptionGroup optionGroup1 = optionGroupRepository.save(์„ ํƒ์ง€_๊ทธ๋ฃน(1L)); + OptionGroup optionGroup2 = optionGroupRepository.save(์„ ํƒ์ง€_๊ทธ๋ฃน(1L)); + OptionGroup optionGroup3 = optionGroupRepository.save(์„ ํƒ์ง€_๊ทธ๋ฃน(1L)); + + OptionGroups optionGroups = new OptionGroups(List.of(optionGroup1, optionGroup2, optionGroup3)); + + // when + List actual = optionGroups.getOptionGroupIds(); + + // then + assertThat(actual).containsExactlyInAnyOrder(optionGroup1.getId(), optionGroup2.getId(), optionGroup3.getId()); + } + + @Test + void ์˜ต์…˜๊ทธ๋ฃน์˜_์งˆ๋ฌธID๋“ค์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + long questionId1 = 1L; + long questionId2 = 2L; + OptionGroup optionGroup1 = optionGroupRepository.save(์„ ํƒ์ง€_๊ทธ๋ฃน(questionId1)); + OptionGroup optionGroup2 = optionGroupRepository.save(์„ ํƒ์ง€_๊ทธ๋ฃน(questionId2)); + OptionGroup optionGroup3 = optionGroupRepository.save(์„ ํƒ์ง€_๊ทธ๋ฃน(questionId2)); + + OptionGroups optionGroups = new OptionGroups(List.of(optionGroup1, optionGroup2, optionGroup3)); + + // when + Set actual = optionGroups.getQuestionIds(); + + // then + assertThat(actual).containsExactlyInAnyOrder(questionId1, questionId2); + } +} diff --git a/backend/src/test/java/reviewme/template/domain/structured/OptionItemsTest.java b/backend/src/test/java/reviewme/template/domain/structured/OptionItemsTest.java new file mode 100644 index 000000000..7cd441351 --- /dev/null +++ b/backend/src/test/java/reviewme/template/domain/structured/OptionItemsTest.java @@ -0,0 +1,67 @@ +package reviewme.template.domain.structured; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static reviewme.fixture.OptionItemFixture.์„ ํƒ์ง€; + +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import reviewme.support.ServiceTest; +import reviewme.template.domain.OptionItem; +import reviewme.template.domain.exception.OptionItemNotExistException; +import reviewme.template.repository.OptionItemRepository; + +@ServiceTest +class OptionItemsTest { + + @Autowired + private OptionItemRepository optionItemRepository; + + @Test + void ์กด์žฌํ•˜์ง€_์•Š๋Š”_์˜ต์…˜์•„์ดํ…œ์œผ๋กœ_์ƒ์„ฑํ• _๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given, when, then + assertAll( + () -> assertThatThrownBy(() -> new OptionItems(null)) + .isInstanceOf(OptionItemNotExistException.class), + () -> assertThatThrownBy(() -> new OptionItems(List.of())) + .isInstanceOf(OptionItemNotExistException.class) + ); + } + + @Test + void ์˜ต์…˜์•„์ดํ…œID๋“ค์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + OptionItem optionItem1 = optionItemRepository.save(์„ ํƒ์ง€(1L)); + OptionItem optionItem2 = optionItemRepository.save(์„ ํƒ์ง€(1L)); + OptionItem optionItem3 = optionItemRepository.save(์„ ํƒ์ง€(1L)); + + OptionItems optionItems = new OptionItems(List.of(optionItem1, optionItem2, optionItem3)); + + // when + List actual = optionItems.getOptionItemIds(); + + // then + assertThat(actual).containsExactlyInAnyOrder(optionItem1.getId(), optionItem2.getId(), optionItem3.getId()); + } + + @Test + void ์˜ต์…˜์•„์ดํ…œ์˜_์˜ต์…˜๊ทธ๋ฃนID๋“ค์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + long optionGroupId1 = 1L; + long optionGroupId2 = 2L; + OptionItem optionItem1 = optionItemRepository.save(์„ ํƒ์ง€(optionGroupId1)); + OptionItem optionItem2 = optionItemRepository.save(์„ ํƒ์ง€(optionGroupId1)); + OptionItem optionItem3 = optionItemRepository.save(์„ ํƒ์ง€(optionGroupId2)); + + OptionItems optionItems = new OptionItems(List.of(optionItem1, optionItem2, optionItem3)); + + // when + Set actual = optionItems.getOptionGroupIds(); + + // then + assertThat(actual).containsExactlyInAnyOrder(optionGroupId1, optionGroupId2); + } +} diff --git a/backend/src/test/java/reviewme/template/domain/structured/QuestionsTest.java b/backend/src/test/java/reviewme/template/domain/structured/QuestionsTest.java new file mode 100644 index 000000000..07fede9d9 --- /dev/null +++ b/backend/src/test/java/reviewme/template/domain/structured/QuestionsTest.java @@ -0,0 +1,84 @@ +package reviewme.template.domain.structured; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static reviewme.fixture.QuestionFixture.์„œ์ˆ ํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ; +import static reviewme.fixture.QuestionFixture.์„ ํƒํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import reviewme.support.ServiceTest; +import reviewme.template.domain.Question; +import reviewme.template.domain.exception.QuestionNotExistException; +import reviewme.template.repository.QuestionRepository; + +@ServiceTest +class QuestionsTest { + + @Autowired + private QuestionRepository questionRepository; + + @Test + void ์กด์žฌํ•˜์ง€_์•Š๋Š”_์งˆ๋ฌธ์œผ๋กœ_์ƒ์„ฑํ• _๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given, when, then + assertAll( + () -> assertThatThrownBy(() -> new Questions(null)).isInstanceOf(QuestionNotExistException.class), + () -> assertThatThrownBy(() -> new Questions(List.of())).isInstanceOf(QuestionNotExistException.class) + ); + } + + @Test + void ์งˆ๋ฌธID๋“ค์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + Question question1 = questionRepository.save(์„œ์ˆ ํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + Question question2 = questionRepository.save(์„œ์ˆ ํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + Question question3 = questionRepository.save(์„œ์ˆ ํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + + Questions questions = new Questions(List.of(question1, question2, question3)); + + // when + List actual = questions.getQuestionIds(); + + // then + assertThat(actual).containsExactlyInAnyOrder(question1.getId(), question2.getId(), question3.getId()); + } + + @Test + void ์ฒดํฌ๋ฐ•์Šคํ˜•_์งˆ๋ฌธID๋“ค์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + Question textQuestion = questionRepository.save(์„œ์ˆ ํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + Question checkboxQuestion1 = questionRepository.save(์„ ํƒํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + Question checkboxQuestion2 = questionRepository.save(์„ ํƒํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + + Questions questions = new Questions(List.of(textQuestion, checkboxQuestion1, checkboxQuestion2)); + + // when + List actual = questions.getCheckboxQuestionIds(); + + // then + assertThat(actual).containsExactlyInAnyOrder(checkboxQuestion1.getId(), checkboxQuestion2.getId()); + } + + @Test + void ์ฒดํฌ๋ฐ•์Šค_์งˆ๋ฌธ์ด_์žˆ๋Š”์ง€_ํ™•์ธํ•œ๋‹ค() { + // given + Question textQuestion = questionRepository.save(์„œ์ˆ ํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + Question checkboxQuestion1 = questionRepository.save(์„ ํƒํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + Question checkboxQuestion2 = questionRepository.save(์„ ํƒํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + + Questions questions1 = new Questions(List.of(textQuestion, checkboxQuestion1, checkboxQuestion2)); + Questions questions2 = new Questions(List.of(textQuestion)); + + // when + boolean actual1 = questions1.hasCheckboxQuestion(); + boolean actual2 = questions2.hasCheckboxQuestion(); + + // then + assertAll( + () -> assertThat(actual1).isTrue(), + () -> assertThat(actual2).isFalse() + ); + } +} diff --git a/backend/src/test/java/reviewme/template/domain/structured/SectionsTest.java b/backend/src/test/java/reviewme/template/domain/structured/SectionsTest.java new file mode 100644 index 000000000..3920bbaa2 --- /dev/null +++ b/backend/src/test/java/reviewme/template/domain/structured/SectionsTest.java @@ -0,0 +1,102 @@ +package reviewme.template.domain.structured; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.*; +import static reviewme.fixture.SectionFixture.์กฐ๊ฑด๋ถ€๋กœ_๋ณด์ด๋Š”_์„น์…˜; +import static reviewme.fixture.SectionFixture.ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜; + +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import reviewme.support.ServiceTest; +import reviewme.template.domain.Section; +import reviewme.template.domain.exception.SectionNotExistException; +import reviewme.template.repository.SectionRepository; + +@ServiceTest +class SectionsTest { + + @Autowired + private SectionRepository sectionRepository; + + @Test + void ์กด์žฌํ•˜์ง€_์•Š๋Š”_์„น์…˜์œผ๋กœ_์ƒ์„ฑํ• _๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given, when, then + assertAll( + () -> assertThatThrownBy(() -> new Sections(null)).isInstanceOf(SectionNotExistException.class), + () -> assertThatThrownBy(() -> new Sections(List.of())).isInstanceOf(SectionNotExistException.class) + ); + } + + @Test + void ์„น์…˜ID๋“ค์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + Section section1 = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(List.of(1L))); + Section section2 = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(List.of(1L))); + Section section3 = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(List.of(1L))); + + Sections sections = new Sections(List.of(section1, section2, section3)); + + // when + List actual = sections.getSectionIds(); + + // then + assertThat(actual).containsExactlyInAnyOrder(section1.getId(),section2.getId(), section3.getId()); + } + + @Test + void ์„น์…˜์˜_์งˆ๋ฌธID๋“ค์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + long questionId1 = 1L; + long questionId2 = 2L; + Section section1 = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(List.of(questionId1))); + Section section2 = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(List.of(questionId2))); + Section section3 = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(List.of(questionId2))); + + Sections sections = new Sections(List.of(section1, section2, section3)); + + // when + Set actual = sections.getQuestionIds(); + + // then + assertThat(actual).containsExactlyInAnyOrder(questionId1, questionId2); + } + + @Test + void ์„ ํƒํ˜•_์˜ต์…˜๋“ค์ด_์ฃผ์–ด์งˆ๋•Œ_๋…ธ์ถœ๋˜์ง€_์•Š๋Š”_์„น์…˜์˜_ID๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + long optionItemId1 = 1L; + long optionItemId2 = 2L; + Section alwaysVisibleSection = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(List.of(1L))); + Section conditionalSection1 = sectionRepository.save(์กฐ๊ฑด๋ถ€๋กœ_๋ณด์ด๋Š”_์„น์…˜(List.of(1L), optionItemId1)); + Section conditionalSection2 = sectionRepository.save(์กฐ๊ฑด๋ถ€๋กœ_๋ณด์ด๋Š”_์„น์…˜(List.of(1L), optionItemId2)); + + Sections sections = new Sections(List.of(alwaysVisibleSection, conditionalSection1, conditionalSection2)); + + // when + List actual = sections.getInvisibleSectionIds(List.of(optionItemId1)); + + // then + assertThat(actual).containsExactlyInAnyOrder(conditionalSection2.getId()); + } + + @Test + void ์„ ํƒํ˜•_์˜ต์…˜๋“ค์ด_์ฃผ์–ด์ง€์ง€_์•Š์„๋•Œ_๋…ธ์ถœ๋˜์ง€_์•Š๋Š”_์„น์…˜์˜_ID๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + long optionItemId1 = 1L; + long optionItemId2 = 2L; + Section alwaysVisibleSection = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(List.of(1L))); + Section conditionalSection1 = sectionRepository.save(์กฐ๊ฑด๋ถ€๋กœ_๋ณด์ด๋Š”_์„น์…˜(List.of(1L), optionItemId1)); + Section conditionalSection2 = sectionRepository.save(์กฐ๊ฑด๋ถ€๋กœ_๋ณด์ด๋Š”_์„น์…˜(List.of(1L), optionItemId2)); + + Sections sections = new Sections(List.of(alwaysVisibleSection, conditionalSection1, conditionalSection2)); + + // when + List actual = sections.getInvisibleSectionIds(); + + // then + assertThat(actual).containsExactlyInAnyOrder(conditionalSection1.getId(), conditionalSection2.getId()); + } +} diff --git a/backend/src/test/java/reviewme/template/domain/structured/StructuredTemplateFinderTest.java b/backend/src/test/java/reviewme/template/domain/structured/StructuredTemplateFinderTest.java new file mode 100644 index 000000000..e827b125d --- /dev/null +++ b/backend/src/test/java/reviewme/template/domain/structured/StructuredTemplateFinderTest.java @@ -0,0 +1,119 @@ +package reviewme.template.domain.structured; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static reviewme.fixture.OptionGroupFixture.์„ ํƒ์ง€_๊ทธ๋ฃน; +import static reviewme.fixture.OptionItemFixture.์„ ํƒ์ง€; +import static reviewme.fixture.QuestionFixture.์„œ์ˆ ํ˜•_์˜ต์…˜_์งˆ๋ฌธ; +import static reviewme.fixture.QuestionFixture.์„œ์ˆ ํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ; +import static reviewme.fixture.QuestionFixture.์„ ํƒํ˜•_์˜ต์…˜_์งˆ๋ฌธ; +import static reviewme.fixture.QuestionFixture.์„ ํƒํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ; +import static reviewme.fixture.SectionFixture.์กฐ๊ฑด๋ถ€๋กœ_๋ณด์ด๋Š”_์„น์…˜; +import static reviewme.fixture.SectionFixture.ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜; +import static reviewme.fixture.TemplateFixture.ํ…œํ”Œ๋ฆฟ; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import reviewme.support.ServiceTest; +import reviewme.template.domain.OptionGroup; +import reviewme.template.domain.OptionItem; +import reviewme.template.domain.Question; +import reviewme.template.domain.Section; +import reviewme.template.domain.Template; +import reviewme.template.repository.OptionGroupRepository; +import reviewme.template.repository.OptionItemRepository; +import reviewme.template.repository.QuestionRepository; +import reviewme.template.repository.SectionRepository; +import reviewme.template.repository.TemplateRepository; +import reviewme.template.service.exception.TemplateNotFoundException; + +@ServiceTest +class StructuredTemplateFinderTest { + + @Autowired + private StructuredTemplateFinder templateCreator; + + @Autowired + private TemplateRepository templateRepository; + + @Autowired + private SectionRepository sectionRepository; + + @Autowired + private QuestionRepository questionRepository; + + @Autowired + private OptionGroupRepository optionGroupRepository; + + @Autowired + private OptionItemRepository optionItemRepository; + + @Test + void ์ฒดํฌ๋ฐ•์Šค_ํƒ€์ž…์˜_์งˆ๋ฌธ์ด_ํฌํ•จ๋œ_๊ตฌ์กฐํ™”๋œ_ํ…œํ”Œ๋ฆฟ์„_์ฐพ๋Š”๋‹ค() { + // given + Question requiredCheckboxQuestion = questionRepository.save(์„ ํƒํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + Question optionalCheckboxQuestion = questionRepository.save(์„ ํƒํ˜•_์˜ต์…˜_์งˆ๋ฌธ()); + Question requiredTextQuestion = questionRepository.save(์„œ์ˆ ํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + Question optionalTextQuestion = questionRepository.save(์„œ์ˆ ํ˜•_์˜ต์…˜_์งˆ๋ฌธ()); + + OptionGroup optionGroup1 = optionGroupRepository.save(์„ ํƒ์ง€_๊ทธ๋ฃน(requiredCheckboxQuestion.getId())); + OptionItem optionItem1 = optionItemRepository.save(์„ ํƒ์ง€(optionGroup1.getId())); + OptionItem optionItem2 = optionItemRepository.save(์„ ํƒ์ง€(optionGroup1.getId())); + + OptionGroup optionGroup2 = optionGroupRepository.save(์„ ํƒ์ง€_๊ทธ๋ฃน(optionalCheckboxQuestion.getId())); + OptionItem optionItem3 = optionItemRepository.save(์„ ํƒ์ง€(optionGroup2.getId())); + OptionItem optionItem4 = optionItemRepository.save(์„ ํƒ์ง€(optionGroup2.getId())); + + Section section1 = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜( + List.of(requiredCheckboxQuestion.getId(), optionalTextQuestion.getId()))); + Section section2 = sectionRepository.save(์กฐ๊ฑด๋ถ€๋กœ_๋ณด์ด๋Š”_์„น์…˜( + List.of(optionalCheckboxQuestion.getId(), requiredTextQuestion.getId()), optionItem1.getId())); + Section section3 = sectionRepository.save(์กฐ๊ฑด๋ถ€๋กœ_๋ณด์ด๋Š”_์„น์…˜( + List.of(optionalCheckboxQuestion.getId(), requiredTextQuestion.getId()), optionItem2.getId())); + + Template template = templateRepository.save(ํ…œํ”Œ๋ฆฟ( + List.of(section1.getId(), section2.getId(), section3.getId()))); + + // when, then + assertDoesNotThrow(() -> templateCreator.find(template.getId())); + } + + @Test + void ์ฒดํฌ๋ฐ•์Šค_ํƒ€์ž…์˜_์งˆ๋ฌธ์ด_์—†๋Š”_๊ตฌ์กฐํ™”๋œ_ํ…œํ”Œ๋ฆฟ์„_์ฐพ๋Š”๋‹ค() { + // given + Question requiredQuestion1 = questionRepository.save(์„œ์ˆ ํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + Question requiredQuestion2 = questionRepository.save(์„œ์ˆ ํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + Question optionalQuestion = questionRepository.save(์„œ์ˆ ํ˜•_์˜ต์…˜_์งˆ๋ฌธ()); + + Section section1 = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜( + List.of(requiredQuestion1.getId(), optionalQuestion.getId()))); + Section section2 = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜( + List.of(requiredQuestion2.getId(), optionalQuestion.getId()))); + + Template template = templateRepository.save(ํ…œํ”Œ๋ฆฟ(List.of(section1.getId(), section2.getId()))); + + // when, then + assertDoesNotThrow(() -> templateCreator.find(template.getId())); + } + + @Test + void ๊ตฌ์กฐํ™”๋œ_ํ…œํ”Œ๋ฆฟ_์ƒ์„ฑ์‹œ_ํ…œํ”Œ๋ฆฟ์ด_์กด์žฌํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + Question checkboxQuestion = questionRepository.save(์„ ํƒํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + Question textQuestion = questionRepository.save(์„œ์ˆ ํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + + OptionGroup optionGroup = optionGroupRepository.save(์„ ํƒ์ง€_๊ทธ๋ฃน(checkboxQuestion.getId())); + OptionItem optionItem1 = optionItemRepository.save(์„ ํƒ์ง€(optionGroup.getId())); + OptionItem optionItem2 = optionItemRepository.save(์„ ํƒ์ง€(optionGroup.getId())); + + Section section1 = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(List.of(checkboxQuestion.getId()))); + Section section2 = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(List.of(textQuestion.getId()))); + + long noExistsTemplateId = 1L; + + // when, then + assertThatThrownBy(() -> templateCreator.find(noExistsTemplateId)) + .isInstanceOf(TemplateNotFoundException.class); + } +} diff --git a/backend/src/test/java/reviewme/template/service/StructuredTemplateServiceTest.java b/backend/src/test/java/reviewme/template/service/StructuredTemplateServiceTest.java new file mode 100644 index 000000000..7e1cf2f3d --- /dev/null +++ b/backend/src/test/java/reviewme/template/service/StructuredTemplateServiceTest.java @@ -0,0 +1,128 @@ +package reviewme.template.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static reviewme.fixture.OptionGroupFixture.์„ ํƒ์ง€_๊ทธ๋ฃน; +import static reviewme.fixture.OptionItemFixture.์„ ํƒ์ง€; +import static reviewme.fixture.QuestionFixture.์„œ์ˆ ํ˜•_์˜ต์…˜_์งˆ๋ฌธ; +import static reviewme.fixture.QuestionFixture.์„œ์ˆ ํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ; +import static reviewme.fixture.QuestionFixture.์„ ํƒํ˜•_์˜ต์…˜_์งˆ๋ฌธ; +import static reviewme.fixture.QuestionFixture.์„ ํƒํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ; +import static reviewme.fixture.SectionFixture.์กฐ๊ฑด๋ถ€๋กœ_๋ณด์ด๋Š”_์„น์…˜; +import static reviewme.fixture.SectionFixture.ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜; +import static reviewme.fixture.TemplateFixture.ํ…œํ”Œ๋ฆฟ; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import reviewme.support.ServiceTest; +import reviewme.template.domain.OptionGroup; +import reviewme.template.domain.OptionItem; +import reviewme.template.domain.Question; +import reviewme.template.domain.Section; +import reviewme.template.domain.Template; +import reviewme.template.domain.structured.StructuredTemplate; +import reviewme.template.repository.OptionGroupRepository; +import reviewme.template.repository.OptionItemRepository; +import reviewme.template.repository.QuestionRepository; +import reviewme.template.repository.SectionRepository; +import reviewme.template.repository.TemplateRepository; +import reviewme.template.service.exception.TemplateNotFoundException; + +@ServiceTest +class StructuredTemplateServiceTest { + + @Autowired + private StructuredTemplateService structuredTemplateService; + + @Autowired + private TemplateRepository templateRepository; + + @Autowired + private SectionRepository sectionRepository; + + @Autowired + private QuestionRepository questionRepository; + + @Autowired + private OptionGroupRepository optionGroupRepository; + + @Autowired + private OptionItemRepository optionItemRepository; + + @Test + void ํ…œํ”Œ๋ฆฟ_์•„์ด๋””๋ฅผ_ํ†ตํ•ด_๊ตฌ์กฐํ™”๋œ_ํ…œํ”Œ๋ฆฟ์„_์‘๋‹ตํ•œ๋‹ค() { + // given + Question requiredCheckboxQuestion = questionRepository.save(์„ ํƒํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + Question optionalCheckboxQuestion = questionRepository.save(์„ ํƒํ˜•_์˜ต์…˜_์งˆ๋ฌธ()); + Question requiredTextQuestion = questionRepository.save(์„œ์ˆ ํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + + OptionGroup optionGroup1 = optionGroupRepository.save(์„ ํƒ์ง€_๊ทธ๋ฃน(requiredCheckboxQuestion.getId())); + OptionItem optionItem1 = optionItemRepository.save(์„ ํƒ์ง€(optionGroup1.getId())); + OptionItem optionItem2 = optionItemRepository.save(์„ ํƒ์ง€(optionGroup1.getId())); + + OptionGroup optionGroup2 = optionGroupRepository.save(์„ ํƒ์ง€_๊ทธ๋ฃน(optionalCheckboxQuestion.getId())); + OptionItem optionItem3 = optionItemRepository.save(์„ ํƒ์ง€(optionGroup2.getId())); + OptionItem optionItem4 = optionItemRepository.save(์„ ํƒ์ง€(optionGroup2.getId())); + + Section section1 = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(List.of(requiredCheckboxQuestion.getId()))); + Section section2 = sectionRepository.save(์กฐ๊ฑด๋ถ€๋กœ_๋ณด์ด๋Š”_์„น์…˜( + List.of(requiredTextQuestion.getId(), optionalCheckboxQuestion.getId()), optionItem1.getId())); + + Template template = templateRepository.save(ํ…œํ”Œ๋ฆฟ(List.of(section1.getId(), section2.getId()))); + + // when + StructuredTemplate actual = structuredTemplateService.getStructuredTemplateById(template.getId()); + + // then + assertAll( + () -> assertThat(actual.getTemplateId()).isEqualTo(template.getId()), + () -> assertThat(actual.getSections().getSectionIds()) + .containsExactlyInAnyOrder(section1.getId(), section2.getId()), + () -> assertThat(actual.getQuestions().getQuestionIds()) + .containsExactlyInAnyOrder(requiredCheckboxQuestion.getId(), optionalCheckboxQuestion.getId(), + requiredTextQuestion.getId()), + () -> assertThat(actual.getOptionGroups().getOptionGroupIds()) + .containsExactlyInAnyOrder(optionGroup1.getId(), optionGroup2.getId()), + () -> assertThat(actual.getOptionItems().getOptionItemIds()) + .containsExactlyInAnyOrder(optionItem1.getId(), optionItem2.getId(), optionItem3.getId(), + optionItem4.getId()) + ); + } + + @Test + void ํ…œํ”Œ๋ฆฟ_์•„์ด๋””๋ฅผ_ํ†ตํ•ด_์ฒดํฌ๋ฐ•์Šค_ํƒ€์ž…์˜_์งˆ๋ฌธ์ด_์—†๋Š”_๊ตฌ์กฐํ™”๋œ_ํ…œํ”Œ๋ฆฟ์„_์‘๋‹ตํ•œ๋‹ค() { + // given + Question requiredQuestion = questionRepository.save(์„œ์ˆ ํ˜•_ํ•„์ˆ˜_์งˆ๋ฌธ()); + Question optionalQuestion = questionRepository.save(์„œ์ˆ ํ˜•_์˜ต์…˜_์งˆ๋ฌธ()); + + Section section1 = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜(List.of(requiredQuestion.getId()))); + Section section2 = sectionRepository.save(ํ•ญ์ƒ_๋ณด์ด๋Š”_์„น์…˜( + List.of(requiredQuestion.getId(), optionalQuestion.getId()))); + + Template template = templateRepository.save(ํ…œํ”Œ๋ฆฟ(List.of(section1.getId(), section2.getId()))); + + // when + StructuredTemplate actual = structuredTemplateService.getStructuredTemplateById(template.getId()); + + // then + assertAll( + () -> assertThat(actual.getTemplateId()).isEqualTo(template.getId()), + () -> assertThat(actual.getSections().getSectionIds()) + .containsExactlyInAnyOrder(section1.getId(), section2.getId()), + () -> assertThat(actual.getQuestions().getQuestionIds()) + .containsExactlyInAnyOrder(requiredQuestion.getId(), optionalQuestion.getId()) + ); + } + + @Test + void ํ…œํ”Œ๋ฆฟ_์•„์ด๋””์—_ํ•ด๋‹นํ•˜๋Š”_ํ…œํ”Œ๋ฆฟ์ด_์—†์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + long wrongTemplateId = 1L; + + // when, then + assertThatThrownBy(() -> structuredTemplateService.getStructuredTemplateById(wrongTemplateId)) + .isInstanceOf(TemplateNotFoundException.class); + } +}