diff --git a/README.md b/README.md index 688fcda86d..63b872f70f 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,63 @@ Question - [x] answer에 다른 사람 답변이 있는 경우 - [x] 질문 삭제 - [x] 질문 삭제 - - [ ] 질문 삭제 이력 기록 - - [ ] 모든 답변 삭제 Answer - [x] 작성자 본인인지 확인 - [x] 답변 삭제 - [x] 답변 삭제 - - [ ] 답변 삭제 이력 기록 \ No newline at end of file + +--- + +### 수강 신청 기능 요구사항 +- [x] 과정(Course)은 기수 단위로 운영하며, 여러 개의 강의(Session)를 가질 수 있다. +- [x] 강의는 시작일과 종료일을 가진다. +- [x] 강의는 강의 커버 이미지 정보를 가진다. + - [x] 이미지 크기는 1MB 이하여야 한다. + - [x] 이미지 타입은 gif, jpg(jpeg 포함), png, svg만 허용한다. + - [x] 이미지의 width는 300픽셀, height는 200픽셀 이상이어야 하며, width와 height의 비율은 3:2여야 한다. +- [x] 강의는 무료 강의와 유료 강의로 나뉜다. + - [x] 무료 강의는 최대 수강 인원 제한이 없다. + - [x] 유료 강의는 강의 최대 수강 인원을 초과할 수 없다. + - [x] 유료 강의는 수강생이 결제한 금액과 수강료가 일치할 때 수강 신청이 가능하다. +- [x] 강의 상태는 준비중, 모집중, 종료 3가지 상태를 가진다. +- [x] 강의 수강신청은 강의 상태가 모집중일 때만 가능하다. + +- [x] 유료 강의의 경우 결제는 이미 완료한 것으로 가정하고 이후 과정을 구현한다. +- [x] 결제를 완료한 결제 정보는 payments 모듈을 통해 관리되며, 결제 정보는 Payment 객체에 담겨 반환된다. + +### TODO +- [x] Course + - 기수 + - List + +- [x] Sessions + - List + +- [x] Session + - SessionData(시작일, 종료일) + - 커버 이미지 정보 + - 강의 유형(무료/유료) + - 강의 상태 + +- [x] 커버 이미지 정보 + - gif, jpg, jpeg, png, svg만 허용 + - 이미지 크기 < 1 + - width >= 300, height >= 200 / width * 2 = height * 3 + +- [x] 무료 강의 + - 최대 수강 인원 제한 없음 + +- [x] 유료 강의 + - 강의 최대 수강인원 + - 강의 최대 수강인원 초과 불가 + - 수강료 + - 수강생이 결제한 금액 == 수강료 일 때만 수강신청 가능 + - 결제 완료 List + +- [x] 강의 상태 + - 준비중(Preparing)/모집중(Recruiting)/종료(Closed) + - 모집중일 때만 신청 가능 + +- [x] Payments + - List \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/Course.java b/src/main/java/nextstep/courses/domain/Course.java index 0f69716043..a591dc0fb0 100644 --- a/src/main/java/nextstep/courses/domain/Course.java +++ b/src/main/java/nextstep/courses/domain/Course.java @@ -1,5 +1,7 @@ package nextstep.courses.domain; +import nextstep.courses.domain.session.Sessions; + import java.time.LocalDateTime; public class Course { @@ -13,19 +15,29 @@ public class Course { private LocalDateTime updatedAt; + private Integer batchNumber; + + private Sessions sessions; + public Course() { } public Course(String title, Long creatorId) { - this(0L, title, creatorId, LocalDateTime.now(), null); + this(0L, title, creatorId, LocalDateTime.now(), null, null, new Sessions()); } public Course(Long id, String title, Long creatorId, LocalDateTime createdAt, LocalDateTime updatedAt) { + this(id, title, creatorId, createdAt, updatedAt, null, new Sessions()); + } + + public Course(Long id, String title, Long creatorId, LocalDateTime createdAt, LocalDateTime updatedAt, Integer batchNumber, Sessions sessions) { this.id = id; this.title = title; this.creatorId = creatorId; this.createdAt = createdAt; this.updatedAt = updatedAt; + this.batchNumber = batchNumber; + this.sessions = sessions; } public String getTitle() { diff --git a/src/main/java/nextstep/courses/domain/session/FreeSession.java b/src/main/java/nextstep/courses/domain/session/FreeSession.java new file mode 100644 index 0000000000..4518eb22c5 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/FreeSession.java @@ -0,0 +1,10 @@ +package nextstep.courses.domain.session; + +import nextstep.payments.domain.Payment; + +public class FreeSession implements SessionStrategy { + @Override + public boolean canEnroll(Payment payment) { + return true; + } +} diff --git a/src/main/java/nextstep/courses/domain/session/PaidSession.java b/src/main/java/nextstep/courses/domain/session/PaidSession.java new file mode 100644 index 0000000000..599a81823c --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/PaidSession.java @@ -0,0 +1,35 @@ +package nextstep.courses.domain.session; + +import nextstep.payments.domain.Payments; +import nextstep.payments.domain.Payment; + +public class PaidSession implements SessionStrategy { + + private int maxEnrollmentCount; + private int currentEnrollmentCount; + private int tuitionFee; + + private Payments payments; + + public PaidSession(int maxEnrollmentCount, int currentEnrollmentCount, int tuitionFee){ + this.maxEnrollmentCount = maxEnrollmentCount; + this.currentEnrollmentCount = currentEnrollmentCount; + this.tuitionFee = tuitionFee; + this.payments = new Payments(); + } + + private boolean isFull() { + return maxEnrollmentCount <= currentEnrollmentCount; + } + + public void enroll(Payment payment){ //todo + if(canEnroll(payment)){ + payments.add(payment); + } + } + + @Override + public boolean canEnroll(Payment payment) { + return !isFull() && payment.isTuitionPaid(tuitionFee); + } +} diff --git a/src/main/java/nextstep/courses/domain/session/Session.java b/src/main/java/nextstep/courses/domain/session/Session.java new file mode 100644 index 0000000000..a5c4b37549 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/Session.java @@ -0,0 +1,37 @@ +package nextstep.courses.domain.session; + +import nextstep.courses.domain.session.coverImage.SessionCoverImage; +import nextstep.payments.domain.Payment; + +import java.time.LocalDate; + +public class Session { + + private SessionDate sessionDate; + private SessionCoverImage sessionCoverImage; + private SessionStatus sessionStatus; + private SessionStrategy sessionStrategy; + + public Session(SessionCoverImage sessionCoverImage, SessionStatus sessionStatus, SessionStrategy sessionStrategy) { + this(null, null, sessionCoverImage, sessionStatus, sessionStrategy); + } + + public Session(LocalDate startDate, LocalDate endDate, SessionCoverImage sessionCoverImage, SessionStatus sessionStatus, SessionStrategy sessionStrategy) { + this.sessionDate = new SessionDate(startDate, endDate); + this.sessionCoverImage = sessionCoverImage; + this.sessionStatus = sessionStatus; + this.sessionStrategy = sessionStrategy; + } + + public boolean isValidCoverImage() { + return sessionCoverImage.isValidCoverImage(); + } + + public boolean canEnroll(Payment payment) { + return sessionStrategy.canEnroll(payment) && isRecruiting(); + } + + private boolean isRecruiting() { + return sessionStatus.isRecruiting(); + } +} diff --git a/src/main/java/nextstep/courses/domain/session/SessionDate.java b/src/main/java/nextstep/courses/domain/session/SessionDate.java new file mode 100644 index 0000000000..581deb8fbd --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/SessionDate.java @@ -0,0 +1,13 @@ +package nextstep.courses.domain.session; + +import java.time.LocalDate; + +public class SessionDate { + private LocalDate startDate; + private LocalDate endDate; + + public SessionDate(LocalDate startDate, LocalDate endDate){ + this.startDate = startDate; + this.endDate = endDate; + } +} diff --git a/src/main/java/nextstep/courses/domain/session/SessionStatus.java b/src/main/java/nextstep/courses/domain/session/SessionStatus.java new file mode 100644 index 0000000000..c8ff6e5710 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/SessionStatus.java @@ -0,0 +1,12 @@ +package nextstep.courses.domain.session; + +public enum SessionStatus { + + PREPARING, + RECRUITING, + CLOSED; + + public boolean isRecruiting(){ + return this == RECRUITING; + } +} diff --git a/src/main/java/nextstep/courses/domain/session/SessionStrategy.java b/src/main/java/nextstep/courses/domain/session/SessionStrategy.java new file mode 100644 index 0000000000..0388301a0c --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/SessionStrategy.java @@ -0,0 +1,8 @@ +package nextstep.courses.domain.session; + +import nextstep.payments.domain.Payment; + +@FunctionalInterface +public interface SessionStrategy { + boolean canEnroll(Payment payment); +} diff --git a/src/main/java/nextstep/courses/domain/session/Sessions.java b/src/main/java/nextstep/courses/domain/session/Sessions.java new file mode 100644 index 0000000000..ec563f2eba --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/Sessions.java @@ -0,0 +1,7 @@ +package nextstep.courses.domain.session; + +import java.util.List; + +public class Sessions { + private List values; +} diff --git a/src/main/java/nextstep/courses/domain/session/coverImage/ImageDimensions.java b/src/main/java/nextstep/courses/domain/session/coverImage/ImageDimensions.java new file mode 100644 index 0000000000..ca1d571dec --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/coverImage/ImageDimensions.java @@ -0,0 +1,26 @@ +package nextstep.courses.domain.session.coverImage; + +public class ImageDimensions { + private int width; + private int height; + + private static final int MIN_WIDTH = 300; + private static final int MIN_HEIGHT = 200; + private static final int WIDTH_RATIO = 3; + private static final int HEIGHT_RATIO = 2; + + public ImageDimensions(int width, int height) { + this.width = width; + this.height = height; + } + + public boolean validDimensions() { + if (width < MIN_WIDTH || height < MIN_HEIGHT) { + throw new IllegalArgumentException("이미지의 너비는 300픽셀, 높이는 200픽셀 이상이어야 합니다."); + } + if (width * HEIGHT_RATIO != height * WIDTH_RATIO) { + throw new IllegalArgumentException("너비와 높이의 비율은 3:2여야 합니다."); + } + return true; + } +} diff --git a/src/main/java/nextstep/courses/domain/session/coverImage/ImageExtension.java b/src/main/java/nextstep/courses/domain/session/coverImage/ImageExtension.java new file mode 100644 index 0000000000..c3b5551541 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/coverImage/ImageExtension.java @@ -0,0 +1,23 @@ +package nextstep.courses.domain.session.coverImage; + +import java.util.Arrays; +import java.util.List; + +public enum ImageExtension { + GIF, + JPG, + JPEG, + PNG, + SVG, + BMP; + + private static final List VALID_EXTENSION = Arrays.asList(GIF, JPG, JPEG, PNG, SVG); + + public static boolean validExtension(ImageExtension extension) { + if (!VALID_EXTENSION.contains(extension)) { + throw new IllegalArgumentException("허용되지 않은 확장자 입니다."); + } + return true; + } + +} diff --git a/src/main/java/nextstep/courses/domain/session/coverImage/ImageSize.java b/src/main/java/nextstep/courses/domain/session/coverImage/ImageSize.java new file mode 100644 index 0000000000..1d5d858967 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/coverImage/ImageSize.java @@ -0,0 +1,18 @@ +package nextstep.courses.domain.session.coverImage; + +public class ImageSize { + private int size; + + private static final int MAX_SIZE = 1; + + public ImageSize(int size) { + this.size = size; + } + + public boolean validSize() { + if (size > MAX_SIZE) { + throw new IllegalArgumentException("이미지는 1MB 이하여야 합니다."); + } + return true; + } +} diff --git a/src/main/java/nextstep/courses/domain/session/coverImage/SessionCoverImage.java b/src/main/java/nextstep/courses/domain/session/coverImage/SessionCoverImage.java new file mode 100644 index 0000000000..4e740b80a5 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/coverImage/SessionCoverImage.java @@ -0,0 +1,23 @@ +package nextstep.courses.domain.session.coverImage; + +public class SessionCoverImage { + private ImageSize imageSize; + private ImageExtension imageExtension; + private ImageDimensions imageDimensions; + + public SessionCoverImage(int size, ImageExtension imageExtension, int width, int height) { + this(new ImageSize(size), imageExtension, new ImageDimensions(width, height)); + } + + public SessionCoverImage(ImageSize imageSize, ImageExtension imageExtension, ImageDimensions imageDimensions) { + this.imageSize = imageSize; + this.imageExtension = imageExtension; + this.imageDimensions = imageDimensions; + } + + public boolean isValidCoverImage() { + return imageSize.validSize() + && ImageExtension.validExtension(imageExtension) + && imageDimensions.validDimensions(); + } +} diff --git a/src/main/java/nextstep/payments/domain/Payment.java b/src/main/java/nextstep/payments/domain/Payment.java index 57d833f851..db2f651042 100644 --- a/src/main/java/nextstep/payments/domain/Payment.java +++ b/src/main/java/nextstep/payments/domain/Payment.java @@ -19,6 +19,10 @@ public class Payment { public Payment() { } + public Payment(Long amount) { + this(null, null, null, amount); + } + public Payment(String id, Long sessionId, Long nsUserId, Long amount) { this.id = id; this.sessionId = sessionId; @@ -26,4 +30,8 @@ public Payment(String id, Long sessionId, Long nsUserId, Long amount) { this.amount = amount; this.createdAt = LocalDateTime.now(); } + + public boolean isTuitionPaid(int tuitionFee) { + return tuitionFee == amount; + } } diff --git a/src/main/java/nextstep/payments/domain/Payments.java b/src/main/java/nextstep/payments/domain/Payments.java new file mode 100644 index 0000000000..297365d799 --- /dev/null +++ b/src/main/java/nextstep/payments/domain/Payments.java @@ -0,0 +1,12 @@ +package nextstep.payments.domain; + +import java.util.ArrayList; +import java.util.List; + +public class Payments { + private List values = new ArrayList<>(); + + public void add(Payment payment){ + values.add(payment); + } +} diff --git a/src/main/java/nextstep/qna/domain/Answer.java b/src/main/java/nextstep/qna/domain/Answer.java index 4ed8dba7e0..6c8b1e8622 100644 --- a/src/main/java/nextstep/qna/domain/Answer.java +++ b/src/main/java/nextstep/qna/domain/Answer.java @@ -2,10 +2,8 @@ import nextstep.qna.NotFoundException; import nextstep.qna.UnAuthorizedException; -import nextstep.qna.service.DeleteHistoryService; import nextstep.users.domain.NsUser; -import javax.annotation.Resource; import java.time.LocalDateTime; public class Answer { @@ -17,7 +15,7 @@ public class Answer { private String contents; - private boolean deleted = false; + private Deleted deleted; private LocalDateTime createdDate = LocalDateTime.now(); @@ -43,19 +41,15 @@ public Answer(Long id, NsUser writer, Question question, String contents) { this.writer = writer; this.question = question; this.contents = contents; + this.deleted = new Deleted(); } public Long getId() { return id; } - public Answer setDeleted(boolean deleted) { - this.deleted = deleted; - return this; - } - public boolean isDeleted() { - return deleted; + return this.deleted.isDeleted(); } public boolean isOwner(NsUser writer) { @@ -66,17 +60,13 @@ public NsUser getWriter() { return writer; } - public String getContents() { - return contents; - } - public void toQuestion(Question question) { this.question = question; } public DeleteHistory delete() { - this.setDeleted(true); - return new DeleteHistory(ContentType.ANSWER, this.id, this.writer, LocalDateTime.now()); + this.deleted.setDeleted(true); + return DeleteHistory.createAnswerDeleteHistory(this.id, this.writer, createdDate); } @Override diff --git a/src/main/java/nextstep/qna/domain/Answers.java b/src/main/java/nextstep/qna/domain/Answers.java new file mode 100644 index 0000000000..364382818f --- /dev/null +++ b/src/main/java/nextstep/qna/domain/Answers.java @@ -0,0 +1,36 @@ +package nextstep.qna.domain; + +import nextstep.qna.CannotDeleteException; +import nextstep.users.domain.NsUser; + +import java.util.ArrayList; +import java.util.List; + +public class Answers { + + private List answers = new ArrayList<>(); + + public void checkDeletePermission(NsUser loginUser) throws CannotDeleteException { + for (Answer answer : this.answers) { + checkAnswerOwner(answer, loginUser); + } + } + + private void checkAnswerOwner(Answer answer, NsUser loginUser) throws CannotDeleteException { + if (!answer.isOwner(loginUser)) { + throw new CannotDeleteException("다른 사람이 쓴 답변이 있어 삭제할 수 없습니다."); + } + } + + public void add(Answer answer){ + this.answers.add(answer); + } + + public List deleteAnswers() { + List deleteHistories = new ArrayList<>(); + for (Answer answer : answers) { + deleteHistories.add(answer.delete()); + } + return deleteHistories; + } +} diff --git a/src/main/java/nextstep/qna/domain/DeleteHistory.java b/src/main/java/nextstep/qna/domain/DeleteHistory.java index 43c37e5e5c..ce789b5987 100644 --- a/src/main/java/nextstep/qna/domain/DeleteHistory.java +++ b/src/main/java/nextstep/qna/domain/DeleteHistory.java @@ -26,6 +26,15 @@ public DeleteHistory(ContentType contentType, Long contentId, NsUser deletedBy, this.createdDate = createdDate; } + public static DeleteHistory createAnswerDeleteHistory(Long contentId, NsUser deletedBy, LocalDateTime createdDate){ + return new DeleteHistory(ContentType.ANSWER, contentId, deletedBy, createdDate); + } + + + public static DeleteHistory createQuestionDeleteHistory(Long contentId, NsUser deletedBy, LocalDateTime createdDate){ + return new DeleteHistory(ContentType.QUESTION, contentId, deletedBy, createdDate); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/nextstep/qna/domain/Deleted.java b/src/main/java/nextstep/qna/domain/Deleted.java new file mode 100644 index 0000000000..0aebb1a5ac --- /dev/null +++ b/src/main/java/nextstep/qna/domain/Deleted.java @@ -0,0 +1,14 @@ +package nextstep.qna.domain; + +public class Deleted { + private boolean deleted = false; + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(Boolean deleted){ + this.deleted = deleted; + } + +} diff --git a/src/main/java/nextstep/qna/domain/Question.java b/src/main/java/nextstep/qna/domain/Question.java index 3c0c8c6017..8abee3a6bd 100644 --- a/src/main/java/nextstep/qna/domain/Question.java +++ b/src/main/java/nextstep/qna/domain/Question.java @@ -9,22 +9,19 @@ public class Question { private Long id; - - private String title; - - private String contents; - + private QuestionBody questionBody; private NsUser writer; - private List answers = new ArrayList<>(); + private Answers answers; - private boolean deleted = false; + private Deleted deleted; private LocalDateTime createdDate = LocalDateTime.now(); private LocalDateTime updatedDate; public Question() { + this(null, null, null, null); } public Question(NsUser writer, String title, String contents) { @@ -34,93 +31,51 @@ public Question(NsUser writer, String title, String contents) { public Question(Long id, NsUser writer, String title, String contents) { this.id = id; this.writer = writer; - this.title = title; - this.contents = contents; + this.questionBody = new QuestionBody(title, contents); + this.answers = new Answers(); + this.deleted = new Deleted(); } public Long getId() { return id; } - public String getTitle() { - return title; - } - - public Question setTitle(String title) { - this.title = title; - return this; - } - - public String getContents() { - return contents; - } - - public Question setContents(String contents) { - this.contents = contents; - return this; - } - public NsUser getWriter() { return writer; } public void addAnswer(Answer answer) { answer.toQuestion(this); - answers.add(answer); + this.answers.add(answer); } private boolean isOwner(NsUser loginUser) { return writer.equals(loginUser); } + public boolean isDeleted() { + return deleted.isDeleted(); + } + public void checkDeletePermission(NsUser loginUser) throws CannotDeleteException { if (!this.isOwner(loginUser)) { throw new CannotDeleteException("질문을 삭제할 권한이 없습니다."); } - for (Answer answer : this.answers) { - checkAnswerOwner(answer, loginUser); - } - } - - //todo owner가 맞는지 체크하는 로직은 Answer에 있어야 할 것 같은데, - // Exception 문구를 보면 Question에 있어야할 내용 같아서 이곳에 작성함. - - // 테스트만 아니면 public으로 작성할 필요가 없을 것 같아 고민됨. - public void checkAnswerOwner(Answer answer, NsUser loginUser) throws CannotDeleteException { - if (!answer.isOwner(loginUser)) { - throw new CannotDeleteException("다른 사람이 쓴 답변이 있어 삭제할 수 없습니다."); - } - } - - public Question setDeleted(boolean deleted) { - this.deleted = deleted; - return this; - } - - public boolean isDeleted() { - return deleted; + this.answers.checkDeletePermission(loginUser); } public List delete(NsUser loginUser) throws CannotDeleteException { checkDeletePermission(loginUser); + deleted.setDeleted(true); List deleteHistories = new ArrayList<>(); - this.setDeleted(true); - deleteHistories.add(new DeleteHistory(ContentType.QUESTION, this.id, this.writer, LocalDateTime.now())); - deleteHistories.addAll(deleteAnswers()); - return deleteHistories; - } - - private List deleteAnswers() { - List deleteHistories = new ArrayList<>(); - for (Answer answer : answers) { - deleteHistories.add(answer.delete()); - } + deleteHistories.add(DeleteHistory.createQuestionDeleteHistory(this.id, this.writer, createdDate)); + deleteHistories.addAll(this.answers.deleteAnswers()); return deleteHistories; } @Override public String toString() { - return "Question [id=" + getId() + ", title=" + title + ", contents=" + contents + ", writer=" + writer + "]"; + return "Question [id=" + getId() + ", " + questionBody.toString() + " writer=" + writer + "]"; } } diff --git a/src/main/java/nextstep/qna/domain/QuestionBody.java b/src/main/java/nextstep/qna/domain/QuestionBody.java new file mode 100644 index 0000000000..6ffbc3f7cc --- /dev/null +++ b/src/main/java/nextstep/qna/domain/QuestionBody.java @@ -0,0 +1,18 @@ +package nextstep.qna.domain; + +public class QuestionBody { + + private String title; + private String contents; + + public QuestionBody(String title, String contents){ + this.title = title; + this.contents = contents; + } + + @Override + public String toString() { + return "title='" + title + '\'' + + ", contents='" + contents; + } +} diff --git a/src/test/java/nextstep/courses/infrastructure/FreeSessionTest.java b/src/test/java/nextstep/courses/infrastructure/FreeSessionTest.java new file mode 100644 index 0000000000..94101721a3 --- /dev/null +++ b/src/test/java/nextstep/courses/infrastructure/FreeSessionTest.java @@ -0,0 +1,18 @@ +package nextstep.courses.infrastructure; + +import nextstep.courses.domain.session.FreeSession; +import nextstep.payments.domain.Payment; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class FreeSessionTest { + + private FreeSession freeSession; + + @Test + void 수강신청_가능여부_확인() { + freeSession = new FreeSession(); + assertTrue(freeSession.canEnroll(new Payment(0L))); + } +} diff --git a/src/test/java/nextstep/courses/infrastructure/PaidSessionTest.java b/src/test/java/nextstep/courses/infrastructure/PaidSessionTest.java new file mode 100644 index 0000000000..2127266429 --- /dev/null +++ b/src/test/java/nextstep/courses/infrastructure/PaidSessionTest.java @@ -0,0 +1,31 @@ +package nextstep.courses.infrastructure; + +import nextstep.courses.domain.session.PaidSession; +import nextstep.payments.domain.Payment; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class PaidSessionTest { + + private PaidSession paidSession; + + @Test + void 수강신청_가능여부_확인__강의_수강료_확인() { + paidSession = new PaidSession(3, 2, 20000); + assertTrue(paidSession.canEnroll(new Payment(20000L))); + paidSession = new PaidSession(3, 2, 20000); + assertFalse(paidSession.canEnroll(new Payment(15000L))); + } + + @Test + void 수강신청_가능여부_확인__인원초과_확인() { + + paidSession = new PaidSession(3, 2, 20000); + assertTrue(paidSession.canEnroll(new Payment(20000L))); + paidSession = new PaidSession(2, 2, 20000); + assertFalse(paidSession.canEnroll(new Payment(20000L))); + } + +} diff --git a/src/test/java/nextstep/courses/infrastructure/SessionCoverImageTest.java b/src/test/java/nextstep/courses/infrastructure/SessionCoverImageTest.java new file mode 100644 index 0000000000..9be9312943 --- /dev/null +++ b/src/test/java/nextstep/courses/infrastructure/SessionCoverImageTest.java @@ -0,0 +1,38 @@ +package nextstep.courses.infrastructure; + +import nextstep.courses.domain.session.coverImage.ImageExtension; +import nextstep.courses.domain.session.coverImage.SessionCoverImage; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class SessionCoverImageTest { + @Test + void 커버_이미지_확인__유효한_이미지() { + SessionCoverImage image1 = new SessionCoverImage(1, ImageExtension.GIF, 300, 200); + assertTrue(image1.isValidCoverImage()); + } + + @Test + void 커버_이미지_확인__유효하지_않은_확장자() { + SessionCoverImage image2 = new SessionCoverImage(1, ImageExtension.BMP, 300, 200); + assertFalse(image2.isValidCoverImage()); + } + + @Test + void 커버_이미지_확인__유효하지_않은_이미지_사이즈() { + SessionCoverImage image1 = new SessionCoverImage(2, ImageExtension.GIF, 200, 200); + assertFalse(image1.isValidCoverImage()); + } + + @Test + void 커버_이미지_확인__유효하지_않은_이미지_너비_높이() { + SessionCoverImage image2 = new SessionCoverImage(1, ImageExtension.GIF, 200, 200); + assertFalse(image2.isValidCoverImage()); + SessionCoverImage image3 = new SessionCoverImage(1, ImageExtension.GIF, 300, 300); + assertFalse(image3.isValidCoverImage()); + SessionCoverImage image4 = new SessionCoverImage(1, ImageExtension.GIF, 300, 400); + assertFalse(image4.isValidCoverImage()); + } +} diff --git a/src/test/java/nextstep/courses/infrastructure/SessionStatusTest.java b/src/test/java/nextstep/courses/infrastructure/SessionStatusTest.java new file mode 100644 index 0000000000..eb33f0f331 --- /dev/null +++ b/src/test/java/nextstep/courses/infrastructure/SessionStatusTest.java @@ -0,0 +1,17 @@ +package nextstep.courses.infrastructure; + +import nextstep.courses.domain.session.SessionStatus; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class SessionStatusTest { + + @Test + @DisplayName("강의 상태가 모집중일 때만 신청이 가능하다.") + void 강의_상태_모집중(){ + SessionStatus sessionStatus = SessionStatus.RECRUITING; + assertTrue(sessionStatus.isRecruiting()); + } +} diff --git a/src/test/java/nextstep/courses/infrastructure/SessionTest.java b/src/test/java/nextstep/courses/infrastructure/SessionTest.java new file mode 100644 index 0000000000..3f10aa9307 --- /dev/null +++ b/src/test/java/nextstep/courses/infrastructure/SessionTest.java @@ -0,0 +1,53 @@ +package nextstep.courses.infrastructure; + +import nextstep.courses.domain.session.FreeSession; +import nextstep.courses.domain.session.PaidSession; +import nextstep.courses.domain.session.Session; +import nextstep.courses.domain.session.SessionStatus; +import nextstep.courses.domain.session.coverImage.ImageExtension; +import nextstep.courses.domain.session.coverImage.SessionCoverImage; +import nextstep.payments.domain.Payment; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class SessionTest { + + private Session session; + + @Test + void 커버_이미지_확인() { + session = new Session(new SessionCoverImage(1, ImageExtension.GIF, 300, 200), SessionStatus.RECRUITING, (payment) -> true); + assertTrue(session.isValidCoverImage()); + } + + @Test + void 수강신청_가능여부_확인__인원초과_확인() { + session = new Session(new SessionCoverImage(1, ImageExtension.GIF, 300, 200), SessionStatus.RECRUITING, new PaidSession(3, 2, 20000)); + assertTrue(session.canEnroll(new Payment(20000L))); + session = new Session(new SessionCoverImage(1, ImageExtension.GIF, 300, 200), SessionStatus.RECRUITING, new PaidSession(2, 2, 20000)); + assertFalse(session.canEnroll(new Payment(20000L))); + } + + @Test + void 수강신청_가능여부_확인__강의_수강료_확인() { + session = new Session(new SessionCoverImage(1, ImageExtension.GIF, 300, 200), SessionStatus.RECRUITING, new PaidSession(3, 2, 20000)); + assertTrue(session.canEnroll(new Payment(20000L))); + session = new Session(new SessionCoverImage(1, ImageExtension.GIF, 300, 200), SessionStatus.RECRUITING, new PaidSession(3, 2, 20000)); + assertFalse(session.canEnroll(new Payment(15000L))); + } + + @Test + void 수강신청_가능여부_확인__강의_상태_모집중() { + session = new Session(new SessionCoverImage(1, ImageExtension.GIF, 300, 200), SessionStatus.RECRUITING, (payment) -> true); + assertTrue(session.canEnroll(new Payment(20000L))); + + session = new Session(new SessionCoverImage(1, ImageExtension.GIF, 300, 200), SessionStatus.CLOSED, new FreeSession()); + assertFalse(session.canEnroll(new Payment(0L))); + + session = new Session(new SessionCoverImage(1, ImageExtension.GIF, 300, 200), SessionStatus.CLOSED, new PaidSession(3, 2, 20000)); + assertFalse(session.canEnroll(new Payment(20000L))); + } + +} diff --git a/src/test/java/nextstep/qna/domain/QuestionTest.java b/src/test/java/nextstep/qna/domain/QuestionTest.java index b9934bb646..9fc23ffc68 100644 --- a/src/test/java/nextstep/qna/domain/QuestionTest.java +++ b/src/test/java/nextstep/qna/domain/QuestionTest.java @@ -20,11 +20,9 @@ public class QuestionTest { @Test void 질문_삭제_권한없음__다른_사람_답변_존재(){ + Q1.addAnswer(new Answer(NsUserTest.JAVAJIGI, QuestionTest.Q1, "Answers Contents1")); assertThatThrownBy(() -> { - Q1.checkAnswerOwner( - new Answer(NsUserTest.JAVAJIGI, QuestionTest.Q1, "Answers Contents1"), - NsUserTest.SANJIGI - ); + Q1.checkDeletePermission(NsUserTest.SANJIGI); }).isInstanceOf(CannotDeleteException.class); }