diff --git a/src/main/java/sixgaezzang/sidepeek/common/dto/request/UpdateUserSkillRequest.java b/src/main/java/sixgaezzang/sidepeek/common/dto/request/SaveTechStackRequest.java similarity index 87% rename from src/main/java/sixgaezzang/sidepeek/common/dto/request/UpdateUserSkillRequest.java rename to src/main/java/sixgaezzang/sidepeek/common/dto/request/SaveTechStackRequest.java index 5a74b426..738e75d1 100644 --- a/src/main/java/sixgaezzang/sidepeek/common/dto/request/UpdateUserSkillRequest.java +++ b/src/main/java/sixgaezzang/sidepeek/common/dto/request/SaveTechStackRequest.java @@ -1,7 +1,7 @@ package sixgaezzang.sidepeek.common.dto.request; -import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.CATEGORY_IS_NULL; -import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.CATEGORY_OVER_MAX_LENGTH; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.CATEGORY_IS_NULL; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.CATEGORY_OVER_MAX_LENGTH; import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_CATEGORY_LENGTH; import static sixgaezzang.sidepeek.common.util.CommonConstant.MIN_ID; import static sixgaezzang.sidepeek.skill.exception.message.SkillErrorMessage.SKILL_ID_IS_NULL; @@ -18,7 +18,7 @@ import sixgaezzang.sidepeek.users.domain.UserSkill; @Schema(description = "기술 스택 저장 요청 정보") -public record UpdateUserSkillRequest( +public record SaveTechStackRequest( @Schema(description = "기술 스택 Id", example = "1") @Min(value = MIN_ID, message = "스킬 id는 " + MIN_ID + "보다 작을 수 없습니다.") @NotNull(message = SKILL_ID_IS_NULL) diff --git a/src/main/java/sixgaezzang/sidepeek/common/exception/message/CommonErrorMessage.java b/src/main/java/sixgaezzang/sidepeek/common/exception/message/CommonErrorMessage.java index 85f0b2d9..f5d0de15 100644 --- a/src/main/java/sixgaezzang/sidepeek/common/exception/message/CommonErrorMessage.java +++ b/src/main/java/sixgaezzang/sidepeek/common/exception/message/CommonErrorMessage.java @@ -1,7 +1,5 @@ package sixgaezzang.sidepeek.common.exception.message; -import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_CATEGORY_LENGTH; -import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_TECH_STACK_COUNT; import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_TEXT_LENGTH; import lombok.AccessLevel; @@ -9,6 +7,7 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public final class CommonErrorMessage { + // Common public static final String LOGIN_IS_REQUIRED = "로그인이 필요합니다."; @@ -20,11 +19,4 @@ public final class CommonErrorMessage { public static final String GITHUB_URL_IS_NULL = "Github URL을 입력해주세요."; public static final String GITHUB_URL_OVER_MAX_LENGTH = "Github URL은 " + MAX_TEXT_LENGTH + "자 이하여야 합니다."; - // TechStack - public static final String TECH_STACKS_IS_NULL = "기술 스택들을 입력해주세요."; - public static final String TECH_STACKS_OVER_MAX_COUNT = - "기술 스택은 " + MAX_TECH_STACK_COUNT + "개 미만이어야 합니다."; - public static final String CATEGORY_IS_NULL = "기술 스택 카테고리를 입력해주세요."; - public static final String CATEGORY_OVER_MAX_LENGTH = "기술 스택 카테고리는 " + MAX_CATEGORY_LENGTH + "자 이하여야 합니다."; - } diff --git a/src/main/java/sixgaezzang/sidepeek/common/exception/message/TechStackErrorMessage.java b/src/main/java/sixgaezzang/sidepeek/common/exception/message/TechStackErrorMessage.java new file mode 100644 index 00000000..d50813c3 --- /dev/null +++ b/src/main/java/sixgaezzang/sidepeek/common/exception/message/TechStackErrorMessage.java @@ -0,0 +1,23 @@ +package sixgaezzang.sidepeek.common.exception.message; + +import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_CATEGORY_LENGTH; +import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_TECH_STACK_COUNT; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class TechStackErrorMessage { + + // Tech Stack List + public static final String TECH_STACKS_IS_NULL = "기술 스택들을 입력해주세요."; + public static final String TECH_STACKS_OVER_MAX_COUNT = + "기술 스택은 " + MAX_TECH_STACK_COUNT + "개 미만이어야 합니다."; + public static final String TECH_STACK_IS_DUPLICATED = "같은 카테고리 내에 같은 기술 스택이 있습니다."; + + // Tech Stack + public static final String CATEGORY_IS_NULL = "기술 스택 카테고리를 입력해주세요."; + public static final String CATEGORY_OVER_MAX_LENGTH = + "기술 스택 카테고리는 " + MAX_CATEGORY_LENGTH + "자 이하여야 합니다."; + +} diff --git a/src/main/java/sixgaezzang/sidepeek/common/util/validation/TechStackValidator.java b/src/main/java/sixgaezzang/sidepeek/common/util/validation/TechStackValidator.java index 7540936e..5e48bafb 100644 --- a/src/main/java/sixgaezzang/sidepeek/common/util/validation/TechStackValidator.java +++ b/src/main/java/sixgaezzang/sidepeek/common/util/validation/TechStackValidator.java @@ -1,10 +1,13 @@ package sixgaezzang.sidepeek.common.util.validation; -import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.CATEGORY_IS_NULL; -import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.CATEGORY_OVER_MAX_LENGTH; -import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.TECH_STACKS_OVER_MAX_COUNT; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.CATEGORY_IS_NULL; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.CATEGORY_OVER_MAX_LENGTH; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.TECH_STACKS_OVER_MAX_COUNT; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.TECH_STACK_IS_DUPLICATED; import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_CATEGORY_LENGTH; import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_TECH_STACK_COUNT; +import static sixgaezzang.sidepeek.common.util.validation.ValidationUtils.validateCollection; +import static sixgaezzang.sidepeek.common.util.validation.ValidationUtils.validateDuplicate; import static sixgaezzang.sidepeek.common.util.validation.ValidationUtils.validateMaxLength; import static sixgaezzang.sidepeek.common.util.validation.ValidationUtils.validateNotBlank; import static sixgaezzang.sidepeek.skill.exception.message.SkillErrorMessage.SKILL_ID_IS_NULL; @@ -13,26 +16,25 @@ import java.util.List; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import sixgaezzang.sidepeek.common.dto.request.UpdateUserSkillRequest; +import sixgaezzang.sidepeek.common.dto.request.SaveTechStackRequest; @NoArgsConstructor(access = AccessLevel.PRIVATE) public final class TechStackValidator { - public static void validateTechStacks(List techStacks) { + public static void validateTechStacks(List techStacks) { Assert.isTrue(techStacks.size() <= MAX_TECH_STACK_COUNT, TECH_STACKS_OVER_MAX_COUNT); - - techStacks.forEach(TechStackValidator::validateTechStack); + validateCollection(techStacks, TechStackValidator::validateTechStack); + validateDuplicate(techStacks, TECH_STACK_IS_DUPLICATED); } - public static void validateTechStack(UpdateUserSkillRequest techStack) { + public static void validateTechStack(SaveTechStackRequest techStack) { Assert.notNull(techStack.skillId(), SKILL_ID_IS_NULL); Assert.notNull(techStack.category(), CATEGORY_IS_NULL); } public static void validateCategory(String category) { validateNotBlank(category, CATEGORY_IS_NULL); - validateMaxLength(category, MAX_CATEGORY_LENGTH, - CATEGORY_OVER_MAX_LENGTH); + validateMaxLength(category, MAX_CATEGORY_LENGTH, CATEGORY_OVER_MAX_LENGTH); } } diff --git a/src/main/java/sixgaezzang/sidepeek/common/util/validation/ValidationUtils.java b/src/main/java/sixgaezzang/sidepeek/common/util/validation/ValidationUtils.java index 04ed46ef..ba66b634 100644 --- a/src/main/java/sixgaezzang/sidepeek/common/util/validation/ValidationUtils.java +++ b/src/main/java/sixgaezzang/sidepeek/common/util/validation/ValidationUtils.java @@ -11,7 +11,13 @@ import static sixgaezzang.sidepeek.users.domain.Password.PASSWORD_REGXP; import java.util.Collection; +import java.util.HashSet; +import java.util.List; import java.util.Objects; +import java.util.Set; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Function; import java.util.regex.Pattern; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -72,6 +78,35 @@ public static void validateGithubUrl(String githubUrl) { validateURI(githubUrl, GITHUB_URL_IS_INVALID); } + public static void validateInclude( + List values, BiPredicate condition, U requiredValue, String errorMessage + ) { + values.stream().filter(value -> condition.test(value, requiredValue)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(errorMessage)); + } + + public static , U> void validateCollection(T values, Consumer validator) { + values.forEach(validator); + } + + public static void validateDuplicate(List values, String errorMessage) { + Set set = new HashSet<>(); + values.forEach(value -> { + Assert.isTrue(!set.contains(value), errorMessage); + set.add(value); + }); + } + + public static void validateKeyDuplicate(List values, Function getKey, String errorMessage) { + Set keySet = new HashSet<>(); + values.forEach(value -> { + U key = getKey.apply(value); + Assert.isTrue(!keySet.contains(key), errorMessage); + keySet.add(getKey.apply(value)); + }); + } + public static boolean isNotNullOrEmpty(Collection input) { return Objects.nonNull(input) && !input.isEmpty(); } diff --git a/src/main/java/sixgaezzang/sidepeek/projects/dto/request/SaveProjectRequest.java b/src/main/java/sixgaezzang/sidepeek/projects/dto/request/SaveProjectRequest.java index e492cebb..b3bbb8a8 100644 --- a/src/main/java/sixgaezzang/sidepeek/projects/dto/request/SaveProjectRequest.java +++ b/src/main/java/sixgaezzang/sidepeek/projects/dto/request/SaveProjectRequest.java @@ -3,8 +3,8 @@ import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.GITHUB_URL_IS_INVALID; import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.GITHUB_URL_IS_NULL; import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.GITHUB_URL_OVER_MAX_LENGTH; -import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.TECH_STACKS_IS_NULL; -import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.TECH_STACKS_OVER_MAX_COUNT; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.TECH_STACKS_IS_NULL; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.TECH_STACKS_OVER_MAX_COUNT; import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_TECH_STACK_COUNT; import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_TEXT_LENGTH; import static sixgaezzang.sidepeek.common.util.CommonConstant.MIN_ID; @@ -41,7 +41,7 @@ import java.time.YearMonth; import java.util.List; import org.hibernate.validator.constraints.URL; -import sixgaezzang.sidepeek.common.dto.request.UpdateUserSkillRequest; +import sixgaezzang.sidepeek.common.dto.request.SaveTechStackRequest; import sixgaezzang.sidepeek.projects.domain.Project; @Schema(description = "프로젝트 생성/수정 요청") @@ -76,7 +76,7 @@ public record SaveProjectRequest( @Schema(description = "프로젝트 기술 스택") @Size(max = MAX_TECH_STACK_COUNT, message = TECH_STACKS_OVER_MAX_COUNT) @NotEmpty(message = TECH_STACKS_IS_NULL) - List techStacks, + List techStacks, // Option @Schema(description = "프로젝트 부제목", example = "좋은 아이디어? 사이드픽에서 찾아봐!") diff --git a/src/main/java/sixgaezzang/sidepeek/projects/exception/message/MemberErrorMessage.java b/src/main/java/sixgaezzang/sidepeek/projects/exception/message/MemberErrorMessage.java index 4a852f99..f84d4d9c 100644 --- a/src/main/java/sixgaezzang/sidepeek/projects/exception/message/MemberErrorMessage.java +++ b/src/main/java/sixgaezzang/sidepeek/projects/exception/message/MemberErrorMessage.java @@ -15,6 +15,7 @@ public final class MemberErrorMessage { public static final String MEMBER_OVER_MAX_COUNT = "멤버 수는 " + MAX_MEMBER_COUNT + "명 미만이어야 합니다."; public static final String MEMBER_IS_EMPTY = "멤버 목록에는 최소 1명(작성자)을 포함해야합니다."; public static final String MEMBER_NOT_INCLUDE_OWNER = "멤버 목록에 작성자를 필수로 포함해야합니다."; + public static final String MEMBER_IS_DUPLICATED = "같은 역할 내에 같은 멤버가 있습니다."; // Member public static final String ROLE_OVER_MAX_LENGTH = diff --git a/src/main/java/sixgaezzang/sidepeek/projects/service/ProjectSkillService.java b/src/main/java/sixgaezzang/sidepeek/projects/service/ProjectSkillService.java index a697a4bd..01b3ac85 100644 --- a/src/main/java/sixgaezzang/sidepeek/projects/service/ProjectSkillService.java +++ b/src/main/java/sixgaezzang/sidepeek/projects/service/ProjectSkillService.java @@ -1,6 +1,6 @@ package sixgaezzang.sidepeek.projects.service; -import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.TECH_STACKS_IS_NULL; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.TECH_STACKS_IS_NULL; import static sixgaezzang.sidepeek.common.util.validation.TechStackValidator.validateTechStacks; import static sixgaezzang.sidepeek.common.util.validation.ValidationUtils.validateNotNullAndEmpty; import static sixgaezzang.sidepeek.projects.util.validation.ProjectValidator.validateProject; @@ -11,7 +11,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import sixgaezzang.sidepeek.common.dto.request.UpdateUserSkillRequest; +import sixgaezzang.sidepeek.common.dto.request.SaveTechStackRequest; import sixgaezzang.sidepeek.projects.domain.Project; import sixgaezzang.sidepeek.projects.domain.ProjectSkill; import sixgaezzang.sidepeek.projects.dto.response.ProjectSkillSummary; @@ -32,7 +32,7 @@ public List findAll(Project project) { } @Transactional - public List saveAll(Project project, List techStacks) { + public List saveAll(Project project, List techStacks) { validateProject(project); validateNotNullAndEmpty(techStacks, TECH_STACKS_IS_NULL); validateTechStacks(techStacks); @@ -49,7 +49,7 @@ public List saveAll(Project project, List convertAllToEntity(Project project, List techStacks) { + private List convertAllToEntity(Project project, List techStacks) { return techStacks.stream().map( techStack -> { Skill skill = skillRepository.findById(techStack.skillId()) diff --git a/src/main/java/sixgaezzang/sidepeek/projects/util/validation/MemberValidator.java b/src/main/java/sixgaezzang/sidepeek/projects/util/validation/MemberValidator.java index c5a40d3f..819cd694 100644 --- a/src/main/java/sixgaezzang/sidepeek/projects/util/validation/MemberValidator.java +++ b/src/main/java/sixgaezzang/sidepeek/projects/util/validation/MemberValidator.java @@ -1,7 +1,11 @@ package sixgaezzang.sidepeek.projects.util.validation; +import static sixgaezzang.sidepeek.common.util.validation.ValidationUtils.validateCollection; +import static sixgaezzang.sidepeek.common.util.validation.ValidationUtils.validateInclude; +import static sixgaezzang.sidepeek.common.util.validation.ValidationUtils.validateKeyDuplicate; import static sixgaezzang.sidepeek.common.util.validation.ValidationUtils.validateMaxLength; import static sixgaezzang.sidepeek.common.util.validation.ValidationUtils.validateNotBlank; +import static sixgaezzang.sidepeek.projects.exception.message.MemberErrorMessage.MEMBER_IS_DUPLICATED; import static sixgaezzang.sidepeek.projects.exception.message.MemberErrorMessage.MEMBER_IS_EMPTY; import static sixgaezzang.sidepeek.projects.exception.message.MemberErrorMessage.MEMBER_NOT_INCLUDE_OWNER; import static sixgaezzang.sidepeek.projects.exception.message.MemberErrorMessage.MEMBER_OVER_MAX_COUNT; @@ -9,12 +13,14 @@ import static sixgaezzang.sidepeek.projects.exception.message.MemberErrorMessage.ROLE_OVER_MAX_LENGTH; import static sixgaezzang.sidepeek.projects.util.ProjectConstant.MAX_MEMBER_COUNT; import static sixgaezzang.sidepeek.projects.util.ProjectConstant.MAX_ROLE_LENGTH; +import static sixgaezzang.sidepeek.users.util.validation.UserValidator.validateNickname; import io.jsonwebtoken.lang.Assert; import java.util.List; import java.util.Objects; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.apache.commons.lang3.tuple.Pair; import sixgaezzang.sidepeek.projects.dto.request.SaveMemberRequest; @NoArgsConstructor(access = AccessLevel.PRIVATE) @@ -23,12 +29,19 @@ public final class MemberValidator { public static void validateMembers(Long ownerId, List members) { Assert.notEmpty(members, MEMBER_IS_EMPTY); Assert.isTrue(members.size() <= MAX_MEMBER_COUNT, MEMBER_OVER_MAX_COUNT); - members.stream().filter(member -> Objects.equals(member.userId(), ownerId)) - .findAny() - .orElseThrow(() -> new IllegalArgumentException(MEMBER_NOT_INCLUDE_OWNER)); + + validateInclude(members, (member, id) -> Objects.equals(member.userId(), id), ownerId, + MEMBER_NOT_INCLUDE_OWNER); + validateCollection(members, MemberValidator::validateSaveMemberRequest); + validateKeyDuplicate(members, (member) -> Pair.of(member.nickname(), member.role()), MEMBER_IS_DUPLICATED); } // Required + public static void validateSaveMemberRequest(SaveMemberRequest member) { + validateNickname(member.nickname()); + validateRole(member.role()); + } + public static void validateRole(String role) { validateNotBlank(role, ROLE_IS_NULL); validateMaxLength(role, MAX_ROLE_LENGTH, ROLE_OVER_MAX_LENGTH); diff --git a/src/main/java/sixgaezzang/sidepeek/users/dto/request/UpdateUserProfileRequest.java b/src/main/java/sixgaezzang/sidepeek/users/dto/request/UpdateUserProfileRequest.java index a0f75c15..c83a2d28 100644 --- a/src/main/java/sixgaezzang/sidepeek/users/dto/request/UpdateUserProfileRequest.java +++ b/src/main/java/sixgaezzang/sidepeek/users/dto/request/UpdateUserProfileRequest.java @@ -17,7 +17,7 @@ import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import java.util.List; -import sixgaezzang.sidepeek.common.dto.request.UpdateUserSkillRequest; +import sixgaezzang.sidepeek.common.dto.request.SaveTechStackRequest; @Schema(description = "회원 프로필 수정 요청") public record UpdateUserProfileRequest( @@ -51,7 +51,7 @@ public record UpdateUserProfileRequest( String blogUrl, @Schema(description = "회원 기술 스택 목록") - List techStacks + List techStacks ) { } diff --git a/src/main/java/sixgaezzang/sidepeek/users/service/UserSkillService.java b/src/main/java/sixgaezzang/sidepeek/users/service/UserSkillService.java index d0c75f8e..782405c0 100644 --- a/src/main/java/sixgaezzang/sidepeek/users/service/UserSkillService.java +++ b/src/main/java/sixgaezzang/sidepeek/users/service/UserSkillService.java @@ -11,7 +11,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import sixgaezzang.sidepeek.common.dto.request.UpdateUserSkillRequest; +import sixgaezzang.sidepeek.common.dto.request.SaveTechStackRequest; import sixgaezzang.sidepeek.skill.domain.Skill; import sixgaezzang.sidepeek.skill.repository.SkillRepository; import sixgaezzang.sidepeek.users.domain.User; @@ -36,7 +36,7 @@ public List findAllByUser(User user) { .toList(); } - public List saveAll(User user, List techStacks) { + public List saveAll(User user, List techStacks) { validateUser(user); if (userSkillRepository.existsByUser(user)) { userSkillRepository.deleteAllByUser(user); @@ -55,7 +55,7 @@ public List saveAll(User user, List te .toList(); } - private List convertAllToEntity(User user, List techStacks) { + private List convertAllToEntity(User user, List techStacks) { return techStacks.stream() .map(techStack -> { Skill skill = skillRepository.findById(techStack.skillId()) diff --git a/src/main/resources/db/data/afterMigrate.sql b/src/main/resources/db/data/afterMigrate.sql index 9a419186..41354061 100644 --- a/src/main/resources/db/data/afterMigrate.sql +++ b/src/main/resources/db/data/afterMigrate.sql @@ -60,13 +60,47 @@ values (2, 1, 'OVERVIEW_IMAGE', 'https://project-images.sidepeek.com/2.png'); -- SKILL insert into skill(id, name, icon_image_url) -values (1, 'React', 'https://cdn.iconscout.com/icon/react.png'); +values (1, 'AWS EC2', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/aws-ec2.png'); insert into skill(id, name, icon_image_url) -values (2, 'Spring', 'https://cdn.iconscout.com/icon/spring.png'); +values (2, 'AWS RDS', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/aws-rds.png'); insert into skill(id, name, icon_image_url) -values (3, 'GitHub', 'https://cdn.iconscout.com/icon/github.png'); +values (3, 'AWS S3', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/aws-s3.png'); insert into skill(id, name, icon_image_url) -values (4, 'React Query', 'https://cdn.iconscout.com/icon/reactQuery.png'); +values (4, 'Figma', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/figma.png'); +insert into skill(id, name, icon_image_url) +values (5, 'Git', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/git-icon.png'); +insert into skill(id, name, icon_image_url) +values (6, 'Github Actions', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/github-actions.png'); +insert into skill(id, name, icon_image_url) +values (7, 'Github', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/github-icon.png'); +insert into skill(id, name, icon_image_url) +values (8, 'Java', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/java.png'); +insert into skill(id, name, icon_image_url) +values (9, 'Javascript', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/javascript.png'); +insert into skill(id, name, icon_image_url) +values (10, 'Kotlin', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/kotlin-icon.png'); +insert into skill(id, name, icon_image_url) +values (11, 'Notion', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/notion-icon.png'); +insert into skill(id, name, icon_image_url) +values (12, 'PostgreSQL', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/postgresql.png'); +insert into skill(id, name, icon_image_url) +values (13, 'React Query', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/react-query-icon.png'); +insert into skill(id, name, icon_image_url) +values (14, 'React', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/react.png'); +insert into skill(id, name, icon_image_url) +values (15, 'Slack', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/slack-icon.png'); +insert into skill(id, name, icon_image_url) +values (16, 'Spring', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/spring-icon.png'); +insert into skill(id, name, icon_image_url) +values (17, 'Swagger', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/swagger.png'); +insert into skill(id, name, icon_image_url) +values (18, 'Thymeleaf', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/thymeleaf-icon.png'); +insert into skill(id, name, icon_image_url) +values (19, 'Tomcat', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/tomcat.png'); +insert into skill(id, name, icon_image_url) +values (20, 'Typescript', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/typescript-icon.png'); +insert into skill(id, name, icon_image_url) +values (21, 'Vercel', 'https://sidepeek-bucket.s3.ap-northeast-2.amazonaws.com/skill/vercel-icon.png'); -- PROJECT_SKILL insert into project_skill(id, project_id, skill_id, category) diff --git a/src/test/java/sixgaezzang/sidepeek/projects/service/MemberServiceTest.java b/src/test/java/sixgaezzang/sidepeek/projects/service/MemberServiceTest.java index 51d4659e..fe154a12 100644 --- a/src/test/java/sixgaezzang/sidepeek/projects/service/MemberServiceTest.java +++ b/src/test/java/sixgaezzang/sidepeek/projects/service/MemberServiceTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; +import static sixgaezzang.sidepeek.projects.exception.message.MemberErrorMessage.MEMBER_IS_DUPLICATED; import static sixgaezzang.sidepeek.projects.exception.message.MemberErrorMessage.MEMBER_IS_EMPTY; import static sixgaezzang.sidepeek.projects.exception.message.MemberErrorMessage.MEMBER_NOT_INCLUDE_OWNER; import static sixgaezzang.sidepeek.projects.exception.message.MemberErrorMessage.MEMBER_OVER_MAX_COUNT; @@ -14,6 +15,8 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.function.Function; +import org.assertj.core.api.AssertionsForClassTypes; import org.assertj.core.api.ThrowableAssert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGeneration; @@ -200,6 +203,22 @@ class 멤버_저장_테스트 { .withMessage(MEMBER_NOT_INCLUDE_OWNER); } + @ParameterizedTest(name = "[{index}] {0}") + @MethodSource("sixgaezzang.sidepeek.util.TestParameterProvider#createDuplicatedMembers") + void 멤버의_역할과_닉네임이_중복이어서_멤버_목록_저장에_실패한다( + String testMessage, Function> getDuplicatedMembers + ) { + // given + members.addAll(getDuplicatedMembers.apply(createAndSaveUser())); + + // when + ThrowableAssert.ThrowingCallable saveAll = () -> memberService.saveAll(project, members); + + // then + AssertionsForClassTypes.assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(saveAll) + .withMessage(MEMBER_IS_DUPLICATED); + } + } @Nested diff --git a/src/test/java/sixgaezzang/sidepeek/projects/service/ProjectServiceTest.java b/src/test/java/sixgaezzang/sidepeek/projects/service/ProjectServiceTest.java index de5b028e..cc9497dc 100644 --- a/src/test/java/sixgaezzang/sidepeek/projects/service/ProjectServiceTest.java +++ b/src/test/java/sixgaezzang/sidepeek/projects/service/ProjectServiceTest.java @@ -29,7 +29,7 @@ import sixgaezzang.sidepeek.comments.domain.Comment; import sixgaezzang.sidepeek.comments.dto.response.CommentResponse; import sixgaezzang.sidepeek.comments.repository.CommentRepository; -import sixgaezzang.sidepeek.common.dto.request.UpdateUserSkillRequest; +import sixgaezzang.sidepeek.common.dto.request.SaveTechStackRequest; import sixgaezzang.sidepeek.common.exception.InvalidAuthenticationException; import sixgaezzang.sidepeek.projects.domain.Project; import sixgaezzang.sidepeek.projects.dto.request.SaveMemberRequest; @@ -55,7 +55,7 @@ class ProjectServiceTest { static final int SKILL_COUNT = MAX_TECH_STACK_COUNT / 2; static List members; static List fellowMemberIds; - static List techStacks; + static List techStacks; static String NAME = FakeValueProvider.createProjectName(); static String OVERVIEW = FakeValueProvider.createOverview(); static String GITHUB_URL = FakeValueProvider.createUrl(); diff --git a/src/test/java/sixgaezzang/sidepeek/projects/service/ProjectSkillServiceTest.java b/src/test/java/sixgaezzang/sidepeek/projects/service/ProjectSkillServiceTest.java index b71b79e3..1e9e65e9 100644 --- a/src/test/java/sixgaezzang/sidepeek/projects/service/ProjectSkillServiceTest.java +++ b/src/test/java/sixgaezzang/sidepeek/projects/service/ProjectSkillServiceTest.java @@ -2,8 +2,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; -import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.TECH_STACKS_IS_NULL; -import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.TECH_STACKS_OVER_MAX_COUNT; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.TECH_STACKS_IS_NULL; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.TECH_STACKS_OVER_MAX_COUNT; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.TECH_STACK_IS_DUPLICATED; import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_TECH_STACK_COUNT; import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.PROJECT_IS_NULL; import static sixgaezzang.sidepeek.skill.exception.message.SkillErrorMessage.SKILL_ID_IS_NULL; @@ -12,6 +13,7 @@ import jakarta.persistence.EntityNotFoundException; import java.util.ArrayList; import java.util.List; +import org.assertj.core.api.AssertionsForClassTypes; import org.assertj.core.api.ThrowableAssert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGeneration; @@ -24,7 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.transaction.annotation.Transactional; -import sixgaezzang.sidepeek.common.dto.request.UpdateUserSkillRequest; +import sixgaezzang.sidepeek.common.dto.request.SaveTechStackRequest; import sixgaezzang.sidepeek.projects.domain.Project; import sixgaezzang.sidepeek.projects.domain.ProjectSkill; import sixgaezzang.sidepeek.projects.dto.response.ProjectSkillSummary; @@ -58,8 +60,8 @@ class ProjectSkillServiceTest { UserRepository userRepository; static final int SKILL_COUNT = MAX_TECH_STACK_COUNT / 2; - static List techStacks; - static List overLengthTechStacks; + static List techStacks; + static List overLengthTechStacks; Project project; User user; Skill skill; @@ -107,7 +109,7 @@ class 프로젝트_기술_스택_목록_저장_테스트 { @ParameterizedTest @NullAndEmptySource - void 빈_기술_스택_목록_저장에_실패한다(List emptyTechStacks) { + void 빈_기술_스택_목록_저장에_실패한다(List emptyTechStacks) { // given, when ThrowableAssert.ThrowingCallable saveAll = () -> projectSkillService.saveAll(project, emptyTechStacks); @@ -145,9 +147,9 @@ class 프로젝트_기술_스택_목록_저장_테스트 { String testMessage, String category, String message ) { // given - List techStacksWithInvalidSkill = new ArrayList<>(techStacks); + List techStacksWithInvalidSkill = new ArrayList<>(techStacks); techStacksWithInvalidSkill.add( - new UpdateUserSkillRequest(skill.getId(), category) + new SaveTechStackRequest(skill.getId(), category) ); // when @@ -162,7 +164,7 @@ class 프로젝트_기술_스택_목록_저장_테스트 { @Test void 존재하지_않는_기술_스택_Id로_기술_스택_목록_저장에_실패한다() { // given - List techStacksWithNonExistSkill = new ArrayList<>(techStacks); + List techStacksWithNonExistSkill = new ArrayList<>(techStacks); techStacksWithNonExistSkill.add( FakeDtoProvider.createUpdateUserSkillRequest(skill.getId() + 1) ); @@ -179,7 +181,7 @@ class 프로젝트_기술_스택_목록_저장_테스트 { @Test void 기술_스택_Id가_누락되어_기술_스택_목록_저장에_실패한다() { // given - List techStacksWithNonExistSkill = new ArrayList<>(techStacks); + List techStacksWithNonExistSkill = new ArrayList<>(techStacks); techStacksWithNonExistSkill.add( FakeDtoProvider.createUpdateUserSkillRequest(null) ); @@ -195,13 +197,18 @@ class 프로젝트_기술_스택_목록_저장_테스트 { @Test void 같은_카테고리_내에_중복된_기술_스택으로_사용자_기술_스택_목록_저장에_실패한다() { - // TODO: 유효성 검사로직 추가 필요 // given + SaveTechStackRequest techStack = techStacks.get(0); + SaveTechStackRequest duplicatedTechStack = new SaveTechStackRequest( + techStack.skillId(), techStack.category()); + techStacks.add(duplicatedTechStack); // when + ThrowableAssert.ThrowingCallable saveAll = () -> projectSkillService.saveAll(project, techStacks); // then - + AssertionsForClassTypes.assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(saveAll) + .withMessage(TECH_STACK_IS_DUPLICATED); } } @@ -216,7 +223,7 @@ class 프로젝트_기술_스택_목록_수정_테스트 { List originalTechStacks = projectSkillService.findAll(project); // when - List techStacksOnlyOne = new ArrayList<>(); + List techStacksOnlyOne = new ArrayList<>(); Skill newSkill = createAndSaveSkill(); techStacksOnlyOne.add(FakeDtoProvider.createUpdateUserSkillRequest(newSkill.getId())); diff --git a/src/test/java/sixgaezzang/sidepeek/users/service/UserServiceTest.java b/src/test/java/sixgaezzang/sidepeek/users/service/UserServiceTest.java index dbf31de6..40146384 100644 --- a/src/test/java/sixgaezzang/sidepeek/users/service/UserServiceTest.java +++ b/src/test/java/sixgaezzang/sidepeek/users/service/UserServiceTest.java @@ -90,56 +90,6 @@ private User createAndSaveUser() { return userRepository.save(newUser); } - @Nested - class 회원_닉네임_검색_테스트 { - - @ParameterizedTest(name = "[{index}] {0}으로 검색할 때 " + USER_COUNT + "명의 모든 회원이 나온다.") - @NullAndEmptySource - void 검색어_없이_전체_회원_닉네임_검색에_성공한다(String keyword) { - // given, when - List users = userService.searchByNickname(keyword) - .users(); - - // then - // TODO: 분명 5개를 BeforeEach로 저장했는데 그 이상이 나온다. - assertThat(users).hasSize(USER_COUNT); - } - - @Test - void 검색어로_회원_닉네임_검색에_성공한다() { - // given, - String keyword = FakeValueProvider.createEnglishKeyword(); - int count = 0; - for (String nickname : userNicknames) { - if (nickname.contains(keyword)) { - count++; - } - } - - // when - List users = userService.searchByNickname(keyword) - .users(); - - // then - assertThat(users.size()).isEqualTo(count); - } - - @Test - void 검색어_최대_글자_수가_넘어_회원_닉네임_검색에_실패한다() { - // given - int keywordLength = MAX_NICKNAME_LENGTH + 1; - String keyword = "a".repeat(keywordLength); - - // when - ThrowingCallable search = () -> userService.searchByNickname(keyword); - - // then - assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(search) - .withMessage(NICKNAME_OVER_MAX_LENGTH); - } - - } - @Nested class 회원가입_테스트 { @@ -225,6 +175,56 @@ class 회원가입_테스트 { } + @Nested + class 회원_닉네임_검색_테스트 { + + @ParameterizedTest(name = "[{index}] {0}으로 검색할 때 " + USER_COUNT + "명의 모든 회원이 나온다.") + @NullAndEmptySource + void 검색어_없이_전체_회원_닉네임_검색에_성공한다(String keyword) { + // given, when + List users = userService.searchByNickname(keyword) + .users(); + + // then + // TODO: 분명 5개를 BeforeEach로 저장했는데 그 이상이 나온다. + assertThat(users).hasSize(USER_COUNT); + } + + @Test + void 검색어로_회원_닉네임_검색에_성공한다() { + // given, + String keyword = FakeValueProvider.createEnglishKeyword(); + int count = 0; + for (String nickname : userNicknames) { + if (nickname.contains(keyword)) { + count++; + } + } + + // when + List users = userService.searchByNickname(keyword) + .users(); + + // then + assertThat(users.size()).isEqualTo(count); + } + + @Test + void 검색어_최대_글자_수가_넘어_회원_닉네임_검색에_실패한다() { + // given + int keywordLength = MAX_NICKNAME_LENGTH + 1; + String keyword = "a".repeat(keywordLength); + + // when + ThrowingCallable search = () -> userService.searchByNickname(keyword); + + // then + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(search) + .withMessage(NICKNAME_OVER_MAX_LENGTH); + } + + } + @Nested class 이메일_중복_확인_테스트 { diff --git a/src/test/java/sixgaezzang/sidepeek/users/service/UserSkillServiceTest.java b/src/test/java/sixgaezzang/sidepeek/users/service/UserSkillServiceTest.java index 7635519f..b7b00ad4 100644 --- a/src/test/java/sixgaezzang/sidepeek/users/service/UserSkillServiceTest.java +++ b/src/test/java/sixgaezzang/sidepeek/users/service/UserSkillServiceTest.java @@ -2,7 +2,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.TECH_STACKS_OVER_MAX_COUNT; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.TECH_STACKS_OVER_MAX_COUNT; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.TECH_STACK_IS_DUPLICATED; import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_TECH_STACK_COUNT; import static sixgaezzang.sidepeek.skill.exception.message.SkillErrorMessage.SKILL_ID_IS_NULL; import static sixgaezzang.sidepeek.skill.exception.message.SkillErrorMessage.SKILL_NOT_EXISTING; @@ -25,7 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.transaction.annotation.Transactional; -import sixgaezzang.sidepeek.common.dto.request.UpdateUserSkillRequest; +import sixgaezzang.sidepeek.common.dto.request.SaveTechStackRequest; import sixgaezzang.sidepeek.skill.domain.Skill; import sixgaezzang.sidepeek.skill.repository.SkillRepository; import sixgaezzang.sidepeek.users.domain.User; @@ -41,8 +42,8 @@ class UserSkillServiceTest { static final int SKILL_COUNT = MAX_TECH_STACK_COUNT / 2; - static List techStacks; - static List overLengthTechStacks; + static List techStacks; + static List overLengthTechStacks; @Autowired UserSkillService userSkillService; @Autowired @@ -133,7 +134,7 @@ class 사용자_기술_스택_목록_수정_테스트 { @ParameterizedTest @NullAndEmptySource - void 비어있는_사용자_기술_스택_목록_수정에_성공한다(List emptyTechStack) { + void 비어있는_사용자_기술_스택_목록_수정에_성공한다(List emptyTechStack) { // given, when userSkillService.saveAll(user, emptyTechStack); List retrievedTechStacks = userSkillService.findAllByUser(user); @@ -170,9 +171,9 @@ class 사용자_기술_스택_목록_수정_테스트 { String testMessage, String category, String message ) { // given - List techStacksWithInvalidSkill = new ArrayList<>(techStacks); + List techStacksWithInvalidSkill = new ArrayList<>(techStacks); techStacksWithInvalidSkill.add( - new UpdateUserSkillRequest(skill.getId(), category) + new SaveTechStackRequest(skill.getId(), category) ); // when @@ -187,7 +188,7 @@ class 사용자_기술_스택_목록_수정_테스트 { @Test void 존재하지_않는_기술_스택_Id로_사용자_기술_스택_목록_수정에_실패한다() { // given - List techStacksWithNonExistSkill = new ArrayList<>(techStacks); + List techStacksWithNonExistSkill = new ArrayList<>(techStacks); techStacksWithNonExistSkill.add( FakeDtoProvider.createUpdateUserSkillRequest(skill.getId() + 1) ); @@ -204,7 +205,7 @@ class 사용자_기술_스택_목록_수정_테스트 { @Test void 기술_스택_Id가_누락되어_사용자_기술_스택_목록_수정에_실패한다() { // given - List techStacksWithNonExistSkill = new ArrayList<>(techStacks); + List techStacksWithNonExistSkill = new ArrayList<>(techStacks); techStacksWithNonExistSkill.add( FakeDtoProvider.createUpdateUserSkillRequest(null) ); @@ -220,13 +221,18 @@ class 사용자_기술_스택_목록_수정_테스트 { @Test void 같은_카테고리_내에_중복된_기술_스택으로_사용자_기술_스택_목록_수정에_실패한다() { - // TODO: 유효성 검사로직 추가 필요 // given + SaveTechStackRequest techStack = techStacks.get(0); + SaveTechStackRequest duplicatedTechStack = new SaveTechStackRequest( + techStack.skillId(), techStack.category()); + techStacks.add(duplicatedTechStack); // when + ThrowableAssert.ThrowingCallable saveAll = () -> userSkillService.saveAll(user, techStacks); // then - + AssertionsForClassTypes.assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(saveAll) + .withMessage(TECH_STACK_IS_DUPLICATED); } } diff --git a/src/test/java/sixgaezzang/sidepeek/util/FakeDtoProvider.java b/src/test/java/sixgaezzang/sidepeek/util/FakeDtoProvider.java index 0cb86928..aa874034 100644 --- a/src/test/java/sixgaezzang/sidepeek/util/FakeDtoProvider.java +++ b/src/test/java/sixgaezzang/sidepeek/util/FakeDtoProvider.java @@ -12,7 +12,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import sixgaezzang.sidepeek.common.dto.request.UpdateUserSkillRequest; +import sixgaezzang.sidepeek.common.dto.request.SaveTechStackRequest; import sixgaezzang.sidepeek.projects.dto.request.SaveMemberRequest; import sixgaezzang.sidepeek.projects.dto.request.SaveProjectRequest; import sixgaezzang.sidepeek.users.domain.Career; @@ -22,12 +22,12 @@ public class FakeDtoProvider { // TechStack - public static UpdateUserSkillRequest createUpdateUserSkillRequest(Long skillId) { - return new UpdateUserSkillRequest(skillId, createSkillCategory()); + public static SaveTechStackRequest createUpdateUserSkillRequest(Long skillId) { + return new SaveTechStackRequest(skillId, createSkillCategory()); } - public static List createUpdateUserSkillRequests(List skillIds) { - List requests = new ArrayList<>(); + public static List createUpdateUserSkillRequests(List skillIds) { + List requests = new ArrayList<>(); for (Long skillId : skillIds) { requests.add( FakeDtoProvider.createUpdateUserSkillRequest(skillId) @@ -39,7 +39,7 @@ public static List createUpdateUserSkillRequests(List techStacks, List members + List techStacks, List members ) { return new SaveProjectRequest(name, overview, ownerId, githubUrl, description, techStacks, null, null, null, null, @@ -47,7 +47,7 @@ public static SaveProjectRequest createSaveProjectRequestOnlyRequired( } public static SaveProjectRequest createSaveProjectRequestWithOwnerIdAndOption( - List techStacks, Long ownerId, String subName, String thumbnailUrl, String deployUrl, + List techStacks, Long ownerId, String subName, String thumbnailUrl, String deployUrl, String troubleShooting, YearMonth startDate, YearMonth endDate ) { return new SaveProjectRequest( diff --git a/src/test/java/sixgaezzang/sidepeek/util/TestParameterProvider.java b/src/test/java/sixgaezzang/sidepeek/util/TestParameterProvider.java index d911b8ee..69c2f030 100644 --- a/src/test/java/sixgaezzang/sidepeek/util/TestParameterProvider.java +++ b/src/test/java/sixgaezzang/sidepeek/util/TestParameterProvider.java @@ -1,10 +1,10 @@ package sixgaezzang.sidepeek.util; -import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.CATEGORY_IS_NULL; -import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.CATEGORY_OVER_MAX_LENGTH; import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.GITHUB_URL_IS_INVALID; import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.GITHUB_URL_IS_NULL; import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.GITHUB_URL_OVER_MAX_LENGTH; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.CATEGORY_IS_NULL; +import static sixgaezzang.sidepeek.common.exception.message.TechStackErrorMessage.CATEGORY_OVER_MAX_LENGTH; import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_CATEGORY_LENGTH; import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_TEXT_LENGTH; import static sixgaezzang.sidepeek.projects.exception.message.FileErrorMessage.OVERVIEW_IMAGE_URL_IS_INVALID; @@ -47,10 +47,14 @@ import java.time.YearMonth; import java.util.Collections; +import java.util.List; +import java.util.function.Function; import java.util.stream.Stream; import org.junit.jupiter.params.provider.Arguments; +import sixgaezzang.sidepeek.projects.dto.request.SaveMemberRequest; import sixgaezzang.sidepeek.users.domain.Career; import sixgaezzang.sidepeek.users.domain.Job; +import sixgaezzang.sidepeek.users.domain.User; import sixgaezzang.sidepeek.users.dto.request.UpdateUserProfileRequest; public class TestParameterProvider { @@ -147,6 +151,34 @@ true, createNickname(), "R".repeat(MAX_ROLE_LENGTH + 1), ); } + public static Stream createDuplicatedMembers() { + String role = FakeValueProvider.createRole(); + + Function> getDuplicatedFellowMembers = + (user) -> List.of( + new SaveMemberRequest(user.getId(), user.getNickname(), role), + new SaveMemberRequest(user.getId(), user.getNickname(), role) + ); + Function> getDuplicatedNonFellowMembers = + (user) -> List.of( + new SaveMemberRequest(null, user.getNickname(), role), + new SaveMemberRequest(null, user.getNickname(), role) + ); + Function> getDuplicatedMembers = + (user) -> List.of( + new SaveMemberRequest(user.getId(), user.getNickname(), role), + new SaveMemberRequest(null, user.getNickname(), role) + ); + return Stream.of( + Arguments.of( + "회원 멤버가 중복인 경우", getDuplicatedFellowMembers), + Arguments.of( + "비회원 멤버가 중복인 경우", getDuplicatedNonFellowMembers), + Arguments.of( + "회원 멤버와 비회원 멤버가 중복인 경우", getDuplicatedMembers) + ); + } + // File public static Stream createInvalidFileInfo() { return Stream.of(