This commit is contained in:
team3
2026-09-19 23:50:36 +02:00
parent e0c615c73a
commit a62b587340
26 changed files with 1654 additions and 1 deletions

View File

@@ -0,0 +1,40 @@
package de.marha.planer
import de.marha.planer.data.Dates
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
class DatesTest {
@Test fun monthGridStartsMondayBefore() {
val grid = Dates.monthGrid(2026, 9)
assertEquals(42, grid.size)
assertEquals("2026-08-31", grid[0])
assertEquals("2026-06-01", Dates.monthGrid(2026, 6)[0])
}
@Test fun weekStartsMonday() {
assertEquals("2026-09-14", Dates.startOfWeek("2026-09-17"))
assertEquals("2026-09-14", Dates.startOfWeek("2026-09-20"))
assertEquals("2026-09-14", Dates.startOfWeek("2026-09-14"))
assertEquals(7, Dates.weekDays("2026-09-17").size)
}
@Test fun isoWeek() {
assertEquals(38, Dates.isoWeek("2026-09-17"))
assertEquals(53, Dates.isoWeek("2027-01-01"))
}
@Test fun formats() {
assertEquals("Do, 17.09.2026", Dates.formatDate("2026-09-17"))
assertEquals("17.09.", Dates.formatDayMonth("2026-09-17"))
assertEquals("September 2026", Dates.formatMonth(2026, 9))
assertEquals(90, Dates.timeToMinutes("01:30"))
assertEquals("01:30", Dates.minutesToTime(90))
}
// Gleiches Format wie die Extension, damit sich Zeitstempel als Strings vergleichen lassen
@Test fun nowIsoHasMillisAndZ() {
assertTrue(Regex("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$").matches(Dates.nowIso()))
}
}

View File

@@ -0,0 +1,45 @@
package de.marha.planer
import androidx.compose.ui.text.font.FontWeight
import de.marha.planer.data.Markdown
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
class MarkdownTest {
@Test fun headingIsBoldAndStripped() {
val out = Markdown.render("# Titel")
assertEquals("Titel", out.text)
assertTrue(out.spanStyles.any { it.item.fontWeight == FontWeight.Bold && it.start == 0 && it.end == 5 })
}
@Test fun inlineStyles() {
assertEquals("A b c", Markdown.render("A **b** c").text)
assertEquals("a kursiv b", Markdown.render("a *kursiv* b").text)
assertEquals("snake_case_name", Markdown.render("snake_case_name").text)
assertEquals("2 * 3 * 4", Markdown.render("2 * 3 * 4").text)
assertEquals("Link", Markdown.render("[Link](http://x)").text)
assertEquals("Wiki", Markdown.render("[[Wiki]]").text)
assertEquals("[Bild: Bild]", Markdown.render("![Bild](a.png)").text)
assertEquals("weg", Markdown.render("~~weg~~").text)
}
@Test fun codeKeepsStars() {
val out = Markdown.render("`**nicht fett**`")
assertEquals("**nicht fett**", out.text)
assertTrue(out.spanStyles.none { it.item.fontWeight == FontWeight.Bold })
}
@Test fun lists() {
assertEquals(" • eins\n • zwei", Markdown.render("- eins\n - zwei").text)
assertEquals(" 1. a\n 2. b", Markdown.render("1. a\n2. b").text)
assertEquals(" ☐ offen\n ☑ fertig", Markdown.render("- [ ] offen\n- [x] fertig").text)
}
@Test fun blocks() {
assertEquals("let a = 1;", Markdown.render("```\nlet a = 1;\n```").text.trim())
assertEquals("▎ zitat", Markdown.render("> zitat").text)
assertTrue(Markdown.render("---").text.startsWith("────"))
assertEquals("a\n\nb", Markdown.render("a\n\nb").text)
}
}

View File

