package roomescape.theme.business import io.kotest.assertions.assertSoftly import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.mockk import org.springframework.data.repository.findByIdOrNull import roomescape.theme.exception.ThemeErrorCode import roomescape.theme.exception.ThemeException import roomescape.theme.infrastructure.persistence.ThemeEntity import roomescape.theme.infrastructure.persistence.ThemeRepository import roomescape.theme.web.ThemeCreateRequest import roomescape.theme.web.ThemeRetrieveResponse import roomescape.util.ThemeFixture class ThemeServiceTest : FunSpec({ val themeRepository: ThemeRepository = mockk() val themeService = ThemeService(themeRepository) context("findThemeById") { val themeId = 1L test("조회 성공") { val theme: ThemeEntity = ThemeFixture.create(id = themeId) every { themeRepository.findByIdOrNull(themeId) } returns theme theme.id shouldBe themeId } test("ID로 테마를 찾을 수 없으면 400 예외를 던진다.") { every { themeRepository.findByIdOrNull(themeId) } returns null val exception = shouldThrow { themeService.findById(themeId) } exception.errorCode shouldBe ThemeErrorCode.THEME_NOT_FOUND } } context("findAllThemes") { test("모든 테마를 조회한다.") { val themes = listOf(ThemeFixture.create(id = 1, name = "t1"), ThemeFixture.create(id = 2, name = "t2")) every { themeRepository.findAll() } returns themes assertSoftly(themeService.findThemes()) { this.themes.size shouldBe themes.size this.themes[0].name shouldBe "t1" this.themes[1].name shouldBe "t2" } } } context("save") { val request = ThemeCreateRequest( name = "New Theme", description = "Description", thumbnail = "http://example.com/thumbnail.jpg" ) test("저장 성공") { every { themeRepository.existsByName(request.name) } returns false every { themeRepository.save(any()) } returns ThemeFixture.create( id = 1L, name = request.name, description = request.description, thumbnail = request.thumbnail ) val response: ThemeRetrieveResponse = themeService.createTheme(request) assertSoftly(response) { this.id shouldBe 1L this.name shouldBe request.name this.description shouldBe request.description this.thumbnail shouldBe request.thumbnail } } test("테마 이름이 중복되면 409 예외를 던진다.") { every { themeRepository.existsByName(request.name) } returns true val exception = shouldThrow { themeService.createTheme(request) } exception.errorCode shouldBe ThemeErrorCode.THEME_NAME_DUPLICATED } } context("deleteById") { test("이미 예약 중인 테마라면 409 예외를 던진다.") { val themeId = 1L every { themeRepository.isReservedTheme(themeId) } returns true val exception = shouldThrow { themeService.deleteTheme(themeId) } exception.errorCode shouldBe ThemeErrorCode.THEME_ALREADY_RESERVED } } })