blob: 5f3c6875bc1f70ab56a036cb2cf44c092dcddd30 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nlpcraft.model.intent.idl.compiler
import org.apache.nlpcraft.model.intent.compiler.{NCIdlCompiler, NCIdlCompilerGlobal}
import org.apache.nlpcraft.model.intent.{NCIdlContext, NCIdlFunction, NCIdlStackItem}
import org.apache.nlpcraft.model.{NCModel, NCModelView, NCToken}
import org.junit.jupiter.api.{BeforeEach, Test}
import java.util
import java.util.{Collections, UUID}
import scala.collection.JavaConverters._
/**
* Tests for IDL functions.
*/
class NCIdlCompilerSpecFunctions {
private final val MODEL_ID = "test.mdl.id"
private final val MODEL: NCModel = new NCModel {
override val getId: String = MODEL_ID
override val getName: String = MODEL_ID
override val getVersion: String = "1.0.0"
override def getOrigin: String = "test"
}
private final val DUMMY_CTX: NCIdlContext = NCIdlContext(req = null)
@BeforeEach
def before(): Unit = NCIdlCompilerGlobal.clearCache(MODEL_ID)
import BoolFunc._
case class BoolFunc(func: NCIdlFunction, token: NCToken, result: Boolean) {
override def toString: String =
s"Boolean function [" +
s"token=${t2s(token)}, " +
s"function=$func, " +
s"expected=$result" +
s"]"
}
object BoolFunc {
private def t2s(t: NCToken) = s"${t.getOriginalText} (${t.getId})"
private def mkToken(
id: String = null,
value: String = null,
txt: String = null,
start: Int = 0,
end: Int = 0,
meta: Map[String, AnyRef] = Map.empty[String, AnyRef]
): NCToken = {
val map = new util.HashMap[String, AnyRef]
map.putAll(meta.asJava)
def nvl(v: String): String = if (v != null) v else "(not set)"
map.put("nlpcraft:nlp:origtext", nvl(txt))
new NCToken {
override def getModel: NCModelView = MODEL
override def getServerRequestId: String = UUID.randomUUID().toString
override def getId: String = nvl(id)
override def getParentId: String = null
override def getAncestors: util.List[String] = Collections.emptyList()
override def getPartTokens: util.List[NCToken] = Collections.emptyList()
override def getAliases: util.Set[String] = Collections.emptySet()
override def getValue: String = value
override def getGroups: util.List[String] = Collections.singletonList(id)
override def getStartCharIndex: Int = start
override def getEndCharIndex: Int = end
override def isAbstract: Boolean = false
override def getMetadata: util.Map[String, AnyRef] = map
}
}
private def mkFunc(term: String): NCIdlFunction = {
val intents = NCIdlCompiler.compileIntents(s"intent=i term(t)={$term}", MODEL, MODEL_ID)
require(intents.size == 1)
val intent = intents.head
require(intent.terms.size == 1)
new NCIdlFunction() {
override def apply(v1: NCToken, v2: NCIdlContext): NCIdlStackItem = intent.terms.head.pred.apply(v1, v2)
override def toString(): String = s"Function, based on term: $term"
}
}
def apply(boolCondition: String, token: String, result: Boolean): BoolFunc =
BoolFunc(func = mkFunc(boolCondition), token = mkToken(token), result = result)
def apply(boolCondition: String, tokenId: String): BoolFunc =
BoolFunc(func = mkFunc(boolCondition), token = mkToken(tokenId), result = true)
def apply(boolCondition: String, token: NCToken, result: Boolean): BoolFunc =
BoolFunc(func = mkFunc(boolCondition), token, result = result)
def apply(bool: String): BoolFunc =
BoolFunc(func = mkFunc(bool), mkToken(), result = true)
}
private def test(funcs: BoolFunc*): Unit =
for ((func, idx) ← funcs.zipWithIndex) {
val res =
try
func.func.apply(func.token, DUMMY_CTX).value
catch {
case e: Exceptionthrow new Exception(s"Execution error [index=$idx, testFunc=$func]", e)
}
res match {
case b: java.lang.Boolean
require(b == func.result,
s"Unexpected result [" +
s"index=$idx, " +
s"testFunc=$func, " +
s"expected=${func.result}, " +
s"result=$res" +
s"]"
)
case _ ⇒
require(requirement = false,
s"Unexpected result type [" +
s"index=$idx, " +
s"testFunc=$func, " +
s"expected=${func.result}, " +
s"result=$res" +
s"]"
)
}
}
@Test
def test(): Unit = {
val now = System.currentTimeMillis()
test(
BoolFunc(boolCondition = "id() == 'a'", tokenId = "a"),
// Math.
// BoolFunc(boolCondition = "sin(90.0) == 0")
// BoolFunc(boolCondition = "rand() < 1")
// String.
BoolFunc(bool = "trim(' a b ') == 'a b'"),
BoolFunc(bool = "strip(' a b ') == 'a b'"),
BoolFunc(bool = "uppercase('aB') == 'AB'"),
BoolFunc(bool = "lowercase('aB') == 'ab'"),
BoolFunc(bool = "is_num('a') == false"),
BoolFunc(bool = "is_num('1') == true"),
// Statistical.
// BoolFunc(boolCondition = "max(list(1, 2, 3)) == 3"),
// BoolFunc(boolCondition = "min(list(1, 2, 3)) == 1")
// Collection.
// BoolFunc(boolCondition = "first(list(1, 2, 3)) == 1"),
// BoolFunc(boolCondition = "last(list(1, 2, 3)) == 3")
BoolFunc(bool = "is_empty(list()) == true"),
BoolFunc(bool = "is_empty(list(1)) == false"),
BoolFunc(bool = "non_empty(list()) == false"),
BoolFunc(bool = "non_empty(list(1)) == true"),
// Date-time functions.
BoolFunc(bool = s"now() - $now < 1000")
)
}
}