@@ -0,0 +1,103 @@
package de.marha.planer
import de.marha.planer.data.Event
import de.marha.planer.data.Store
import de.marha.planer.data.Todo
import org.json.JSONObject
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
class StoreTest {
@get:Rule val tmp = TemporaryFolder()
private fun store() = Store(tmp.root)
private fun event(title: String, date: String, start: String? = null, end: String? = null, endDate: String? = null) =
Event(id = "", title = title, date = date, start = start, end = end, endDate = endDate, created = "", updated = "")
@Test fun eventsGetIdAndTombstone() {
val s = store()
s.saveEvent(event("Zahnarzt", "2026-09-17", "09:30", "10:30"))
val saved = s.events.single()
assertTrue(saved.id.isNotEmpty() && saved.updated.endsWith("Z"))
s.removeEvent(saved.id)
assertTrue(s.events.single().deleted)
assertEquals(0, s.eventsOn("2026-09-17").size)
// Neu laden: Tombstone bleibt in der Datei
assertTrue(store().events.single().deleted)
}
@Test fun multiDayEventTouchesEveryDay() {
val s = store()
s.saveEvent(event("Messe", "2026-09-15", "14:00", "11:00", "2026-09-16"))
assertEquals(1, s.eventsOn("2026-09-15").size)
assertEquals(1, s.eventsOn("2026-09-16").size)
assertEquals(0, s.eventsOn("2026-09-17").size)
}
@Test fun todosSorted() {
val s = store()
s.saveTodo(Todo(id = "", title = "allgemein", created = "", updated = ""))
s.saveTodo(Todo(id = "", title = "morgen", date = "2026-09-18", created = "", updated = ""))
s.saveTodo(Todo(id = "", title = "heute", date = "2026-09-17", time = "11:00", created = "", updated = ""))
s.toggleTodo(s.todos.first { it.title == "morgen" }.id)
assertEquals(listOf("heute", "allgemein", "morgen"), s.sortedTodos().map { it.title })
s.removeTodo(s.todos.first { it.title == "heute" }.id)
assertEquals(listOf("allgemein", "morgen"), s.sortedTodos().map { it.title })
}
@Test fun notesAndFolders() {
val s = store()
val folder = s.createFolder("", "Projekte")
val sub = s.createFolder(folder, "App")
val note = s.createNote(sub, "Plan")
assertEquals("Projekte/App/Plan.md", note)
s.writeNote(note, "# Plan")
assertEquals("# Plan", s.note(note)!!.content)
assertEquals(listOf("Projekte"), s.tree().folders.map { it.name })
assertEquals(listOf("Plan"), s.tree().folders[0].folders[0].notes.map { it.name })
val renamed = s.renameNote(note, "Neu")
assertEquals("Projekte/App/Neu.md", renamed)
assertNull(s.note(note))
assertEquals("# Plan", s.note(renamed)!!.content)
val moved = s.renameFolder(folder, "Arbeit")
assertEquals("Arbeit", moved)
assertNotNull(s.note("Arbeit/App/Neu.md"))
assertTrue(s.folders.any { it.id == "Arbeit/App" && !it.deleted })
assertTrue(s.folders.any { it.id == "Projekte" && it.deleted })
try {
s.deleteFolder("Arbeit")
throw AssertionError("voller Ordner darf nicht löschbar sein")
} catch (e: IllegalArgumentException) {
assertEquals("Der Ordner ist nicht leer", e.message)
}
s.deleteNote("Arbeit/App/Neu.md")
s.deleteFolder("Arbeit/App")
s.deleteFolder("Arbeit")
assertTrue(s.tree().folders.isEmpty())
}
@Test fun remoteNewerWins() {
val s = store()
s.saveTodo(Todo(id = "", title = "lokal", created = "", updated = ""))
val id = s.todos.single().id
val older = JSONObject().put("id", id).put("title", "alt").put("updated", "2000-01-01T00:00:00.000Z")
assertEquals(false, s.applyRemote("todos", listOf(older)))
assertEquals("lokal", s.todos.single().title)
val newer = JSONObject().put("id", id).put("title", "neu").put("updated", "2099-01-01T00:00:00.000Z").put("done", true)
assertEquals(true, s.applyRemote("todos", listOf(newer)))
assertEquals("neu", s.todos.single().title)
assertTrue(s.todos.single().done)
// Notiz vom Server samt Ordner
s.applyRemote("folders", listOf(JSONObject().put("id", "Remote").put("updated", "2026-01-01T00:00:00.000Z")))
s.applyRemote("notes", listOf(JSONObject().put("id", "Remote/Idee.md").put("content", "hi").put("updated", "2026-01-01T00:00:00.000Z")))
assertEquals("hi", s.tree().folders.single().notes.single().content)
}
}