package be.simplenotes.search import be.simplenotes.types.PersistedNote import be.simplenotes.types.PersistedNoteMetadata import org.assertj.core.api.Assertions.assertThat import org.intellij.lang.annotations.Language import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.parallel.ResourceLock import java.nio.file.Path import java.time.LocalDateTime import java.util.* @ResourceLock("lucene") internal class NoteSearcherImplTest { // region setup private val searcher = NoteSearcherImpl(Path.of("/tmp", "lucene")) private fun index( title: String, tags: List = emptyList(), content: String = "", uuid: UUID = UUID.randomUUID(), ): PersistedNote { val note = PersistedNote( title = title, tags = tags, markdown = content, html = "", updatedAt = LocalDateTime.MIN, uuid = uuid, public = false, ) searcher.indexNote(1, note) return note } private fun search( title: String? = null, tag: String? = null, content: String? = null, all: String? = null, ): List = searcher.search(1, SearchTerms(title, tag, content, all)) @BeforeEach @AfterAll fun dropIndexes() { searcher.dropIndex(1) } @Language("markdown") val markdownSample = """ # Apache Lucene Core Apache Lucene is a high-performance, full-featured text search engine library written entirely in Java. It is a technology suitable for nearly any application that requires full-text search, especially cross-platform. Apache Lucene is an open source project available for free download. Please use the links on the right to access Lucene. # Lucene Features Lucene offers powerful features through a simple API: ## Scalable, High-Performance Indexing * over [150GB/hour on modern hardware](http://home.apache.org/~mikemccand/lucenebench/indexing.html) * small RAM requirements -- only 1MB heap * incremental indexing as fast as batch indexing * index size roughly 20-30% the size of text indexed """.trimIndent() // endregion @Test fun `exact title search`() { index("first") index("second") index("flip") assertThat(search("first")) .hasSizeGreaterThanOrEqualTo(1) .anyMatch { it.title == "first" } assertThat(search("nothing")).isEmpty() } @Test fun `fuzzy title search`() { index("first") index("second") index("flip") @Suppress("SpellCheckingInspection") assertThat(search("firt")) .hasSizeGreaterThanOrEqualTo(1) .anyMatch { it.title == "first" } assertThat(search("nothing")).isEmpty() } @Test fun `exact tags search`() { index("first", tags = listOf("example", "flamingo")) index("second", tags = listOf("yes")) index("second") assertThat(search(tag = "example")) .hasSize(1) .anyMatch { it.title == "first" } } @Test fun `exact content search`() { index("first", content = markdownSample) assertThat(search(content = "fast")) .hasSize(1) .anyMatch { it.title == "first" } @Suppress("SpellCheckingInspection") assertThat(search(content = "preformance")) // <- note the error .hasSize(1) .anyMatch { it.title == "first" } } @Test fun `combined search`() { index("first", content = markdownSample, tags = listOf("abc")) assertThat(search(title = "fir", tag = "abc", content = "20")) .hasSize(1) } @Test fun `search all`() { index("first", content = markdownSample, tags = listOf("abc")) assertThat(search(all = "abc", title = "first")) .hasSize(1) } @Test fun `delete index`() { val uuid = index("first").uuid searcher.deleteIndex(1, uuid) assertThat(search("first")).isEmpty() } @Test fun `update index`() { val note = index("first") searcher.updateIndex(1, note.copy(title = "new")) assertThat(search("first")).isEmpty() assertThat(search("new")).hasSize(1) } }