moved to Kotlin multiplatform
This commit is contained in:
4
Jenkinsfile
vendored
4
Jenkinsfile
vendored
@@ -7,8 +7,8 @@ pipeline {
|
|||||||
stage("Build") {
|
stage("Build") {
|
||||||
steps {
|
steps {
|
||||||
sh "./gradlew clean build"
|
sh "./gradlew clean build"
|
||||||
junit testResults: "build/test-results/test/*.xml"
|
junit testResults: "build/test-results/*Test/*.xml"
|
||||||
archiveArtifacts artifacts: 'build/libs/*.jar,benchmark/build/libs/*.jar',
|
archiveArtifacts artifacts: 'build/libs/*.jar,build/libs/*.klib,benchmark/build/distributions/*.jar',
|
||||||
allowEmptyArchive: true,
|
allowEmptyArchive: true,
|
||||||
fingerprint: true,
|
fingerprint: true,
|
||||||
onlyIfSuccessful: true
|
onlyIfSuccessful: true
|
||||||
|
@@ -1,13 +1,27 @@
|
|||||||
plugins {
|
plugins {
|
||||||
alias catalog.plugins.kotlin.jvm
|
alias catalog.plugins.kotlin.multiplatform
|
||||||
alias catalog.plugins.envelope
|
alias catalog.plugins.envelope apply false
|
||||||
|
}
|
||||||
|
|
||||||
|
import net.woggioni.gradle.envelope.EnvelopeJarTask
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation catalog.jwo
|
jvmMainImplementation catalog.jwo
|
||||||
implementation(rootProject)
|
jvmMainImplementation(rootProject)
|
||||||
}
|
}
|
||||||
|
|
||||||
envelopeJar {
|
Provider<EnvelopeJarTask> envelopeJarTaskProvider = project.tasks.register("envelopeJar", EnvelopeJarTask.class) {
|
||||||
|
group = BasePlugin.BUILD_GROUP
|
||||||
|
description = "Package the application in a single executable jar file"
|
||||||
|
includeLibraries(project.configurations.named("jvmRuntimeClasspath"))
|
||||||
|
includeLibraries(project.getTasks().named("jvmJar", Jar.class))
|
||||||
mainClass = "net.woggioni.klevtree.benchmark.BenchmarkKt"
|
mainClass = "net.woggioni.klevtree.benchmark.BenchmarkKt"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
project.tasks.named(BasePlugin.ASSEMBLE_TASK_NAME, DefaultTask.class) {
|
||||||
|
dependsOn(envelopeJarTaskProvider)
|
||||||
|
}
|
||||||
|
60
build.gradle
60
build.gradle
@@ -1,9 +1,10 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
alias catalog.plugins.kotlin.jvm
|
alias catalog.plugins.kotlin.multiplatform
|
||||||
alias catalog.plugins.multi.release.jar
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
group = "net.woggioni"
|
group = "net.woggioni"
|
||||||
@@ -17,34 +18,41 @@ allprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
kotlin {
|
||||||
setProperty('jpms.module.name', 'net.woggioni.klevtree')
|
sourceSets {
|
||||||
}
|
commonTest {
|
||||||
|
dependencies {
|
||||||
dependencies {
|
implementation group: 'org.jetbrains.kotlin',
|
||||||
implementation catalog.jwo
|
name: 'kotlin-test',
|
||||||
|
version: catalog.versions.kotlin.get()
|
||||||
testImplementation catalog.junit.jupiter.api
|
}
|
||||||
testImplementation catalog.junit.jupiter.params
|
}
|
||||||
testRuntimeOnly catalog.junit.jupiter.engine
|
}
|
||||||
testRuntimeOnly catalog.log4j.slf4j.impl
|
jvm {
|
||||||
}
|
jvmToolchain(17)
|
||||||
|
withJava()
|
||||||
compileJava {
|
compilations.main {
|
||||||
options.release = 8
|
Action<KotlinJvmCompilerOptions> action = { KotlinJvmCompilerOptions kjco ->
|
||||||
options.compilerArgs << '-parameters'
|
kjco.javaParameters = true
|
||||||
}
|
kjco.jvmTarget = JvmTarget.JVM_1_8
|
||||||
|
kjco.moduleName = "net.woggioni.klevtree"
|
||||||
compileKotlin {
|
}
|
||||||
kotlinOptions.with {
|
compilerOptions.configure(action)
|
||||||
jvmTarget = '1.8'
|
}
|
||||||
|
}
|
||||||
|
linuxX64()
|
||||||
|
js(IR) {
|
||||||
|
nodejs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
compileJava {
|
||||||
useJUnitPlatform()
|
options.release = 11
|
||||||
|
String patchString = 'net.woggioni.klevtree=' + kotlin.targets.jvm.compilations.main.output.classesDirs.asPath
|
||||||
|
options.compilerArgs << '--patch-module' << patchString
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
@@ -53,7 +61,7 @@ publishing {
|
|||||||
}
|
}
|
||||||
publications {
|
publications {
|
||||||
maven(MavenPublication) {
|
maven(MavenPublication) {
|
||||||
from(components["java"])
|
from(components.kotlin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
|
kotlin.jvm.target.validation.mode=ignore
|
||||||
|
|
||||||
woggioniMavenRepositoryUrl=https://woggioni.net/mvn/
|
woggioniMavenRepositoryUrl=https://woggioni.net/mvn/
|
||||||
|
|
||||||
klevtree.version = 2023.03
|
klevtree.version = 2023.03
|
||||||
lys.version = 2023.05
|
lys.version = 2023.05.20
|
||||||
|
@@ -1,12 +1,14 @@
|
|||||||
package net.woggioni.klevtree
|
package net.woggioni.klevtree
|
||||||
|
|
||||||
import net.woggioni.jwo.TreeNodeVisitor
|
import net.woggioni.klevtree.tree.TreeNodeVisitor
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
|
||||||
sealed class DistanceCalculator {
|
sealed class DistanceCalculator {
|
||||||
abstract fun compute(keyChecker : Trie.Keychecker<Char>,
|
abstract fun compute(keyChecker : Trie.Keychecker<Char>,
|
||||||
stack: List<TreeNodeVisitor.StackContext<LevNode, Unit>>,
|
stack: List<TreeNodeVisitor.StackContext<LevNode, Unit>>,
|
||||||
wordkey: String,
|
wordkey: String,
|
||||||
worstCase : Int) : TreeNodeVisitor.VisitOutcome
|
worstCase : Int) : TreeNodeVisitor.VisitOutcome
|
||||||
|
|
||||||
object LevenshteinDistanceCalculator : DistanceCalculator() {
|
object LevenshteinDistanceCalculator : DistanceCalculator() {
|
||||||
override fun compute(keyChecker : Trie.Keychecker<Char>,
|
override fun compute(keyChecker : Trie.Keychecker<Char>,
|
||||||
@@ -21,7 +23,7 @@ sealed class DistanceCalculator {
|
|||||||
if(keyChecker.check(wordkey[i - 1], currentStackElement.node.key)) {
|
if(keyChecker.check(wordkey[i - 1], currentStackElement.node.key)) {
|
||||||
currentRow[i] = previousRow[i - 1]
|
currentRow[i] = previousRow[i - 1]
|
||||||
} else {
|
} else {
|
||||||
currentRow[i] = Math.min(Math.min(currentRow[i - 1], previousRow[i -1]), previousRow[i]) + 1
|
currentRow[i] = min(min(currentRow[i - 1], previousRow[i -1]), previousRow[i]) + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return if(worstCase >= 0 && worstCase <= currentRow.minOrNull()!!) {
|
return if(worstCase >= 0 && worstCase <= currentRow.minOrNull()!!) {
|
||||||
@@ -45,13 +47,13 @@ sealed class DistanceCalculator {
|
|||||||
if (keyChecker.check(wordkey[i - 1], cse.node.key)) {
|
if (keyChecker.check(wordkey[i - 1], cse.node.key)) {
|
||||||
crow[i] = prow[i - 1]
|
crow[i] = prow[i - 1]
|
||||||
} else {
|
} else {
|
||||||
crow[i] = Math.min(Math.min(crow[i - 1], prow[i - 1]), prow[i]) + 1
|
crow[i] = min(min(crow[i - 1], prow[i - 1]), prow[i]) + 1
|
||||||
}
|
}
|
||||||
if (stack.size > 2 && i > 1 && keyChecker.check(wordkey[i - 2], cse.node.key)
|
if (stack.size > 2 && i > 1 && keyChecker.check(wordkey[i - 2], cse.node.key)
|
||||||
&& keyChecker.check(wordkey[i - 1], pse.node.key)) {
|
&& keyChecker.check(wordkey[i - 1], pse.node.key)) {
|
||||||
val ppse = stack[stack.size - 3]
|
val ppse = stack[stack.size - 3]
|
||||||
val pprow: IntArray = ppse.node.payload!!
|
val pprow: IntArray = ppse.node.payload!!
|
||||||
crow[i] = Math.min(crow[i], pprow[i - 2] + 1)
|
crow[i] = min(crow[i], pprow[i - 2] + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return if(worstCase >= 0 && worstCase <= prow.minOrNull()!!) {
|
return if(worstCase >= 0 && worstCase <= prow.minOrNull()!!) {
|
@@ -1,9 +1,9 @@
|
|||||||
package net.woggioni.klevtree
|
package net.woggioni.klevtree
|
||||||
|
|
||||||
import net.woggioni.jwo.TreeNodeVisitor
|
|
||||||
import net.woggioni.jwo.TreeWalker
|
|
||||||
import net.woggioni.klevtree.node.CharNode
|
import net.woggioni.klevtree.node.CharNode
|
||||||
import net.woggioni.klevtree.node.TrieNode
|
import net.woggioni.klevtree.node.TrieNode
|
||||||
|
import net.woggioni.klevtree.tree.TreeNodeVisitor
|
||||||
|
import net.woggioni.klevtree.tree.TreeWalker
|
||||||
|
|
||||||
internal typealias LevNode = TrieNode<Char, IntArray>
|
internal typealias LevNode = TrieNode<Char, IntArray>
|
||||||
|
|
||||||
@@ -41,7 +41,8 @@ class LevTrie : CharTrie<IntArray>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun fuzzySearch(word : String, maxResult: Int) : List<Pair<String, Int>> {
|
fun fuzzySearch(word : String, maxResult: Int) : List<Pair<String, Int>> {
|
||||||
val result = sortedSetOf<Pair<String, Int>>(compareBy({ it.second }, { it.first }))
|
val comparator : Comparator<Pair<String, Int>> = compareBy({ it.second }, { it.first })
|
||||||
|
val result = mutableListOf<Pair<String, Int>>()
|
||||||
val requiredSize = word.length + 1
|
val requiredSize = word.length + 1
|
||||||
val visitor = object: TreeNodeVisitor<LevNode, Unit> {
|
val visitor = object: TreeNodeVisitor<LevNode, Unit> {
|
||||||
override fun visitPre(stack: List<TreeNodeVisitor.StackContext<LevNode, Unit>>): TreeNodeVisitor.VisitOutcome {
|
override fun visitPre(stack: List<TreeNodeVisitor.StackContext<LevNode, Unit>>): TreeNodeVisitor.VisitOutcome {
|
||||||
@@ -64,6 +65,7 @@ class LevTrie : CharTrie<IntArray>() {
|
|||||||
val candidate = sb.toString()
|
val candidate = sb.toString()
|
||||||
val distance = stack[stack.size - 2].node.payload!![word.length]
|
val distance = stack[stack.size - 2].node.payload!![word.length]
|
||||||
result.add(candidate to distance)
|
result.add(candidate to distance)
|
||||||
|
result.sortWith(comparator)
|
||||||
if(result.size > maxResult) {
|
if(result.size > maxResult) {
|
||||||
result.remove(result.last())
|
result.remove(result.last())
|
||||||
}
|
}
|
@@ -1,8 +1,8 @@
|
|||||||
package net.woggioni.klevtree
|
package net.woggioni.klevtree
|
||||||
|
|
||||||
import net.woggioni.jwo.TreeNodeVisitor
|
|
||||||
import net.woggioni.jwo.TreeWalker
|
|
||||||
import net.woggioni.klevtree.node.TrieNode
|
import net.woggioni.klevtree.node.TrieNode
|
||||||
|
import net.woggioni.klevtree.tree.TreeNodeVisitor
|
||||||
|
import net.woggioni.klevtree.tree.TreeWalker
|
||||||
|
|
||||||
abstract class Trie<T : TrieNode<KEY, PAYLOAD>, KEY, PAYLOAD> {
|
abstract class Trie<T : TrieNode<KEY, PAYLOAD>, KEY, PAYLOAD> {
|
||||||
|
|
@@ -1,6 +1,6 @@
|
|||||||
package net.woggioni.klevtree.node
|
package net.woggioni.klevtree.node
|
||||||
|
|
||||||
import net.woggioni.jwo.TreeNodeVisitor
|
import net.woggioni.klevtree.tree.TreeNodeVisitor
|
||||||
|
|
||||||
|
|
||||||
open class TrieNode<T, PAYLOAD>(val key : T?) : TreeNodeVisitor.TreeNode<TrieNode<T, PAYLOAD>> {
|
open class TrieNode<T, PAYLOAD>(val key : T?) : TreeNodeVisitor.TreeNode<TrieNode<T, PAYLOAD>> {
|
@@ -0,0 +1,64 @@
|
|||||||
|
package net.woggioni.klevtree.tree
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface must be implemented by the user of [TreeWalker] and its methods will be called by
|
||||||
|
* [TreeWalker.walk]. The methods will receive as an input a list of [StackContext]
|
||||||
|
* instances each one correspond to a node in the tree, each node is preceded in the list
|
||||||
|
* by its parents in the tree. Each instance has a method, [StackContext.context]
|
||||||
|
* to set a custom object that can be used in the [.visitPre] method and the method
|
||||||
|
* [StackContext.context] that can be used in the [.visitPost] method to retrieve
|
||||||
|
* the same instance. This is to provide support for algorithms that require both pre-order and post-order logic.
|
||||||
|
* The last element of the list corresponds to the node currently being traversed.
|
||||||
|
* @param <T> the type of the context object used
|
||||||
|
</T> */
|
||||||
|
interface TreeNodeVisitor<NODE : TreeNodeVisitor.TreeNode<NODE>, T> {
|
||||||
|
interface TreeNode<NODE : TreeNode<NODE>> {
|
||||||
|
fun children(): Iterator<NODE>?
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface exposes the methods that are visible to the user of
|
||||||
|
* [TreeWalker], it allows to
|
||||||
|
* set/get a custom object in the current stack context or to get the current link's Aci
|
||||||
|
* @param <T> the type of the context object used
|
||||||
|
</T> */
|
||||||
|
interface StackContext<NODE : TreeNode<*>?, T> {
|
||||||
|
/**
|
||||||
|
* @return the current user object
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @param ctx the user object to set for this stack level
|
||||||
|
*/
|
||||||
|
var context: T?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current TreeNode
|
||||||
|
*/
|
||||||
|
val node: NODE
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class VisitOutcome {
|
||||||
|
CONTINUE,
|
||||||
|
SKIP,
|
||||||
|
EARLY_EXIT
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will be called for each link using
|
||||||
|
* [a Depth-first pre-oder algorithm](https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_(NLR))
|
||||||
|
* @param stack is a list of [StackContext] instances corresponding to the full path from the root to the
|
||||||
|
* current node in the tree
|
||||||
|
* @return a boolean that will be used to decide whether to traverse the subtree rooted in the current link or not
|
||||||
|
*/
|
||||||
|
fun visitPre(stack: List<StackContext<NODE, T>>): VisitOutcome {
|
||||||
|
return VisitOutcome.CONTINUE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will be called for each node using
|
||||||
|
* [a Depth-first post-oder algorithm](https://en.wikipedia.org/wiki/Tree_traversal#Post-order_(LRN))
|
||||||
|
* @param stack is a list of [StackContext] instances corresponding to the full path from the root to the
|
||||||
|
* current node in the tree
|
||||||
|
*/
|
||||||
|
fun visitPost(stack: List<StackContext<NODE, T>>) {}
|
||||||
|
}
|
@@ -0,0 +1,48 @@
|
|||||||
|
package net.woggioni.klevtree.tree
|
||||||
|
|
||||||
|
|
||||||
|
class TreeWalker<NODE : TreeNodeVisitor.TreeNode<NODE>, T>(
|
||||||
|
private val visitor: TreeNodeVisitor<NODE, T>
|
||||||
|
) {
|
||||||
|
|
||||||
|
private class StackElement<NODE : TreeNodeVisitor.TreeNode<NODE>, T>(override val node: NODE) :
|
||||||
|
TreeNodeVisitor.StackContext<NODE, T> {
|
||||||
|
override var context: T? = null
|
||||||
|
var childrenIterator: Iterator<NODE>? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This methods does the actual job of traversing the tree calling the methods of the provided
|
||||||
|
* [TreeNodeVisitor] instance
|
||||||
|
* @param root the root node of the tree
|
||||||
|
*/
|
||||||
|
fun walk(root: NODE) {
|
||||||
|
val stack: MutableList<StackElement<NODE, T>> = mutableListOf()
|
||||||
|
val rootStackElement = StackElement<NODE, T>(root)
|
||||||
|
stack.add(rootStackElement)
|
||||||
|
val publicStack: List<TreeNodeVisitor.StackContext<NODE, T>> = stack
|
||||||
|
when (visitor.visitPre(publicStack)) {
|
||||||
|
TreeNodeVisitor.VisitOutcome.CONTINUE -> rootStackElement.childrenIterator = root.children()
|
||||||
|
TreeNodeVisitor.VisitOutcome.SKIP -> rootStackElement.childrenIterator = null
|
||||||
|
TreeNodeVisitor.VisitOutcome.EARLY_EXIT -> return
|
||||||
|
}
|
||||||
|
while (stack.isNotEmpty()) {
|
||||||
|
val lastElement: StackElement<NODE, T> = stack.last()
|
||||||
|
val childrenIterator = lastElement.childrenIterator
|
||||||
|
if (childrenIterator != null && childrenIterator.hasNext()) {
|
||||||
|
val childNode = childrenIterator.next()
|
||||||
|
val childStackElement = StackElement<NODE, T>(childNode)
|
||||||
|
stack.add(childStackElement)
|
||||||
|
when (visitor.visitPre(publicStack)) {
|
||||||
|
TreeNodeVisitor.VisitOutcome.CONTINUE -> childStackElement.childrenIterator = childNode.children()
|
||||||
|
TreeNodeVisitor.VisitOutcome.SKIP -> childStackElement.childrenIterator = null
|
||||||
|
TreeNodeVisitor.VisitOutcome.EARLY_EXIT -> return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
visitor.visitPost(publicStack)
|
||||||
|
stack.removeLast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -1,7 +1,11 @@
|
|||||||
package net.woggioni.klevtree
|
package net.woggioni.klevtree
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions
|
import kotlin.test.Test
|
||||||
import org.junit.jupiter.api.Test
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
import kotlin.test.assertNull
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
|
||||||
class LevtreeTest {
|
class LevtreeTest {
|
||||||
|
|
||||||
@@ -13,23 +17,23 @@ class LevtreeTest {
|
|||||||
val word = "dailies"
|
val word = "dailies"
|
||||||
run {
|
run {
|
||||||
val pair = tree.add(word)
|
val pair = tree.add(word)
|
||||||
Assertions.assertTrue(pair.first)
|
assertTrue(pair.first)
|
||||||
val node = tree.search(word)
|
val node = tree.search(word)
|
||||||
Assertions.assertNotNull(node)
|
assertNotNull(node)
|
||||||
Assertions.assertEquals(
|
assertEquals(
|
||||||
word,
|
word,
|
||||||
node!!.linealDescendant().fold(StringBuilder(), StringBuilder::append).toString()
|
node.linealDescendant().fold(StringBuilder(), StringBuilder::append).toString()
|
||||||
)
|
)
|
||||||
val result = tree.fuzzySearch(word, 5)
|
val result = tree.fuzzySearch(word, 5)
|
||||||
Assertions.assertEquals(1, result.size)
|
assertEquals(1, result.size)
|
||||||
Assertions.assertEquals(word to 0, result[0])
|
assertEquals(word to 0, result[0])
|
||||||
}
|
}
|
||||||
run {
|
run {
|
||||||
tree.remove(word)
|
tree.remove(word)
|
||||||
val node = tree.search(word)
|
val node = tree.search(word)
|
||||||
Assertions.assertNull(node)
|
assertNull(node)
|
||||||
val result = tree.fuzzySearch(word, 5)
|
val result = tree.fuzzySearch(word, 5)
|
||||||
Assertions.assertEquals(0, result.size)
|
assertEquals(0, result.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,21 +67,21 @@ class LevtreeTest {
|
|||||||
run {
|
run {
|
||||||
val word = "fired"
|
val word = "fired"
|
||||||
val result = tree.fuzzySearch(word, 4)
|
val result = tree.fuzzySearch(word, 4)
|
||||||
Assertions.assertEquals(4, result.size)
|
assertEquals(4, result.size)
|
||||||
Assertions.assertEquals("tired" to 1, result[0])
|
assertEquals("tired" to 1, result[0])
|
||||||
}
|
}
|
||||||
run {
|
run {
|
||||||
val word = "tierd"
|
val word = "tierd"
|
||||||
val result = tree.fuzzySearch(word, 4)
|
val result = tree.fuzzySearch(word, 4)
|
||||||
Assertions.assertEquals(4, result.size)
|
assertEquals(4, result.size)
|
||||||
Assertions.assertEquals("tired" to 2, result[0])
|
assertEquals("tired" to 2, result[0])
|
||||||
}
|
}
|
||||||
run {
|
run {
|
||||||
val word = "tierd"
|
val word = "tierd"
|
||||||
tree.remove("tired")
|
tree.remove("tired")
|
||||||
val result = tree.fuzzySearch(word, 4)
|
val result = tree.fuzzySearch(word, 4)
|
||||||
Assertions.assertEquals(4, result.size)
|
assertEquals(4, result.size)
|
||||||
Assertions.assertEquals("trail" to 4, result[0])
|
assertEquals("trail" to 4, result[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,22 +93,22 @@ class LevtreeTest {
|
|||||||
run {
|
run {
|
||||||
val word = "fired"
|
val word = "fired"
|
||||||
val result = tree.fuzzySearch(word, 4)
|
val result = tree.fuzzySearch(word, 4)
|
||||||
Assertions.assertEquals(4, result.size)
|
assertEquals(4, result.size)
|
||||||
Assertions.assertEquals("tired" to 1, result[0])
|
assertEquals("tired" to 1, result[0])
|
||||||
}
|
}
|
||||||
run {
|
run {
|
||||||
val word = "capitvate"
|
val word = "capitvate"
|
||||||
val result = tree.fuzzySearch(word, 4)
|
val result = tree.fuzzySearch(word, 4)
|
||||||
Assertions.assertEquals(4, result.size)
|
assertEquals(4, result.size)
|
||||||
Assertions.assertEquals("captivate" to 1, result[0])
|
assertEquals("captivate" to 1, result[0])
|
||||||
Assertions.assertEquals("captivity" to 3, result[1])
|
assertEquals("captivity" to 3, result[1])
|
||||||
}
|
}
|
||||||
run {
|
run {
|
||||||
tree.remove("captivate")
|
tree.remove("captivate")
|
||||||
val word = "capitvate"
|
val word = "capitvate"
|
||||||
val result = tree.fuzzySearch(word, 4)
|
val result = tree.fuzzySearch(word, 4)
|
||||||
Assertions.assertEquals(4, result.size)
|
assertEquals(4, result.size)
|
||||||
Assertions.assertEquals("captivity" to 3, result[0])
|
assertEquals("captivity" to 3, result[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
module net.woggioni.klevtree {
|
module net.woggioni.klevtree {
|
||||||
requires net.woggioni.jwo;
|
requires kotlin.stdlib;
|
||||||
exports net.woggioni.klevtree;
|
exports net.woggioni.klevtree;
|
||||||
}
|
}
|
@@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Configuration status="WARN">
|
|
||||||
<Appenders>
|
|
||||||
<Console name="Console" target="SYSTEM_ERR">
|
|
||||||
<PatternLayout pattern="%d{HH:mm:ss,SSS} %highlight{[%p]} (%t) %c: %m%n"/>
|
|
||||||
<Filters>
|
|
||||||
<ThresholdFilter level="ERROR" onMatch="ACCEPT" />
|
|
||||||
</Filters>
|
|
||||||
</Console>
|
|
||||||
</Appenders>
|
|
||||||
|
|
||||||
<Loggers>
|
|
||||||
<Root level="ALL">
|
|
||||||
<AppenderRef ref="Console"/>
|
|
||||||
</Root>
|
|
||||||
</Loggers>
|
|
||||||
</Configuration>
|
|
Reference in New Issue
Block a user