Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
- 저장된 메모를 삭제할 수 있어야 한다.
- 메모를 한 번에 여러개 삭제할 수 있어야 한다.

### ⚠️ 메모 삭제 기능 예외 상황
### ⚠️ 메모 삭제 기능 고려 사항

- 삭제할 메모가 없으면 아무 수행도 해선 안된다.

Expand All @@ -55,13 +55,13 @@

- 저장된 메모의 content를 수정할 수 있어야 한다.

### ⚠️ 메모 수정 기능 예외 상황
### ⚠️ 메모 수정 기능 고려 사항

- 수정할 메모가 없다면 아무 수행도 해선 안된다.

---

### 🏁 메모 추출 기능
### 메모 추출 기능

- 저장된 메모를 한 개 이상 선택하여 txt 파일로 추출할 수 있어야 한다.
- 추출한 단위 메모의 구성 내용은 다음과 같다.
Expand All @@ -76,18 +76,22 @@
- txt 파일의 이름은 `devlog-{프로젝트명}-{내보낸날짜}-{내보낸시각}.txt` 이다.
- 추출할 메모가 없으면 빈 txt 파일을 반환한다.

### ⚠️ 메모 추출 기능 예외 상황
### ⚠️ 메모 추출 기능 고려 사항

- 메모 추출 기능에서 고려 사항은 없습니다.

---

### ☑️ 노트 수정/저장 기능
### 노트 수정/저장 기능

- 노트를 저장할 수 있어야 한다.
- 노트의 수정/저장 데이터는 다음과 같다.
- `String content`: 노트의 내용
- `LocalDateTime savedAt`: 저장된 시각

### ⚠️ 노트 수정/저장 기능 예외 상황
### ⚠️ 노트 수정/저장 기능 고려 사항

- 노트가 수정할 내용이 없다면 아무 수행도 해선 안된다.

---

Expand Down
25 changes: 25 additions & 0 deletions src/main/kotlin/com/github/yeoli/devlog/domain/note/domain/Note.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.github.yeoli.devlog.domain.note.domain

import com.github.yeoli.devlog.domain.note.repository.NoteState
import java.time.LocalDateTime

class Note(
val content: String,
val updatedAt: LocalDateTime
) {

constructor(content: String) : this(content, LocalDateTime.now())

fun update(content: String): Note {
return Note(
content = content
)
}

fun toState(): NoteState {
return NoteState(
content = this.content,
updatedAt = this.updatedAt.toString()
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.github.yeoli.devlog.domain.note.repository

import com.github.yeoli.devlog.domain.note.domain.Note
import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import java.time.LocalDateTime

@State(
name = "DevLogNoteStorage",
storages = [Storage("devlog-note.xml")]
)
@Service(Service.Level.PROJECT)
class NoteRepository : PersistentStateComponent<NoteState> {

private var state: NoteState? = NoteState(
content = "",
updatedAt = LocalDateTime.now().toString()
)

override fun getState(): NoteState? = state

override fun loadState(state: NoteState) {
this.state = state
}

fun getNote(): Note {
if (state == null) {
state = Note(
content = ""
).toState()
}
return state!!.toDomain()
}

fun updateNote(updatedNote: Note) {
this.state = updatedNote.toState()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.github.yeoli.devlog.domain.note.repository

import com.github.yeoli.devlog.domain.note.domain.Note
import java.time.LocalDateTime

data class NoteState(
val content: String,
val updatedAt: String
) {

fun toDomain(): Note {
return Note(content, updatedAt = this.updatedAt.let { LocalDateTime.parse(it) })
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.github.yeoli.devlog.domain.note.service

import com.github.yeoli.devlog.domain.note.domain.Note
import com.github.yeoli.devlog.domain.note.repository.NoteRepository
import com.intellij.openapi.components.Service
import com.intellij.openapi.project.Project

@Service(Service.Level.PROJECT)
class NoteService(private val project: Project) {

Check warning on line 9 in src/main/kotlin/com/github/yeoli/devlog/domain/note/service/NoteService.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Constructor parameter is never used as a property

Constructor parameter is never used as a property

private val noteRepository =
project.getService<NoteRepository>(NoteRepository::class.java)

Check notice on line 12 in src/main/kotlin/com/github/yeoli/devlog/domain/note/service/NoteService.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unnecessary type argument

Remove explicit type arguments

fun getNote(): Note {
return noteRepository.getNote()
}

fun updateNote(content: String) {
val note: Note = getNote()
if (note.content == content) return

val updatedNote = note.update(content)

noteRepository.updateNote(updatedNote)
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.github.yeoli.devlog.domain.note.domain

import org.junit.jupiter.api.Assertions.*
import java.time.LocalDateTime
import kotlin.test.Test

class NoteTest {

@Test
fun `test 업데이트 시 새로운 인스턴스를 반환해야 한다`() {
val original = Note(
content = "hello"
)

val updated = original.update("new content")

assertNotSame(original, updated)
}

@Test
fun `test 업데이트 시 콘텐츠가 변경되어야 한다`() {
val original = Note(
content = "old content"
)

val updated = original.update("new content")

assertEquals("new content", updated.content)
assertNotEquals(original.content, updated.content)
}

@Test
fun `test 빈 문자열로 업데이트할 때 정상적으로 처리되어야 한다`() {
val original = Note(
content = "something"
)

val updated = original.update("")

assertEquals("", updated.content)
}

// =========== toState 테스트 ===========
@Test
fun `test toState - content와 updatedAt이 올바르게 변환된다`() {
// given
val now = LocalDateTime.of(2025, 1, 1, 12, 0)
val note = Note("Hello", now)

// when
val state = note.toState()

// then
assertEquals("Hello", state.content)
assertEquals(now.toString(), state.updatedAt)
}

@Test
fun `test toState - empty content도 정상 변환된다`() {
// given
val note = Note("")

// when
val state = note.toState()

// then
assertEquals("", state.content)
assertNotNull(state.updatedAt)
}

@Test
fun `test toState - updatedAt이 현재 시간이 아닐 수 있다`() {
// given
val customTime = LocalDateTime.of(2024, 12, 31, 23, 59)
val note = Note("Time test", customTime)

// when
val state = note.toState()

// then
assertEquals(customTime.toString(), state.updatedAt)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.github.yeoli.devlog.domain.note.repository

import org.junit.jupiter.api.Assertions.assertDoesNotThrow
import org.junit.jupiter.api.Assertions.assertEquals
import java.time.LocalDateTime
import kotlin.test.Test

class NoteStateTest {
@Test
fun `test toDomain - content와 updatedAt이 올바르게 변환된다`() {
// given
val nowString = "2025-01-01T12:00:00"
val state = NoteState(
content = "Hello Note",
updatedAt = nowString
)

// when
val note = state.toDomain()

// then
assertEquals("Hello Note", note.content)
assertEquals(LocalDateTime.parse(nowString), note.updatedAt)
}

@Test
fun `test toDomain - 빈 content도 정상적으로 변환된다`() {
// given
val nowString = LocalDateTime.now().toString()
val state = NoteState(
content = "",
updatedAt = nowString
)

// when
val note = state.toDomain()

// then
assertEquals("", note.content)
assertEquals(LocalDateTime.parse(nowString), note.updatedAt)
}

@Test
fun `test toDomain - updatedAt 문자열 포맷이 LocalDateTime으로 파싱 가능해야 한다`() {
// given
val formattedTime = "2024-12-31T23:59:00"
val state = NoteState("TimeCheck", formattedTime)

// when & then
assertDoesNotThrow {
state.toDomain()
}
}
}
Loading
Loading