You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nlpcraft.apache.org by se...@apache.org on 2021/03/26 21:23:12 UTC
[incubator-nlpcraft] branch NLPCRAFT-278 updated: Minor fixes.
Tests added.
This is an automated email from the ASF dual-hosted git repository.
sergeykamov pushed a commit to branch NLPCRAFT-278
in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git
The following commit(s) were added to refs/heads/NLPCRAFT-278 by this push:
new b5bba5e Minor fixes. Tests added.
b5bba5e is described below
commit b5bba5ebe8183046b61cd7f2b2ddf2a7f813c3a4
Author: Sergey Kamov <sk...@gmail.com>
AuthorDate: Sat Mar 27 00:23:03 2021 +0300
Minor fixes. Tests added.
---
.../nlpcraft/common/config/NCConfigurableJava.java | 4 +-
.../common/extcfg/NCExternalConfigManager.scala | 4 +-
.../nlpcraft/common/makro/NCMacroCompiler.scala | 4 +-
.../org/apache/nlpcraft/common/util/NCUtils.scala | 81 +++++++++---
.../model/intent/compiler/NCIdlCompiler.scala | 52 +++++---
.../model/intent/compiler/NCIdlCompilerBase.scala | 8 +-
.../model/intent/solver/NCIntentSolverEngine.scala | 38 +++---
.../probe/mgrs/conn/NCConnectionManager.scala | 16 +--
.../server/geo/tools/NCGeoNamesGenerator.scala | 2 +-
.../geo/tools/NCGeoStateNamesGenerator.scala | 2 +-
.../geo/tools/metro/NCGeoMetroGenerator.scala | 2 +-
.../geo/tools/unstats/NCUnsdStatsService.scala | 2 +-
.../org/apache/nlpcraft/server/json/NCJson.scala | 4 +-
.../nlpcraft/model/dialog/NCDialogSpec.scala | 71 +++++++++-
.../nlpcraft/model/dialog/NCDialogSpec2.scala | 147 +++++++++++++++++++++
.../idl/compiler/functions/NCIdlFunctions.scala | 84 +++++++++---
.../compiler/functions/NCIdlFunctionsCompany.scala | 1 -
.../compiler/functions/NCIdlFunctionsCustom.scala | 86 ++++++++++++
.../compiler/functions/NCIdlFunctionsMath.scala | 18 +--
.../compiler/functions/NCIdlFunctionsOther.scala | 15 ++-
.../compiler/functions/NCIdlFunctionsRequest.scala | 2 +-
.../compiler/functions/NCIdlFunctionsStat.scala | 15 ++-
.../compiler/functions/NCIdlFunctionsStrings.scala | 15 ++-
.../compiler/functions/NCIdlFunctionsToken.scala | 4 +-
...nsStat.scala => NCIdlFunctionsTokensUsed.scala} | 48 ++++---
.../nlpcraft/model/intent/idl/compiler/test_ok.idl | 4 +-
26 files changed, 564 insertions(+), 165 deletions(-)
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/config/NCConfigurableJava.java b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/config/NCConfigurableJava.java
index 320eb12..e7cfd45 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/config/NCConfigurableJava.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/config/NCConfigurableJava.java
@@ -62,7 +62,7 @@ public class NCConfigurableJava {
abortWith(String.format("Invalid 'host:port' endpoint format: %s", ep));
try {
- return new Pair<String, Integer>(ep.substring(0, i), Integer.parseInt(ep.substring(i + 1)));
+ return new Pair<>(ep.substring(0, i), Integer.parseInt(ep.substring(i + 1)));
}
catch (NumberFormatException e) {
abortWith(String.format("Invalid 'host:port' endpoint port: %s", ep));
@@ -80,7 +80,7 @@ public class NCConfigurableJava {
* @return Pair of host and port from given configuration property or default values.
*/
public Pair<String, Integer> getHostPortOrElse(String name, String dfltHost, int dfltPort) {
- return cfg.hasPath(name) ? getHostPort(name) : new Pair<String, Integer>(dfltHost, dfltPort);
+ return cfg.hasPath(name) ? getHostPort(name) : new Pair<>(dfltHost, dfltPort);
}
/**
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/extcfg/NCExternalConfigManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/extcfg/NCExternalConfigManager.scala
index c041f7c..d6e0b91 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/extcfg/NCExternalConfigManager.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/extcfg/NCExternalConfigManager.scala
@@ -231,7 +231,7 @@ object NCExternalConfigManager extends NCService {
@throws[NCE]
def getContent(typ: NCExternalConfigType, res: String, parent: Span = null): String =
startScopedSpan("getContent", parent, "res" → res) { _ ⇒
- mkString(U.readFile(mkFile(typ, res), "UTF-8"))
+ mkString(U.readFile(mkFile(typ, res)))
}
/**
@@ -269,7 +269,7 @@ object NCExternalConfigManager extends NCService {
d.listFiles(new FileFilter { override def accept(f: File): Boolean = f.isFile && resFilter(f.getName) })
if (files != null)
- files.toStream.map(f ⇒ NCExternalConfigHolder(typ, f.getName, mkString(U.readFile(f, "UTF-8"))))
+ files.toStream.map(f ⇒ NCExternalConfigHolder(typ, f.getName, mkString(U.readFile(f))))
else
Stream.empty
}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroCompiler.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroCompiler.scala
index 16ff67f..561fe23 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroCompiler.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroCompiler.scala
@@ -87,12 +87,12 @@ object NCMacroCompiler extends LazyLogging {
// Add harmless empty string.
buf += ""
- stack.push(StackItem(buf, false))
+ stack.push(StackItem(buf, isGroup = false))
}
override def enterGroup(ctx: P.GroupContext): Unit = {
// NOTE: group cannot be empty based on the BNF grammar.
- stack.push(StackItem(mutable.Buffer.empty[String], true))
+ stack.push(StackItem(mutable.Buffer.empty[String], isGroup = true))
}
override def exitExpr(ctx: NCMacroDslParser.ExprContext): Unit = {
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala
index df50ab1..42023ae 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala
@@ -860,7 +860,7 @@ object NCUtils extends LazyLogging {
* @param path File path.
*/
@throws[NCE]
- def serializePath(path: String, obj: Any): Unit = {
+ def serializePath(path: String, obj: Any): Unit =
try {
manageOutput(new FileOutputStream(path)) acquireAndGet { out ⇒
out.writeObject(obj)
@@ -871,7 +871,6 @@ object NCUtils extends LazyLogging {
catch {
case e: IOException ⇒ throw new NCE(s"Error writing file: $path", e)
}
- }
/**
* Serializes data from file.
@@ -1945,35 +1944,74 @@ object NCUtils extends LazyLogging {
}
/**
- *
+ * Calling a method with one parameter and a non-null return value.
+ *
* @param objFac
* @param mtdName
* @param arg
* @tparam T
* @return
*/
- def callMethod[T: ClassTag, R](objFac: () ⇒ Object, mtdName: String, arg: T): R = {
- val obj = objFac()
- val mtd = obj.getClass.getMethod(mtdName, classTag[T].runtimeClass)
-
- var flag = mtd.canAccess(obj)
-
+ @throws[NCE]
+ def callMethod[T: ClassTag, R: ClassTag](objFac: () ⇒ Any, mtdName: String, arg: T): R =
try {
- if (!flag) {
- mtd.setAccessible(true)
-
- flag = true
+ val obj: Any = objFac()
+
+ if (obj == null)
+ throw new NCE(s"Invalid 'null' object created attempting to call method: $mtdName")
+
+ val argCls = classTag[T].runtimeClass
+ val retCls = classTag[R].runtimeClass
+
+ def mkErrors = s"[" +
+ s"name=${obj.getClass.getName}#$mtdName(...), " +
+ s"argType=${argCls.getCanonicalName}, " +
+ s"retType=${retCls.getCanonicalName}" +
+ s"]"
+
+ val mtd =
+ try
+ obj.getClass.getMethod(mtdName, argCls)
+ catch {
+ case e: NoSuchMethodException ⇒ throw new NCE(s"Method not found $mkErrors", e)
+ }
+
+ var flag = mtd.canAccess(obj)
+
+ try {
+ if (!flag) {
+ mtd.setAccessible(true)
+
+ flag = true
+ }
+ else
+ flag = false
+
+ val res =
+ try
+ mtd.invoke(obj, arg.asInstanceOf[Object])
+ catch {
+ case e: Throwable ⇒ throw new NCE(s"Failed to execute method $mkErrors", e)
+ }
+
+ if (res == null)
+ throw new NCE(s"Unexpected 'null' result for method execution $mkErrors")
+
+ try
+ res.asInstanceOf[R]
+ catch {
+ case e: ClassCastException ⇒ throw new NCE(s"Invalid method result type $mkErrors", e)
+ }
+ }
+ finally {
+ if (flag)
+ mtd.setAccessible(false)
}
- else
- flag = false
-
- mtd.invoke(obj, arg.asInstanceOf[Object]).asInstanceOf[R]
}
- finally {
- if (flag)
- mtd.setAccessible(false)
+ catch {
+ case e: NCE ⇒ throw e
+ case e: Throwable ⇒ throw new NCE(s"Unexpected error calling method: $mtdName(...)", e)
}
- }
/**
*
@@ -1981,6 +2019,7 @@ object NCUtils extends LazyLogging {
* @tparam T Type of the object to create.
* @return New instance of the specified type.
*/
+ @throws[NCE]
def mkObject[T](clsName: String): T = {
try
// Try Java reflection first.
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/compiler/NCIdlCompiler.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/compiler/NCIdlCompiler.scala
index 7e24d46..3e9f737 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/compiler/NCIdlCompiler.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/compiler/NCIdlCompiler.scala
@@ -77,9 +77,11 @@ object NCIdlCompiler extends LazyLogging {
private var min = 1
private var max = 1
- // Current method reference.
- private var refClsName: Option[String] = None
- private var refMtdName: Option[String] = None
+ // Class & method reference.
+ private var clsName: Option[String] = None
+ private var mtdName: Option[String] = None
+ private var flowClsName: Option[String] = None
+ private var flowMtdName: Option[String] = None
// List of instructions for the current expression.
private var expr = mutable.Buffer.empty[SI]
@@ -185,10 +187,8 @@ object NCIdlCompiler extends LazyLogging {
}
override def exitMtdRef(ctx: IDP.MtdRefContext): Unit = {
- if (ctx.javaFqn() != null)
- refClsName = Some(ctx.javaFqn().getText)
-
- refMtdName = Some(ctx.id().getText)
+ clsName = if (ctx.javaFqn() != null) Some(ctx.javaFqn().getText) else None
+ mtdName = Some(ctx.id().getText)
}
override def exitTermId(ctx: IDP.TermIdContext): Unit = {
@@ -256,6 +256,9 @@ object NCIdlCompiler extends LazyLogging {
override def exitFlowDecl(ctx: IDP.FlowDeclContext): Unit = {
if (ctx.qstring() != null) {
+ flowClsName = None
+ flowMtdName = None
+
val regex = U.trimQuotes(ctx.qstring().getText)
if (regex != null && regex.length > 2)
@@ -269,6 +272,13 @@ object NCIdlCompiler extends LazyLogging {
newSyntaxError(s"${e.getDescription} in intent flow regex '${e.getPattern}' near index ${e.getIndex}.")(ctx.qstring())
}
}
+ else {
+ flowClsName = clsName
+ flowMtdName = mtdName
+ }
+
+ clsName = None
+ mtdName = None
}
override def exitTerm(ctx: IDP.TermContext): Unit = {
@@ -276,11 +286,11 @@ object NCIdlCompiler extends LazyLogging {
throw newSyntaxError(s"Invalid intent term min quantifiers: $min (must be min >= 0 && min <= max).")(ctx.minMax())
if (max < 1)
throw newSyntaxError(s"Invalid intent term max quantifiers: $max (must be max >= 1).")(ctx.minMax())
-
- val pred: NCIdlFunction = if (refMtdName.isDefined) { // User-code defined term.
+
+ val pred: NCIdlFunction = if (mtdName.isDefined) { // User-code defined term.
// Closure copies.
- val clsName = refClsName.orNull
- val mtdName = refMtdName.orNull
+ val cls = clsName.orNull
+ val mtd = mtdName.orNull
(tok: NCToken, termCtx: NCIdlContext) ⇒ {
val javaCtx: NCTokenPredicateContext = new NCTokenPredicateContext {
@@ -294,12 +304,12 @@ object NCIdlCompiler extends LazyLogging {
}
val mdl = tok.getModel
- val mdlCls = if (clsName == null) mdl.meta[String](MDL_META_MODEL_CLASS_KEY) else clsName
+ val mdlCls = if (cls == null) mdl.meta[String](MDL_META_MODEL_CLASS_KEY) else cls
try {
val res = U.callMethod[NCTokenPredicateContext, NCTokenPredicateResult](
- () ⇒ if (clsName == null) mdl else U.mkObject(clsName),
- mtdName,
+ () ⇒ if (cls == null) mdl else U.mkObject(cls),
+ mtd,
javaCtx
)
@@ -307,7 +317,7 @@ object NCIdlCompiler extends LazyLogging {
}
catch {
case e: Exception ⇒
- throw newRuntimeError(s"Failed to invoke custom intent term: $mdlCls.$mtdName", e)(ctx.mtdDecl())
+ throw newRuntimeError(s"Failed to invoke custom intent term: $mdlCls.$mtd(...)", e)(ctx.mtdDecl())
}
}
}
@@ -330,8 +340,8 @@ object NCIdlCompiler extends LazyLogging {
termId = null
expr.clear()
vars.clear()
- refClsName = None
- refMtdName = None
+ clsName = None
+ mtdName = None
}
/**
@@ -451,14 +461,14 @@ object NCIdlCompiler extends LazyLogging {
ordered,
if (intentMeta == null) Map.empty else intentMeta,
flowRegex,
- refClsName,
- refMtdName,
+ flowClsName,
+ flowMtdName,
terms.toList
)
)(ctx.intentId())
- refClsName = None
- refMtdName = None
+ flowClsName = None
+ flowMtdName = None
intentMeta = null
terms.clear()
}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/compiler/NCIdlCompilerBase.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/compiler/NCIdlCompilerBase.scala
index daccbdb..f16ef03 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/compiler/NCIdlCompilerBase.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/compiler/NCIdlCompilerBase.scala
@@ -386,7 +386,7 @@ trait NCIdlCompilerBase {
def parseEqNeqExpr(eq: TN, neq: TN)(implicit ctx: PRC): SI = (_, stack: S, _) ⇒ {
val (x1, x2) = pop2()(stack, ctx)
- def doEq(op: String, v1: Object, v2: Object): Boolean = {
+ def doEq(v1: Object, v2: Object): Boolean = {
if (v1 eq v2) true
else if (v1 == null && v2 == null) true
else if ((v1 == null && v2 != null) || (v1 != null && v2 == null)) false
@@ -405,11 +405,11 @@ trait NCIdlCompilerBase {
val f =
if (eq != null)
- doEq("==", v1, v2)
+ doEq(v1, v2)
else {
assert(neq != null)
- !doEq("!='", v1, v2)
+ !doEq(v1, v2)
}
Z(f, n)
@@ -742,7 +742,7 @@ trait NCIdlCompilerBase {
else {
val seq: Seq[Double] = lst.asScala.map(p ⇒ JDouble.valueOf(p.toString).doubleValue())
- Z(seq.sum / seq.size, n)
+ Z(seq.sum / seq.length, n)
}
catch {
case e: Exception ⇒ throw rtListTypeError(fun, e)
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/solver/NCIntentSolverEngine.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/solver/NCIntentSolverEngine.scala
index 9cba0d7..7dbdcbf 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/solver/NCIntentSolverEngine.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/solver/NCIntentSolverEngine.scala
@@ -18,15 +18,15 @@
package org.apache.nlpcraft.model.intent.solver
import com.typesafe.scalalogging.LazyLogging
+import org.apache.nlpcraft.common._
import org.apache.nlpcraft.common.ascii.NCAsciiTable
import org.apache.nlpcraft.common.debug.{NCLogGroupToken, NCLogHolder}
import org.apache.nlpcraft.common.opencensus.NCOpenCensusTrace
-import org.apache.nlpcraft.common._
import org.apache.nlpcraft.model.impl.NCTokenLogger
-import org.apache.nlpcraft.model.{NCContext, NCDialogFlowItem, NCIntentMatch, NCResult, NCToken}
-import org.apache.nlpcraft.probe.mgrs.dialogflow.NCDialogFlowManager
import org.apache.nlpcraft.model.impl.NCTokenPimp._
import org.apache.nlpcraft.model.intent.{NCIdlContext, NCIdlFunction, NCIdlIntent, NCIdlTerm, NCIdlStackItem ⇒ Z}
+import org.apache.nlpcraft.model.{NCContext, NCDialogFlowItem, NCIntentMatch, NCResult, NCToken}
+import org.apache.nlpcraft.probe.mgrs.dialogflow.NCDialogFlowManager
import java.util.function.Function
import scala.collection.JavaConverters._
@@ -435,31 +435,31 @@ object NCIntentSolverEngine extends LazyLogging with NCOpenCensusTrace {
val str = flow.map(_.getIntentId).mkString(" ")
def x(s: String): Unit = {
- logger.info(s"Intent '$intentId' ${bo(s)} regex dialog flow $varStr:")
+ logger.info(s"Intent '$intentId' $s regex dialog flow $varStr:")
logger.info(s" |-- ${c("Intent IDs :")} $str")
logger.info(s" +-- ${c("Match regex :")} ${flowRegex.get.toString}")
}
if (!flowRegex.get.matcher(str).find(0)) {
- x("did not match")
+ x(s"${bo(r("did not match"))}")
flowMatched = false
}
else
- x("matched")
+ x(s"matched")
}
else if (intent.flowMtdName.isDefined) {
- require(intent.flowClsName.isDefined)
-
- val clsName = intent.flowClsName.get
+ val clsName = intent.flowClsName.orNull
val mtdName = intent.flowMtdName.get
-
- val fqn = s"$clsName.$mtdName(java.util.List[NCDialogFlowItem])"
-
+
+ val fqn =
+ s"${if (clsName == null) ctx.getModel.getClass.getName else clsName}." +
+ s"$mtdName(java.util.List[NCDialogFlowItem])"
+
val res =
try
U.callMethod[java.util.List[NCDialogFlowItem], java.lang.Boolean](
- U.mkObject(clsName),
+ () ⇒ if (clsName == null) ctx.getModel else U.mkObject(clsName),
mtdName,
flow.toList.asJava
)
@@ -469,12 +469,12 @@ object NCIntentSolverEngine extends LazyLogging with NCOpenCensusTrace {
}
def x(s: String): Unit = {
- logger.info(s"Intent '$intentId' ${bo(s)} custom flow callback $varStr:")
+ logger.info(s"Intent '$intentId' $s custom flow callback $varStr:")
logger.info(s" +-- ${c("Custom callback :")} $fqn")
}
if (!res) {
- x("did not match")
+ x(s"${bo(r("did not match"))}")
flowMatched = false
}
@@ -541,7 +541,7 @@ object NCIntentSolverEngine extends LazyLogging with NCOpenCensusTrace {
case None ⇒
// Term is missing. Stop further processing for this intent. This intent cannot be matched.
- logger.info(s"Intent '$intentId' ${r("did not")} match because of unmatched term '$term' $varStr.")
+ logger.info(s"Intent '$intentId' ${bo(r("did not match"))} because of unmatched term '$term' $varStr.")
abort = true
}
@@ -557,15 +557,15 @@ object NCIntentSolverEngine extends LazyLogging with NCOpenCensusTrace {
var res: Option[IntentMatch] = None
if (usedSenToks.isEmpty && usedConvToks.isEmpty)
- logger.info(s"Intent '$intentId' ${r("did not")} match because no tokens were matched $varStr.")
+ logger.info(s"Intent '$intentId' ${bo(r("did not match"))} because no tokens were matched $varStr.")
else if (usedSenToks.isEmpty && usedConvToks.nonEmpty)
- logger.info(s"Intent '$intentId' ${r("did not")} match because all its matched tokens came from STM $varStr.")
+ logger.info(s"Intent '$intentId' ${bo(r("did not match"))} because all its matched tokens came from STM $varStr.")
else if (unusedSenToks.exists(_.token.isUserDefined))
NCTokenLogger.prepareTable(unusedSenToks.filter(_.token.isUserDefined).map(_.token)).
info(
logger,
Some(
- s"Intent '$intentId' ${r("did not")} match because of remaining unused user tokens $varStr." +
+ s"Intent '$intentId' ${bo(r("did not match"))} because of remaining unused user tokens $varStr." +
s"\nUnused user tokens for intent '$intentId' $varStr:"
)
)
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/conn/NCConnectionManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/conn/NCConnectionManager.scala
index 8121f88..e19a9d2 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/conn/NCConnectionManager.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/conn/NCConnectionManager.scala
@@ -17,13 +17,6 @@
package org.apache.nlpcraft.probe.mgrs.conn
-import java.io.{EOFException, IOException, InterruptedIOException}
-import java.net.{InetAddress, NetworkInterface}
-import java.util
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.atomic.AtomicInteger
-import java.util.{Properties, TimeZone}
-
import io.opencensus.trace.Span
import org.apache.nlpcraft.common._
import org.apache.nlpcraft.common.config.NCConfigurable
@@ -35,6 +28,11 @@ import org.apache.nlpcraft.probe.mgrs.NCProbeMessage
import org.apache.nlpcraft.probe.mgrs.cmd.NCCommandManager
import org.apache.nlpcraft.probe.mgrs.model.NCModelManager
+import java.io.{EOFException, IOException, InterruptedIOException}
+import java.net.{InetAddress, NetworkInterface}
+import java.util
+import java.util.concurrent.CountDownLatch
+import java.util.{Properties, TimeZone}
import scala.collection.mutable
/**
@@ -176,11 +174,11 @@ object NCConnectionManager extends NCService {
val ver = NCVersion.getCurrent
val tmz = TimeZone.getDefault
- val srvNlpEng =
+ val srvNlpEng: String =
hashResp.getOrElse(
"NLP_ENGINE",
throw new HandshakeError("NLP engine parameter missed in response.")
- )
+ ).asInstanceOf[String]
val probeNlpEng = NCNlpCoreManager.getEngine
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/NCGeoNamesGenerator.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/NCGeoNamesGenerator.scala
index 2b64a16..35ab1cc 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/NCGeoNamesGenerator.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/NCGeoNamesGenerator.scala
@@ -74,7 +74,7 @@ object NCGeoNamesGenerator extends App {
// GEO name ID → internal representation mapping.
private val ids = mutable.Map.empty[String, Location]
- private def read(path: String): Seq[String] = U.readPath(path, "UTF-8").filter(!_.startsWith("#"))
+ private def read(path: String): Seq[String] = U.readPath(path).filter(!_.startsWith("#"))
// Process country and continent information.
private def processCountries(unsdContinents: Seq[NCUnsdStatsContinent]): Set[Country] = {
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/NCGeoStateNamesGenerator.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/NCGeoStateNamesGenerator.scala
index 8c570dc..e775cd9 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/NCGeoStateNamesGenerator.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/NCGeoStateNamesGenerator.scala
@@ -31,7 +31,7 @@ import org.apache.nlpcraft.common.U
object NCGeoStateNamesGenerator extends App {
// Produce a map of regions (countryCode + regCode → region name)).
private def getStates(txtFile: String): Map[String, String] =
- U.readPath(txtFile, "UTF-8").filter(!_.startsWith("#")).flatMap(line ⇒ {
+ U.readPath(txtFile).filter(!_.startsWith("#")).flatMap(line ⇒ {
val seq = line.split("\t").toSeq
if (seq(7) == "ADM1" && seq(8) == "US") {
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/metro/NCGeoMetroGenerator.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/metro/NCGeoMetroGenerator.scala
index 28565ac..a76b823 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/metro/NCGeoMetroGenerator.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/metro/NCGeoMetroGenerator.scala
@@ -43,7 +43,7 @@ object NCGeoMetroGenerator extends App {
U.normalize(s.replaceAll("\\(", " ").replaceAll("\\)", " "), " ")
private def generate() {
- val lines = U.readPath(in, "UTF-8").map(_.strip).filter(_.nonEmpty)
+ val lines = U.readPath(in).map(_.strip).filter(_.nonEmpty)
// Skips header.
val metro = lines.tail.filter(!_.contains("(not set)")).map(line ⇒ Holder(line.takeWhile(_ != ',')))
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/unstats/NCUnsdStatsService.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/unstats/NCUnsdStatsService.scala
index ac4ba82..c7030cf 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/unstats/NCUnsdStatsService.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/geo/tools/unstats/NCUnsdStatsService.scala
@@ -72,7 +72,7 @@ object NCUnsdStatsService {
private val codesPath = s"$dir/codes.txt"
private def read(path: String): Seq[String] =
- U.readPath(path, "UTF-8").map(_.strip).filter(_.nonEmpty).filter(_.head != '#')
+ U.readPath(path).map(_.strip).filter(_.nonEmpty).filter(_.head != '#')
def skip(iso: String): Boolean = SKIPPED_COUNTRIES_ISO3.contains(iso)
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/json/NCJson.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/json/NCJson.scala
index 9d1f452..a63b1c1 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/json/NCJson.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/json/NCJson.scala
@@ -239,14 +239,14 @@ object NCJson {
*
* @param f File to extract from.
*/
- private def readFile(f: File): String = removeComments(U.readFile(f, "UTF-8").mkString)
+ private def readFile(f: File): String = removeComments(U.readFile(f).mkString)
/**
* Reads stream.
*
* @param in Stream to extract from.
*/
- private def readStream(in: InputStream): String = removeComments(U.readStream(in, "UTF-8").mkString)
+ private def readStream(in: InputStream): String = removeComments(U.readStream(in).mkString)
/**
* Extracts type `T` from given JSON `file`.
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/dialog/NCDialogSpec.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/dialog/NCDialogSpec.scala
index 60b234b..3ebd2b5 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/dialog/NCDialogSpec.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/dialog/NCDialogSpec.scala
@@ -17,23 +17,33 @@
package org.apache.nlpcraft.model.dialog
-import org.apache.nlpcraft.model.{NCElement, NCIntent, NCModel, NCResult}
+import org.apache.nlpcraft.model.{NCDialogFlowItem, NCElement, NCIntent, NCModel, NCResult}
import org.apache.nlpcraft.{NCTestContext, NCTestElement, NCTestEnvironment}
import org.junit.jupiter.api.Assertions.{assertEquals, assertTrue}
import org.junit.jupiter.api.Test
import java.util
+import scala.collection.JavaConverters._
/**
* Test model.
*/
+class NCDialogSpecModelFlow {
+ def trueAlways(flow: java.util.List[NCDialogFlowItem]): Boolean = true
+ def falseAlways(flow: java.util.List[NCDialogFlowItem]): Boolean = false
+ def trueAfterOnA7(flow: java.util.List[NCDialogFlowItem]): Boolean = flow.asScala.exists(_.getIntentId == "onA7")
+ def trueAfterOnA7AndA8(flow: java.util.List[NCDialogFlowItem]): Boolean = {
+ val seq = flow.asScala
+ seq.exists(_.getIntentId == "onA7") && seq.exists(_.getIntentId == "onA8")
+ }
+}
+
class NCDialogSpecModel extends NCModel {
override def getId: String = this.getClass.getSimpleName
override def getName: String = this.getClass.getSimpleName
override def getVersion: String = "1.0.0"
- override def getElements: util.Set[NCElement] =
- Set((for (ch ← 'a' to 'y'; i ← 1 to 9) yield NCTestElement(s"$ch$i")):_*)
+ override def getElements: util.Set[NCElement] = Set((for (i ← 1 to 100) yield NCTestElement(s"a$i")):_*)
@NCIntent("intent=onA1 term~{tok_id() == 'a1'}")
def onA1(): NCResult = NCResult.text("ok")
@@ -46,6 +56,31 @@ class NCDialogSpecModel extends NCModel {
@NCIntent("intent=onA4 flow='onA1 onA1' term~{tok_id() == 'a4'}")
def onA4(): NCResult = NCResult.text("ok")
+
+ @NCIntent("intent=onA5 flow=/org.apache.nlpcraft.model.dialog.NCDialogSpecModelFlow#trueAlways/ term~{tok_id() == 'a5'}")
+ def onA5(): NCResult = NCResult.text("ok")
+
+ @NCIntent("intent=onA6 flow=/org.apache.nlpcraft.model.dialog.NCDialogSpecModelFlow#falseAlways/ term~{tok_id() == 'a6'}")
+ def onA6(): NCResult = NCResult.text("ok")
+
+ @NCIntent("intent=onA7 term~{tok_id() == 'a7'}")
+ def onA7(): NCResult = NCResult.text("ok")
+
+ @NCIntent("intent=onA8 flow=/org.apache.nlpcraft.model.dialog.NCDialogSpecModelFlow#trueAfterOnA7/ term~{tok_id() == 'a8'}")
+ def onA8(): NCResult = NCResult.text("ok")
+
+ @NCIntent("intent=onA9 flow=/org.apache.nlpcraft.model.dialog.NCDialogSpecModelFlow#trueAfterOnA7AndA8/ term~{tok_id() == 'a9'}")
+ def onA9(): NCResult = NCResult.text("ok")
+
+ def trueAlwaysInternal(flow: java.util.List[NCDialogFlowItem]): Boolean = true
+
+ @NCIntent("intent=onA10 flow=/#trueAlwaysInternal/ term~{tok_id() == 'a10'}")
+ def onA10(): NCResult = NCResult.text("ok")
+
+ def falseAlwaysInternal(flow: java.util.List[NCDialogFlowItem]): Boolean = false
+
+ @NCIntent("intent=onA11 flow=/#falseAlwaysInternal/ term~{tok_id() == 'a11'}")
+ def onA11(): NCResult = NCResult.text("ok")
}
/**
@@ -116,4 +151,34 @@ class NCDialogSpec extends NCTestContext {
"a4" → "onA4",
"a4" → "onA4"
)
+
+ @Test
+ private[dialog] def test4(): Unit = {
+ // Always true.
+ checkIntent("a5", "onA5")
+ checkIntent("a5", "onA5")
+
+ // Always false.
+ require(getClient.ask("a6").isFailed)
+ require(getClient.ask("a6").isFailed)
+ }
+
+ @Test
+ private[dialog] def test5(): Unit =
+ f(
+ "a8" → null,
+ "a9" → null,
+ "a7" → "onA7",
+ "a9" → null,
+ "a8" → "onA8",
+ "a9" → "onA9"
+ )
+
+ @Test
+ private[dialog] def test6(): Unit = {
+ // Always 'true'.
+ require(getClient.ask("a10").isOk)
+ // Always 'false'.
+ require(getClient.ask("a11").isFailed)
+ }
}
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/dialog/NCDialogSpec2.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/dialog/NCDialogSpec2.scala
new file mode 100644
index 0000000..6cf9249
--- /dev/null
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/dialog/NCDialogSpec2.scala
@@ -0,0 +1,147 @@
+/*
+ * 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.dialog
+
+import org.apache.nlpcraft.model.{NCDialogFlowItem, NCElement, NCIntent, NCModel, NCResult}
+import org.apache.nlpcraft.{NCTestContext, NCTestElement, NCTestEnvironment}
+import org.junit.jupiter.api.Test
+
+import java.util
+
+object NCDialogSpecModelFlow2 {
+ var error = false
+}
+
+import NCDialogSpecModelFlow2._
+
+/**
+ * Test model.
+ */
+class NCDialogSpecModelFlow2 {
+ def invalidDef1(flow: java.util.List[NCDialogFlowItem]): String = "string"
+ def invalidDef2(): Boolean = true
+ def invalidDef3(flow: java.util.List[NCDialogFlowItem]): Boolean = throw new IllegalStateException()
+ def invalidDef4(flow: java.util.List[NCDialogFlowItem]): java.lang.Boolean = null
+ def validDef(flow: java.util.List[NCDialogFlowItem]): Boolean = {
+ if (error)
+ throw new IllegalStateException()
+
+ true
+ }
+}
+
+/**
+ *
+ */
+class NCDialogSpecModel21 extends NCModel {
+ override def getId: String = this.getClass.getSimpleName
+ override def getName: String = this.getClass.getSimpleName
+ override def getVersion: String = "1.0.0"
+
+ override def getElements: util.Set[NCElement] = Set(NCTestElement("a"))
+
+ @NCIntent("intent=onA flow=/org.apache.nlpcraft.model.dialog.NCDialogSpecModelFlow2#invalidDef1/ term~{tok_id() == 'a'}")
+ def onA(): NCResult = NCResult.text("ok")
+}
+
+/**
+ *
+ */
+@NCTestEnvironment(model = classOf[NCDialogSpecModel21], startClient = true)
+class NCDialogSpec21 extends NCTestContext {
+ @Test
+ def test(): Unit = require(getClient.ask("a").isFailed)
+}
+
+/**
+ *
+ */
+class NCDialogSpecModel22 extends NCDialogSpecModel21 {
+ @NCIntent("intent=onA flow=/org.apache.nlpcraft.model.dialog.NCDialogSpecModelFlow2#invalidDef2/ term~{tok_id() == 'a'}")
+ override def onA(): NCResult = NCResult.text("ok")
+}
+
+/**
+ *
+ */
+@NCTestEnvironment(model = classOf[NCDialogSpecModel22], startClient = true)
+class NCDialogSpec22 extends NCDialogSpec21
+
+/**
+ *
+ */
+class NCDialogSpecModel23 extends NCDialogSpecModel21 {
+ @NCIntent("intent=onA flow=/org.apache.nlpcraft.model.dialog.NCDialogSpecModelFlow2#invalidDef3/ term~{tok_id() == 'a'}")
+ override def onA(): NCResult = NCResult.text("ok")
+}
+
+/**
+ *
+ */
+@NCTestEnvironment(model = classOf[NCDialogSpecModel23], startClient = true)
+class NCDialogSpec23 extends NCDialogSpec21
+
+/**
+ *
+ */
+class NCDialogSpecModel24 extends NCDialogSpecModel21 {
+ @NCIntent("intent=onA flow=/org.apache.nlpcraft.model.dialog.NCDialogSpecModelFlow2#invalidDef4/ term~{tok_id() == 'a'}")
+ override def onA(): NCResult = NCResult.text("ok")
+}
+
+/**
+ *
+ */
+@NCTestEnvironment(model = classOf[NCDialogSpecModel24], startClient = true)
+class NCDialogSpec24 extends NCDialogSpec21
+
+/**
+ *
+ */
+class NCDialogSpecModel25 extends NCDialogSpecModel21 {
+ @NCIntent("intent=onA flow=/org.apache.nlpcraft.model.dialog.NCDialogSpecModelFlow2#validDef/ term~{tok_id() == 'a'}")
+ override def onA(): NCResult = NCResult.text("ok")
+}
+
+/**
+ *
+ */
+@NCTestEnvironment(model = classOf[NCDialogSpecModel25], startClient = true)
+class NCDialogSpec25 extends NCTestContext {
+ @Test
+ def test(): Unit = {
+ def test(txt: String, exp: Boolean): Unit = {
+ NCDialogSpecModelFlow2.error = !exp
+
+ require(getClient.ask("a").isOk == exp)
+ }
+
+ test(txt = "a", exp = true)
+ test(txt = "a", exp = false)
+ test(txt = "a", exp = true)
+ }
+}
+
+
+
+
+
+
+
+
+
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctions.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctions.scala
index 4c8840d..35eb0f7 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctions.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctions.scala
@@ -20,7 +20,7 @@ package org.apache.nlpcraft.model.intent.idl.compiler.functions
import org.apache.nlpcraft.common.{NCE, ScalaMeta}
import org.apache.nlpcraft.model.intent.compiler.{NCIdlCompiler, NCIdlCompilerGlobal}
import org.apache.nlpcraft.model.intent.{NCIdlContext, NCIdlTerm}
-import org.apache.nlpcraft.model.{NCCompany, NCModel, NCModelView, NCRequest, NCToken, NCUser}
+import org.apache.nlpcraft.model.{NCCompany, NCModel, NCModelView, NCRequest, NCToken, NCTokenPredicateContext, NCTokenPredicateResult, NCUser}
import org.junit.jupiter.api.BeforeEach
import java.util
@@ -34,20 +34,36 @@ import scala.language.implicitConversions
private[functions] trait NCIdlFunctions {
private final val MODEL_ID = "test.mdl.id"
- final val MODEL: NCModel = new NCModel {
+ // It shouldn't be anonimous class because we need access to 'trueAlwaysCustomToken' method via reflection.
+ class TestModel extends 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"
+
+ def trueAlwaysCustomToken(ctx: NCTokenPredicateContext): NCTokenPredicateResult =
+ new NCTokenPredicateResult(true, 1)
}
+ final val MODEL: NCModel = new TestModel()
+
@BeforeEach
def before(): Unit = NCIdlCompilerGlobal.clearCache(MODEL_ID)
- case class TestDesc(truth: String, token: Option[NCToken] = None, idlCtx: NCIdlContext = ctx()) {
- val term: NCIdlTerm = {
- val intents = NCIdlCompiler.compileIntents(s"intent=i term(t)={$truth}", MODEL, MODEL_ID)
+ case class TestDesc(
+ truth: String,
+ token: Option[NCToken] = None,
+ idlCtx: NCIdlContext = ctx(),
+ isCustom: Boolean = false,
+ expectedRes: Boolean = true,
+ tokensUsed: Option[Int] = None
+ ) {
+ // It should be lazy for errors verification methods.
+ lazy val term: NCIdlTerm = {
+ val (s1, s2) = if (isCustom) ('/', '/') else ('{', '}')
+
+ val intents = NCIdlCompiler.compileIntents(s"intent=i term(t)=$s1$truth$s2", MODEL, MODEL_ID)
require(intents.size == 1)
require(intents.head.terms.size == 1)
@@ -70,7 +86,7 @@ private[functions] trait NCIdlFunctions {
TestDesc(truth = truth, token = Some(token))
}
- private def t2s(t: NCToken) = {
+ private def t2s(t: NCToken): String = {
def nvl(s: String, name: String): String = if (s != null) s else s"$name (not set)"
s"text=${nvl(t.getOriginalText, "text")} [${nvl(t.getId, "id")}]"
@@ -148,42 +164,66 @@ private[functions] trait NCIdlFunctions {
protected def test(funcs: TestDesc*): Unit =
for (f ← funcs) {
- val res =
+ val item =
try {
// Process declarations.
f.idlCtx.vars ++= f.term.decls
// Execute term's predicate.
- f.term.pred.apply(f.token.getOrElse(tkn()), f.idlCtx).value
+ f.term.pred.apply(f.token.getOrElse(tkn()), f.idlCtx)
}
catch {
- case e: NCE ⇒ throw new NCE(s"Execution error processing: $f", e)
+ case e: NCE ⇒ throw e
case e: Exception ⇒ throw new Exception(s"Execution error processing: $f", e)
}
- res match {
- case b: java.lang.Boolean ⇒ require(b, s"Unexpected FALSE result for: $f")
+ item.value match {
+ case b: java.lang.Boolean ⇒ require(if (f.expectedRes) b else !b, s"Unexpected '$b' result for: $f")
case _ ⇒
require(
requirement = false,
s"Unexpected result type [" +
- s"resType=${if (res == null) "null" else res.getClass.getName}, " +
- s"resValue=$res, " +
+ s"resType=${if (item.value == null) "null" else item.value.getClass.getName}, " +
+ s"resValue=${item.value}, " +
s"function=$f" +
s"]"
)
}
- }
- protected def expectError(f: String): Unit =
- try {
- test(f)
+ f.tokensUsed match {
+ case Some(exp) ⇒
+ require(
+ exp == item.tokUse,
+ s"Unexpected tokens used [" +
+ s"expectedTokensUsed=$exp, " +
+ s"resultTokensUsed=${item.tokUse}, " +
+ s"function=$f" +
+ s"]"
+ )
- require(false)
- }
- catch {
- case e: Exception ⇒ println(s"Expected error: ${e.getLocalizedMessage}")
+ case None ⇒ // No-op.
+ }
}
+ protected def expectError(funcs: TestDesc*): Unit =
+ for (f ← funcs)
+ try {
+ test(f)
+
+ require(false)
+ }
+ catch {
+ case e: Exception ⇒
+ println(s"Expected error: ${e.getLocalizedMessage}")
+
+ var cause = e.getCause
+
+ while (cause != null) {
+ println(s" Cause: ${cause.getLocalizedMessage} (${cause.getClass.getName})")
+
+ cause = cause.getCause
+ }
+ }
+
protected implicit def convert(pred: String): TestDesc = TestDesc(truth = pred)
-}
+}
\ No newline at end of file
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsCompany.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsCompany.scala
index 9a95032..b03a78c 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsCompany.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsCompany.scala
@@ -55,7 +55,6 @@ class NCIdlFunctionsCompany extends NCIdlFunctions {
override def getMetadata: util.Map[String, AnyRef] =
Map("k1" → "v1").map(p ⇒ p._1 → p._2.asInstanceOf[AnyRef]).asJava
})
-
}
private def test(comp: NCCompany): Unit = {
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsCustom.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsCustom.scala
new file mode 100644
index 0000000..651ca1e
--- /dev/null
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsCustom.scala
@@ -0,0 +1,86 @@
+/*
+ * 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.functions
+
+import org.apache.nlpcraft.common.U
+import org.apache.nlpcraft.model.{NCTokenPredicateContext, NCTokenPredicateResult}
+import org.junit.jupiter.api.Test
+
+class NCIdlTokensTestWrapper {
+ def trueOn123(ctx: NCTokenPredicateContext): NCTokenPredicateResult =
+ new NCTokenPredicateResult(ctx.getToken.getOriginalText == "123", 1)
+
+ def wrongParams1(): NCTokenPredicateResult = new NCTokenPredicateResult(true, 1)
+ def wrongParams2(s: String): NCTokenPredicateResult = new NCTokenPredicateResult(true, 1)
+ def wrongParams3(s: String, ctx: NCTokenPredicateContext): NCTokenPredicateResult =
+ new NCTokenPredicateResult(true, 1)
+ def wrongRet1(ctx: NCTokenPredicateContext): String = ""
+ def wrongRet2(ctx: NCTokenPredicateContext): Unit = {}
+ def wrongExec1(ctx: NCTokenPredicateContext): NCTokenPredicateResult = null
+ def wrongExec2(ctx: NCTokenPredicateContext): NCTokenPredicateResult = throw new NullPointerException
+}
+
+/**
+ * Tests for 'custom' functions.
+ */
+class NCIdlFunctionsCustom extends NCIdlFunctions {
+ private final val C = U.cleanClassName(classOf[NCIdlTokensTestWrapper], simpleName = false)
+
+ @Test
+ def testErrors(): Unit = {
+ def test(truth: String*): Unit =
+ for (t ← truth)
+ expectError(TestDesc(truth = t, isCustom = true))
+
+ test(
+ "invalid",
+ s"$C#missed",
+ s"$C#wrongParams1",
+ s"$C#wrongParams2",
+ s"$C#wrongParams3",
+ s"$C#wrongRet1",
+ s"$C#wrongRet2",
+ s"$C#wrongExec1",
+ s"$C#wrongExec2"
+ )
+ }
+
+ @Test
+ def test(): Unit =
+ test(
+ TestDesc(
+ truth = s"$C#trueOn123",
+ isCustom = true,
+ token = Some(tkn(txt = "123")),
+ tokensUsed = Some(1)
+ ),
+ TestDesc(
+ truth = s"$C#trueOn123",
+ isCustom = true,
+ token = Some(tkn(txt = "456")),
+ expectedRes = false,
+ tokensUsed = Some(1)
+ ),
+ TestDesc(
+ // Method defined in model.
+ truth = s"#trueAlwaysCustomToken",
+ isCustom = true,
+ token = Some(tkn(txt = "any"))
+ )
+ )
+}
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsMath.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsMath.scala
index 9596dc2..e921ee8 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsMath.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsMath.scala
@@ -25,15 +25,15 @@ import org.junit.jupiter.api.Test
*/
class NCIdlFunctionsMath extends NCIdlFunctions {
@Test
- def testError(): Unit = {
- // Invalid name.
- expectError("xxx(1, 1)")
- expectError("xxx()")
-
- // Invalid arguments count.
- expectError("atan(1, 1) == 1")
- expectError("pi(1)")
- }
+ def testError(): Unit =
+ expectError(
+ // Invalid name.
+ "xxx(1, 1)",
+ "xxx()",
+ // Invalid arguments count.
+ "atan(1, 1) == 1",
+ "pi(1)"
+ )
@Test
def test(): Unit =
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsOther.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsOther.scala
index 5d1ebc9..de1c718 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsOther.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsOther.scala
@@ -53,10 +53,19 @@ class NCIdlFunctionsOther extends NCIdlFunctions {
}
@Test
- def test3(): Unit = {
+ def test3(): Unit =
test(
- s"to_string(list(1, 2, 3)) == list('1', '2', '3')",
+ "to_string(list(1, 2, 3)) == list('1', '2', '3')",
"to_string(3.123) == '3.123'"
)
- }
+
+ @Test
+ def test4(): Unit =
+ test(
+ "true",
+ "true == true",
+ "false == false",
+ "false != true",
+ "true != false"
+ )
}
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsRequest.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsRequest.scala
index b756389..32daca3 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsRequest.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsRequest.scala
@@ -46,7 +46,7 @@ class NCIdlFunctionsRequest extends NCIdlFunctions {
mkTestDesc(s"req_normtext() == '$reqNormText'"),
mkTestDesc(s"req_tstamp() == $reqTstamp"),
mkTestDesc(s"req_addr() == '$reqAddr'"),
- mkTestDesc(s"req_agent() == '$reqAgent'"),
+ mkTestDesc(s"req_agent() == '$reqAgent'")
)
}
}
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsStat.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsStat.scala
index 4e99c1b..b41b596 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsStat.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsStat.scala
@@ -24,12 +24,13 @@ import org.junit.jupiter.api.Test
*/
class NCIdlFunctionsStat extends NCIdlFunctions {
@Test
- def testError(): Unit = {
- expectError("avg(list()) == 2")
- expectError("avg(list('A')) == 2")
- expectError("stdev(list()) == 2")
- expectError("stdev(list('A')) == 2")
- }
+ def testError(): Unit =
+ expectError(
+ "avg(list()) == 2",
+ "avg(list('A')) == 2",
+ "stdev(list()) == 2",
+ "stdev(list('A')) == 2"
+ )
@Test
def test(): Unit =
@@ -45,6 +46,6 @@ class NCIdlFunctionsStat extends NCIdlFunctions {
"stdev(list(1, 2.2, 3.1)) > 0",
"stdev(list(1, 2, 3)) > 0",
"stdev(list(0.0, 0.0, 0.0)) == 0.0",
- "stdev(list(0, 0, 0)) == 0.0",
+ "stdev(list(0, 0, 0)) == 0.0"
)
}
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsStrings.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsStrings.scala
index 9a33eaf..12e621b 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsStrings.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsStrings.scala
@@ -77,11 +77,12 @@ class NCIdlFunctionsStrings extends NCIdlFunctions {
)
@Test
- def testError(): Unit = {
- expectError("substr('abc', 10, 30) == 'bc'")
- expectError("split('1 A') == true")
- expectError("split_trim('1 A') == true")
- expectError("to_double('1, 1') == true")
- expectError("to_double('A') == true")
- }
+ def testError(): Unit =
+ expectError(
+ "substr('abc', 10, 30) == 'bc'",
+ "split('1 A') == true",
+ "split_trim('1 A') == true",
+ "to_double('1, 1') == true",
+ "to_double('A') == true"
+ )
}
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsToken.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsToken.scala
index f985559..cdf2e49 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsToken.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsToken.scala
@@ -105,8 +105,6 @@ class NCIdlFunctionsToken extends NCIdlFunctions {
truth = "tok_end_idx() == 123",
token = tkn(end = 123)
),
- TestDesc(
- truth = "tok_this() == tok_this()"
- )
+ TestDesc(truth = "tok_this() == tok_this()")
)
}
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsStat.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsTokensUsed.scala
similarity index 50%
copy from nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsStat.scala
copy to nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsTokensUsed.scala
index 4e99c1b..8b62bdd 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsStat.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/functions/NCIdlFunctionsTokensUsed.scala
@@ -20,31 +20,35 @@ package org.apache.nlpcraft.model.intent.idl.compiler.functions
import org.junit.jupiter.api.Test
/**
- * Tests for 'stat' functions.
+ * Tests for 'tokens used' result.
*/
-class NCIdlFunctionsStat extends NCIdlFunctions {
- @Test
- def testError(): Unit = {
- expectError("avg(list()) == 2")
- expectError("avg(list('A')) == 2")
- expectError("stdev(list()) == 2")
- expectError("stdev(list('A')) == 2")
- }
-
+class NCIdlFunctionsTokensUsed extends NCIdlFunctions {
@Test
def test(): Unit =
test(
- "max(list(1, 2, 3)) == 3",
- "max(list(1.0, 2.0, 3.0)) == 3.0",
- "min(list(1, 2, 3)) == 1",
- "min(list(1.0, 2.0, 3.0)) == 1.0",
- "avg(list(1.0, 2.0, 3.0)) == 2.0",
- "avg(list(1, 2, 3)) == 2.0",
- "avg(list(1.2, 2.2, 3.2)) == 2.2",
- "avg(list(1, 2.2, 3.1)) == 2.1",
- "stdev(list(1, 2.2, 3.1)) > 0",
- "stdev(list(1, 2, 3)) > 0",
- "stdev(list(0.0, 0.0, 0.0)) == 0.0",
- "stdev(list(0, 0, 0)) == 0.0",
+ TestDesc(
+ truth = "1 == 1",
+ tokensUsed = Some(0)
+ ),
+ TestDesc(
+ truth = "tok_id() == 'a'",
+ token = Some(tkn(id = "a")),
+ tokensUsed = Some(1)
+ ),
+ TestDesc(
+ truth = "tok_id() == 'a' && tok_id() == 'a'",
+ token = Some(tkn(id = "a")),
+ tokensUsed = Some(2)
+ ),
+ TestDesc(
+ truth = "tok_id() == 'a' && tok_parent() == 'b'",
+ token = Some(tkn(id = "a", parentId = "b")),
+ tokensUsed = Some(2)
+ ),
+ TestDesc(
+ truth = "tok_id() == 'a' && tok_id() == 'a' && tok_parent() == 'b'",
+ token = Some(tkn(id = "a", parentId = "b")),
+ tokensUsed = Some(3)
+ )
)
}
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/test_ok.idl b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/test_ok.idl
index b9ae2df..593a7f5 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/test_ok.idl
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/idl/compiler/test_ok.idl
@@ -55,4 +55,6 @@ intent=i3
json(meta_req('user_json_payload')),
list("موسكو\"", 'v1\'v1', "k2", "v2")
)
- }
\ No newline at end of file
+ }
+
+intent=i4 flow=/#flowModelMethod/ term(t1)=/#termModelMethod/
\ No newline at end of file