diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/course/storage/CourseEntity.kt b/src/main/kotlin/com/yourssu/soongpt/domain/course/CourseEntity.kt similarity index 95% rename from src/main/kotlin/com/yourssu/soongpt/domain/course/storage/CourseEntity.kt rename to src/main/kotlin/com/yourssu/soongpt/domain/course/CourseEntity.kt index 1a03819..b52b0b1 100644 --- a/src/main/kotlin/com/yourssu/soongpt/domain/course/storage/CourseEntity.kt +++ b/src/main/kotlin/com/yourssu/soongpt/domain/course/CourseEntity.kt @@ -1,4 +1,4 @@ -package com.yourssu.soongpt.domain.course.storage +package com.yourssu.soongpt.domain.course import com.yourssu.soongpt.domain.course.implement.Classification import com.yourssu.soongpt.domain.course.implement.Course diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/course/storage/CourseRepositoryImpl.kt b/src/main/kotlin/com/yourssu/soongpt/domain/course/CourseRepositoryImpl.kt similarity index 65% rename from src/main/kotlin/com/yourssu/soongpt/domain/course/storage/CourseRepositoryImpl.kt rename to src/main/kotlin/com/yourssu/soongpt/domain/course/CourseRepositoryImpl.kt index 5cc3d39..51326e9 100644 --- a/src/main/kotlin/com/yourssu/soongpt/domain/course/storage/CourseRepositoryImpl.kt +++ b/src/main/kotlin/com/yourssu/soongpt/domain/course/CourseRepositoryImpl.kt @@ -1,10 +1,11 @@ -package com.yourssu.soongpt.domain.course.storage +package com.yourssu.soongpt.domain.course import com.querydsl.jpa.impl.JPAQueryFactory +import com.yourssu.soongpt.domain.course.QCourseEntity.courseEntity import com.yourssu.soongpt.domain.course.implement.Classification import com.yourssu.soongpt.domain.course.implement.Course import com.yourssu.soongpt.domain.course.implement.CourseRepository -import com.yourssu.soongpt.domain.course.storage.QCourseEntity.courseEntity +import com.yourssu.soongpt.domain.course.implement.Courses import com.yourssu.soongpt.domain.departmentGrade.storage.QDepartmentGradeEntity.departmentGradeEntity import com.yourssu.soongpt.domain.target.storage.QTargetEntity.targetEntity import org.springframework.data.jpa.repository.JpaRepository @@ -40,6 +41,26 @@ class CourseRepositoryImpl( .fetch() .map { it.toDomain() } } + + override fun findByDepartmentIdAndCourseName( + departmentId: Long, + courseName: String, + classification: Classification + ): Courses { + val courses = jpaQueryFactory.selectFrom(courseEntity) + .innerJoin(targetEntity) + .on(courseEntity.id.eq(targetEntity.courseId)) + .innerJoin(departmentGradeEntity) + .on(targetEntity.departmentGradeId.eq(departmentGradeEntity.id)) + .where( + departmentGradeEntity.departmentId.eq(departmentId), + courseEntity.courseName.eq(courseName), + courseEntity.classification.eq(classification) + ) + .fetch() + .map { it.toDomain() } + return Courses(courses) + } } interface CourseJpaRepository : JpaRepository { diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/course/business/CourseService.kt b/src/main/kotlin/com/yourssu/soongpt/domain/course/business/CourseService.kt index 85a9bb3..fc8f45d 100644 --- a/src/main/kotlin/com/yourssu/soongpt/domain/course/business/CourseService.kt +++ b/src/main/kotlin/com/yourssu/soongpt/domain/course/business/CourseService.kt @@ -10,11 +10,11 @@ import com.yourssu.soongpt.domain.courseTime.implement.CourseTimeReader import com.yourssu.soongpt.domain.courseTime.implement.CourseTimeWriter import com.yourssu.soongpt.domain.department.implement.DepartmentReader import com.yourssu.soongpt.domain.departmentGrade.implement.DepartmentGradeReader +import com.yourssu.soongpt.domain.target.implement.Target import com.yourssu.soongpt.domain.target.implement.TargetReader +import com.yourssu.soongpt.domain.target.implement.TargetWriter import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import com.yourssu.soongpt.domain.target.implement.Target -import com.yourssu.soongpt.domain.target.implement.TargetWriter @Service class CourseService( diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/CourseReader.kt b/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/CourseReader.kt index 8c02c2a..393e873 100644 --- a/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/CourseReader.kt +++ b/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/CourseReader.kt @@ -1,5 +1,6 @@ package com.yourssu.soongpt.domain.course.implement +import com.yourssu.soongpt.domain.course.implement.exception.CourseNotFoundException import org.springframework.stereotype.Component @Component @@ -17,4 +18,24 @@ class CourseReader( fun findAllByDepartmentIdInGeneralRequired(departmentId: Long): List { return courseRepository.findAllByDepartmentId(departmentId, Classification.GENERAL_REQUIRED) } + + fun findAllByCourseNameInMajorRequired(departmentId: Long, courseName: String): Courses { + return findAllByCourseName(departmentId, courseName, Classification.MAJOR_REQUIRED) + } + + fun findAllByCourseNameInMajorElective(departmentId: Long, courseName: String): Courses { + return findAllByCourseName(departmentId, courseName, Classification.MAJOR_ELECTIVE) + } + + fun findAllByCourseNameInGeneralRequired(departmentId: Long, courseName: String): Courses { + return findAllByCourseName(departmentId, courseName, Classification.GENERAL_REQUIRED) + } + + private fun findAllByCourseName(departmentId: Long, courseName: String, classification: Classification): Courses { + val courses = courseRepository.findByDepartmentIdAndCourseName(departmentId, courseName, classification) + if (courses.isEmpty()) { + throw CourseNotFoundException(courseName = courseName) + } + return courses + } } diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/CourseRepository.kt b/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/CourseRepository.kt index 9aaf791..11e41c0 100644 --- a/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/CourseRepository.kt +++ b/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/CourseRepository.kt @@ -4,4 +4,5 @@ interface CourseRepository { fun save(course: Course): Course fun findAllByDepartmentId(departmentId: Long, classification: Classification): List fun getAll(ids: List): List + fun findByDepartmentIdAndCourseName(departmentId: Long, courseName: String, classification: Classification): Courses } diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/Courses.kt b/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/Courses.kt new file mode 100644 index 0000000..1f5abd1 --- /dev/null +++ b/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/Courses.kt @@ -0,0 +1,13 @@ +package com.yourssu.soongpt.domain.course.implement + +class Courses( + val courses: List, +) { + fun isEmpty(): Boolean { + return courses.isEmpty() + } + + fun unpackNameAndProfessor(): List> { + return courses.map { it.courseName to it.professorName!! } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/CoursesFactory.kt b/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/CoursesFactory.kt new file mode 100644 index 0000000..56a5115 --- /dev/null +++ b/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/CoursesFactory.kt @@ -0,0 +1,23 @@ +package com.yourssu.soongpt.domain.course.implement + +import com.yourssu.soongpt.domain.course.implement.exception.InvalidTimetableRequestException +import org.springframework.stereotype.Component + +@Component +class CoursesFactory { + fun generateTimetableCandidates( + coursesCandidates: List + ): List { + return coursesCandidates.fold(listOf(emptyList())) { acc, courses -> + acc.flatMap { currentCombination -> + courses.courses.map { course -> currentCombination + course } + } + }.map { Courses(it) } + } + + fun validateEmpty(timetableCandidates: List) { + if (timetableCandidates.isEmpty()) { + throw InvalidTimetableRequestException() + } + } +} diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/exception/CourseNotFoundException.kt b/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/exception/CourseNotFoundException.kt new file mode 100644 index 0000000..e80a73a --- /dev/null +++ b/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/exception/CourseNotFoundException.kt @@ -0,0 +1,8 @@ +package com.yourssu.soongpt.domain.course.implement.exception + +import com.yourssu.soongpt.common.handler.NotFoundException + +class CourseNotFoundException( + val courseName: String = "", +) : NotFoundException(message = "해당하는 과목이 없습니다. 과목 이름: {$courseName}") { +} diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/exception/InvalidCoursesException.kt b/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/exception/InvalidCoursesException.kt new file mode 100644 index 0000000..021dd00 --- /dev/null +++ b/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/exception/InvalidCoursesException.kt @@ -0,0 +1,3 @@ +package com.yourssu.soongpt.domain.course.implement.exception + +class InvalidCoursesException : RuntimeException() diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/exception/InvalidTimetableRequestException.kt b/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/exception/InvalidTimetableRequestException.kt new file mode 100644 index 0000000..84ecea7 --- /dev/null +++ b/src/main/kotlin/com/yourssu/soongpt/domain/course/implement/exception/InvalidTimetableRequestException.kt @@ -0,0 +1,7 @@ +package com.yourssu.soongpt.domain.course.implement.exception + +import com.yourssu.soongpt.common.handler.BadRequestException + +class InvalidTimetableRequestException : BadRequestException(message = "시간표가 나올 수 있는 경우의 수가 없습니다.") { + +} diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/course/storage/exception/CourseNotFoundException.kt b/src/main/kotlin/com/yourssu/soongpt/domain/course/storage/exception/CourseNotFoundException.kt deleted file mode 100644 index 2635bb5..0000000 --- a/src/main/kotlin/com/yourssu/soongpt/domain/course/storage/exception/CourseNotFoundException.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.yourssu.soongpt.domain.course.storage.exception - -import com.yourssu.soongpt.common.handler.NotFoundException - -class CourseNotFoundException : NotFoundException(message = "해당하는 과목이 없습니다.") { -} diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/rating/application/dto/RatingCreatedRequest.kt b/src/main/kotlin/com/yourssu/soongpt/domain/rating/application/dto/RatingCreatedRequest.kt new file mode 100644 index 0000000..f29a70d --- /dev/null +++ b/src/main/kotlin/com/yourssu/soongpt/domain/rating/application/dto/RatingCreatedRequest.kt @@ -0,0 +1,19 @@ +package com.yourssu.soongpt.domain.rating.application.dto + +import com.yourssu.soongpt.domain.rating.business.RatingCreatedCommand + +data class RatingCreatedRequest( + val course: String, + val professor: String, + val star: Double, + val point: Double +) { + fun toCommand(): RatingCreatedCommand { + return RatingCreatedCommand( + course = course, + professor = professor, + star = star, + point = point + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/rating/business/RatingCreatedCommand.kt b/src/main/kotlin/com/yourssu/soongpt/domain/rating/business/RatingCreatedCommand.kt new file mode 100644 index 0000000..07bdb10 --- /dev/null +++ b/src/main/kotlin/com/yourssu/soongpt/domain/rating/business/RatingCreatedCommand.kt @@ -0,0 +1,19 @@ +package com.yourssu.soongpt.domain.rating.business + +import com.yourssu.soongpt.domain.rating.implement.Rating + +class RatingCreatedCommand( + val course: String, + val professor: String, + val star: Double, + val point: Double, +) { + fun toRating(): Rating { + return Rating( + courseName = course, + professorName = professor, + star = star, + point = point, + ) + } +} diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/rating/business/dto/RatingResponse.kt b/src/main/kotlin/com/yourssu/soongpt/domain/rating/business/dto/RatingResponse.kt new file mode 100644 index 0000000..1310596 --- /dev/null +++ b/src/main/kotlin/com/yourssu/soongpt/domain/rating/business/dto/RatingResponse.kt @@ -0,0 +1,21 @@ +package com.yourssu.soongpt.domain.rating.business.dto + +import com.yourssu.soongpt.domain.rating.implement.Rating + +data class RatingResponse( + val course: String, + val professor: String, + val star: Double, + val point: Double, +) { + companion object { + fun from(rating: Rating): RatingResponse { + return RatingResponse( + course = rating.courseName, + professor = rating.professorName, + star = rating.star, + point = rating.point, + ) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/rating/implement/Rating.kt b/src/main/kotlin/com/yourssu/soongpt/domain/rating/implement/Rating.kt index 74342c9..b71e2ff 100644 --- a/src/main/kotlin/com/yourssu/soongpt/domain/rating/implement/Rating.kt +++ b/src/main/kotlin/com/yourssu/soongpt/domain/rating/implement/Rating.kt @@ -4,7 +4,7 @@ class Rating( val id: Long? = null, val courseName: String, val professorName: String, - val star: Int, + val star: Double, var point: Double = 50.0, ) { } \ No newline at end of file diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/rating/implement/RatingReader.kt b/src/main/kotlin/com/yourssu/soongpt/domain/rating/implement/RatingReader.kt new file mode 100644 index 0000000..3a6c545 --- /dev/null +++ b/src/main/kotlin/com/yourssu/soongpt/domain/rating/implement/RatingReader.kt @@ -0,0 +1,22 @@ +package com.yourssu.soongpt.domain.rating.implement + +import com.yourssu.soongpt.domain.course.implement.Courses +import com.yourssu.soongpt.domain.rating.implement.exception.RatingNotFoundByCourseNameException +import org.springframework.stereotype.Component + +@Component +class RatingReader( + private val ratingRepository: RatingRepository, +) { + fun findAllBy(courses: Courses): List { + return courses.unpackNameAndProfessor().mapNotNull { (courseName, professorName) -> + ratingRepository.findByCourseNameAndProfessorName(courseName, professorName) + } + } + + + fun findBy(courseName: String, professorName: String): Rating { + return ratingRepository.findByCourseNameAndProfessorName(courseName, professorName) + ?: throw RatingNotFoundByCourseNameException() + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/rating/storage/RatingEntity.kt b/src/main/kotlin/com/yourssu/soongpt/domain/rating/storage/RatingEntity.kt index 9f227ab..2bb4e1b 100644 --- a/src/main/kotlin/com/yourssu/soongpt/domain/rating/storage/RatingEntity.kt +++ b/src/main/kotlin/com/yourssu/soongpt/domain/rating/storage/RatingEntity.kt @@ -17,7 +17,7 @@ class RatingEntity( val professorName: String, @Column(name = "star", nullable = false) - val star: Int, + val star: Double, @Column(name = "point", nullable = false) val point: Double, diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/timetable/application/TimetableController.kt b/src/main/kotlin/com/yourssu/soongpt/domain/timetable/application/TimetableController.kt index 69fe53b..1d6a753 100644 --- a/src/main/kotlin/com/yourssu/soongpt/domain/timetable/application/TimetableController.kt +++ b/src/main/kotlin/com/yourssu/soongpt/domain/timetable/application/TimetableController.kt @@ -1,19 +1,25 @@ package com.yourssu.soongpt.domain.timetable.application import com.yourssu.soongpt.common.business.dto.Response +import com.yourssu.soongpt.domain.timetable.application.dto.TimetableCreatedRequest import com.yourssu.soongpt.domain.timetable.business.TimetableService import com.yourssu.soongpt.domain.timetable.business.dto.TimetableResponse +import com.yourssu.soongpt.domain.timetable.business.dto.TimetableResponses import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/api/timetables") class TimetableController( private val timetableService: TimetableService, ) { + @PostMapping + fun createTimetable(@RequestBody request: TimetableCreatedRequest): ResponseEntity> { + val responses = timetableService.createTimetable(request.toCommand()) + return ResponseEntity.ok(Response(result=responses)) + } + + @GetMapping("/{id}") fun getTimetable(@PathVariable id: Long): ResponseEntity> { val response = timetableService.getTimeTable(id) diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/timetable/application/dto/TimetableCreatedRequest.kt b/src/main/kotlin/com/yourssu/soongpt/domain/timetable/application/dto/TimetableCreatedRequest.kt new file mode 100644 index 0000000..986159d --- /dev/null +++ b/src/main/kotlin/com/yourssu/soongpt/domain/timetable/application/dto/TimetableCreatedRequest.kt @@ -0,0 +1,39 @@ +package com.yourssu.soongpt.domain.timetable.application.dto + +import com.yourssu.soongpt.domain.timetable.business.dto.TimetableCreatedCommand +import jakarta.validation.constraints.NotBlank +import jakarta.validation.constraints.NotNull +import org.hibernate.validator.constraints.Range + +data class TimetableCreatedRequest( + @field:Range(min = 15, max = 25, message = "학번은 15부터 25까지 가능합니다.") + val schoolId: Int, + + @field:NotBlank(message = "학과는 필수 입력값입니다.") + val department: String, + + @field:Range(min = 1, max = 5, message = "학년은 1부터 5까지 가능합니다.") + val grade: Int, + + val isChapel: Boolean = false, + + @field:NotNull + val majorRequiredCourses: List, + + @field:NotNull + val majorElectiveCourses: List, + + @field:NotNull + val generalRequiredCourses: List, +) { + fun toCommand(): TimetableCreatedCommand { + return TimetableCreatedCommand( + departmentName = department, + grade = grade, + isChapel = isChapel, + majorRequiredCourses = majorRequiredCourses, + majorElectiveCourses = majorElectiveCourses, + generalRequiredCourses = generalRequiredCourses, + ) + } +} diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/timetable/business/TimetableService.kt b/src/main/kotlin/com/yourssu/soongpt/domain/timetable/business/TimetableService.kt index c48887d..42c0eee 100644 --- a/src/main/kotlin/com/yourssu/soongpt/domain/timetable/business/TimetableService.kt +++ b/src/main/kotlin/com/yourssu/soongpt/domain/timetable/business/TimetableService.kt @@ -1,18 +1,68 @@ package com.yourssu.soongpt.domain.timetable.business +import com.yourssu.soongpt.domain.course.implement.CourseReader +import com.yourssu.soongpt.domain.course.implement.Courses +import com.yourssu.soongpt.domain.course.implement.CoursesFactory import com.yourssu.soongpt.domain.courseTime.implement.CourseTimeReader +import com.yourssu.soongpt.domain.department.implement.DepartmentReader import com.yourssu.soongpt.domain.timetable.business.dto.TimetableCourseResponse +import com.yourssu.soongpt.domain.timetable.business.dto.TimetableCreatedCommand import com.yourssu.soongpt.domain.timetable.business.dto.TimetableResponse -import com.yourssu.soongpt.domain.timetable.implement.TimetableCourseReader -import com.yourssu.soongpt.domain.timetable.implement.TimetableReader +import com.yourssu.soongpt.domain.timetable.business.dto.TimetableResponses +import com.yourssu.soongpt.domain.timetable.implement.* import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional @Service class TimetableService( private val timetableReader: TimetableReader, + private val timetableWriter: TimetableWriter, + private val timetableCourseWriter: TimetableCourseWriter, private val timetableCourseReader: TimetableCourseReader, private val courseTimeReader: CourseTimeReader, + private val departmentReader: DepartmentReader, + private val courseReader: CourseReader, + private val coursesFactory: CoursesFactory, ) { + @Transactional + fun createTimetable(command: TimetableCreatedCommand): TimetableResponses { + val department = departmentReader.getByName(command.departmentName) + val majorRequiredCourses = + command.majorRequiredCourses.map { courseReader.findAllByCourseNameInMajorRequired(department.id!!, it) } + val majorElectiveCourses = + command.majorElectiveCourses.map { courseReader.findAllByCourseNameInMajorElective(department.id!!, it) } + val generalRequiredCourses = + command.generalRequiredCourses.map { courseReader.findAllByCourseNameInGeneralRequired(department.id!!, it) + } + + val coursesCandidates = + coursesFactory.generateTimetableCandidates(majorRequiredCourses + majorElectiveCourses + generalRequiredCourses) + coursesFactory.validateEmpty(coursesCandidates) + + val responses = ArrayList() + for (courses in coursesCandidates) { + val timetable = timetableWriter.save(Timetable(tag = Tag.DEFAULT)) + saveTimetableCourses(courses, timetable) + responses.add( + TimetableResponse( + timetable.id!!, + timetable.tag.name, + toTimetableCourseResponses(courses) + ) + ) + } + return TimetableResponses(responses) + } + + private fun toTimetableCourseResponses(courses: Courses) = + courses.courses.map { TimetableCourseResponse.from(it, courseTimeReader.findAllByCourseId(it.id!!)) } + + private fun saveTimetableCourses(courses: Courses, timetable: Timetable) { + for (course in courses.courses) { + timetableCourseWriter.save(TimetableCourse(timetableId = timetable.id!!, courseId = course.id!!)) + } + } + fun getTimeTable(id: Long): TimetableResponse { val timetable = timetableReader.get(id) val courses = timetableCourseReader.findAllCourseByTimetableId(id) diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/timetable/business/dto/TimetableCreatedCommand.kt b/src/main/kotlin/com/yourssu/soongpt/domain/timetable/business/dto/TimetableCreatedCommand.kt new file mode 100644 index 0000000..bd983fb --- /dev/null +++ b/src/main/kotlin/com/yourssu/soongpt/domain/timetable/business/dto/TimetableCreatedCommand.kt @@ -0,0 +1,11 @@ +package com.yourssu.soongpt.domain.timetable.business.dto + +data class TimetableCreatedCommand( + val departmentName: String, + val grade: Int, + val isChapel: Boolean, + val majorRequiredCourses: List, + val majorElectiveCourses: List, + val generalRequiredCourses: List, +) { +} \ No newline at end of file diff --git a/src/main/kotlin/com/yourssu/soongpt/domain/timetable/business/dto/TimetableResponses.kt b/src/main/kotlin/com/yourssu/soongpt/domain/timetable/business/dto/TimetableResponses.kt new file mode 100644 index 0000000..4867762 --- /dev/null +++ b/src/main/kotlin/com/yourssu/soongpt/domain/timetable/business/dto/TimetableResponses.kt @@ -0,0 +1,5 @@ +package com.yourssu.soongpt.domain.timetable.business.dto + +data class TimetableResponses( + val timetables: List, +) \ No newline at end of file diff --git a/src/test/kotlin/com/yourssu/soongpt/common/support/fixture/CourseFixture.kt b/src/test/kotlin/com/yourssu/soongpt/common/support/fixture/CourseFixture.kt index 9c11d60..61ac9b1 100644 --- a/src/test/kotlin/com/yourssu/soongpt/common/support/fixture/CourseFixture.kt +++ b/src/test/kotlin/com/yourssu/soongpt/common/support/fixture/CourseFixture.kt @@ -26,7 +26,7 @@ enum class CourseFixture( professorName = "교수명", classification = Classification.GENERAL_REQUIRED, credit = 3, - ) + ), ; fun toDomain(): Course { diff --git a/src/test/kotlin/com/yourssu/soongpt/domain/course/storage/business/CourseServiceTest.kt b/src/test/kotlin/com/yourssu/soongpt/domain/course/business/CourseServiceTest.kt similarity index 98% rename from src/test/kotlin/com/yourssu/soongpt/domain/course/storage/business/CourseServiceTest.kt rename to src/test/kotlin/com/yourssu/soongpt/domain/course/business/CourseServiceTest.kt index d47aa90..b885315 100644 --- a/src/test/kotlin/com/yourssu/soongpt/domain/course/storage/business/CourseServiceTest.kt +++ b/src/test/kotlin/com/yourssu/soongpt/domain/course/business/CourseServiceTest.kt @@ -1,11 +1,10 @@ -package com.yourssu.soongpt.domain.course.storage.business +package com.yourssu.soongpt.domain.course.business import com.querydsl.jpa.impl.JPAQueryFactory import com.yourssu.soongpt.common.business.initialization.CollegesAndDepartmentsInitializer import com.yourssu.soongpt.common.support.config.ApplicationTest import com.yourssu.soongpt.common.support.fixture.CourseFixture import com.yourssu.soongpt.common.support.fixture.CourseTimeFixture -import com.yourssu.soongpt.domain.course.business.CourseService import com.yourssu.soongpt.domain.course.implement.CourseRepository import com.yourssu.soongpt.domain.courseTime.implement.CourseTimeRepository import com.yourssu.soongpt.domain.department.storage.QDepartmentEntity.departmentEntity diff --git a/src/test/kotlin/com/yourssu/soongpt/domain/course/implement/CourseReaderTest.kt b/src/test/kotlin/com/yourssu/soongpt/domain/course/implement/CourseReaderTest.kt new file mode 100644 index 0000000..58dd84b --- /dev/null +++ b/src/test/kotlin/com/yourssu/soongpt/domain/course/implement/CourseReaderTest.kt @@ -0,0 +1,85 @@ +package com.yourssu.soongpt.domain.course.implement + +import com.yourssu.soongpt.common.support.config.ApplicationTest +import com.yourssu.soongpt.common.support.fixture.CourseFixture.MAJOR_REQUIRED +import com.yourssu.soongpt.common.support.fixture.DepartmentFixture.COMPUTER +import com.yourssu.soongpt.common.support.fixture.DepartmentGradeFixture.FIRST +import com.yourssu.soongpt.common.support.fixture.TargetFixture +import com.yourssu.soongpt.domain.course.implement.exception.CourseNotFoundException +import com.yourssu.soongpt.domain.department.implement.DepartmentRepository +import com.yourssu.soongpt.domain.departmentGrade.implement.DepartmentGradeRepository +import com.yourssu.soongpt.domain.target.implement.TargetRepository +import org.junit.jupiter.api.* +import org.springframework.beans.factory.annotation.Autowired + +@ApplicationTest +class CourseReaderTest { + @Autowired + private lateinit var courseReader: CourseReader + + @Autowired + private lateinit var courseRepository: CourseRepository + + @Autowired + private lateinit var departmentRepository: DepartmentRepository + + @Autowired + private lateinit var departmentGradeRepository: DepartmentGradeRepository + + @Autowired + private lateinit var targetRepository: TargetRepository + + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores::class) + inner class findAllByCourseNameInMajorRequired_메서드는 { + var departmentId: Long? = null + var courseName: String? = null + + @BeforeEach + fun setUp() { + val course = courseRepository.save(MAJOR_REQUIRED.toDomain()) + + courseName = course.courseName + val department = departmentRepository.save(COMPUTER.toDomain(1L)) + departmentId = department.id + val departmentGrade = departmentGradeRepository.save(FIRST.toDomain(departmentId = departmentId!!)) + targetRepository.save( + TargetFixture.TARGET1.toDomain( + departmentGradeId = departmentGrade.id!!, + courseId = course.id!! + ) + ) + } + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores::class) + inner class 학과이름이_일치하지_않는_경우 { + @Test + @DisplayName("CourseNotFoundException 예외를 반환한다.") + fun success() { + assertThrows { + courseReader.findAllByCourseNameInMajorRequired( + departmentId = departmentId!!, + courseName = "일치하지 않는 과목 이름", + ) + } + } + } + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores::class) + inner class 수강대상이_일치하지_않는_경우 { + @Test + @DisplayName("CourseNotFoundException 예외를 반환한다.") + fun success() { + assertThrows { + courseReader.findAllByCourseNameInMajorRequired( + departmentId = 0L, + courseName = courseName!!, + ) + } + } + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/yourssu/soongpt/domain/timetable/implement/CoursesFactoryTest.kt b/src/test/kotlin/com/yourssu/soongpt/domain/timetable/implement/CoursesFactoryTest.kt new file mode 100644 index 0000000..53e6844 --- /dev/null +++ b/src/test/kotlin/com/yourssu/soongpt/domain/timetable/implement/CoursesFactoryTest.kt @@ -0,0 +1,34 @@ +package com.yourssu.soongpt.domain.timetable.implement + +import com.yourssu.soongpt.common.support.fixture.CourseFixture +import com.yourssu.soongpt.domain.course.implement.Courses +import com.yourssu.soongpt.domain.course.implement.CoursesFactory +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.* + +class CoursesFactoryTest { + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores::class) + inner class generateTimetableCandidates_메서드는 { + val courses = Courses( + listOf( + CourseFixture.MAJOR_REQUIRED.toDomain(), + CourseFixture.MAJOR_ELECTIVE.toDomain(), + ) + ) + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores::class) + inner class 과목_그룹들을_받으면 { + @Test + @DisplayName("각 그룹에서 과목을 모두 선택한 집합들의 리스트를 반환한다.") + fun success() { + val coursesFactory = CoursesFactory() + val courseCandidates = listOf(courses, courses) + + val actual = coursesFactory.generateTimetableCandidates(courseCandidates) + assertThat(actual).hasSize(4) + } + } + } +} \ No newline at end of file