diff --git a/Gruntfile.coffee b/Gruntfile.coffee
index ab95146..ca6f7f0 100644
--- a/Gruntfile.coffee
+++ b/Gruntfile.coffee
@@ -74,4 +74,4 @@ module.exports = (grunt) ->
grunt.registerTask "dist", ["coffee", "browserify", "uglify"]
grunt.registerTask "server", ["dist", "connect:server"]
grunt.registerTask "lint", ["coffeelint"]
- grunt.registerTask "test", ["nodeunit"]
+ grunt.registerTask "test", ["coffee", "nodeunit"]
diff --git a/README.md b/README.md
index f09c624..b5a51c0 100644
--- a/README.md
+++ b/README.md
@@ -9,8 +9,13 @@ scripting language for chatterbots, making it easy to write trigger/response
pairs for building up a bot's intelligence.
This library can be used both in a web browser or as a Node module.
-See the `eg/` folder for a web browser example. There's a `node/` folder with
-an example Node TCP server.
+See the `eg/` folder for examples.
+
+## DOCUMENTATION
+
+[Documentation](https://github.com/aichaos/rivescript-js/tree/master/docs) for
+the module's API is available in the `docs/` directory and is browseable in
+Markdown and HTML format.
## INSTALLATION
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..ef0fd2b
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,17 @@
+# RiveScript.js Documentation
+
+This provides documentation for the RiveScript JS module.
+
+You probably want the public facing API: [RiveScript](./rivescript.md)
+
+The rest of the documentation covers internal modules and functions which aren't
+necessarily available over the public API.
+
+* [rivescript.RiveScript](./rivescript.md)
+* [rivescript.Brain](./brain.md)
+* [rivescript.inheritance](./inheritance.md)
+* [rivescript.lang.coffee](./lang.coffee.md)
+* [rivescript.lang.javascript](./lang.javascript.md)
+* [rivescript.Parser](./parser.md)
+* [rivescript.sorting](./sorting.md)
+* [rivescript.utils](./utils.md)
diff --git a/docs/html/rivescript.html b/docs/html/rivescript.html
index bba0e30..afb9bf9 100644
--- a/docs/html/rivescript.html
+++ b/docs/html/rivescript.html
@@ -15,6 +15,7 @@
RiveScript (hash options)
bool strict: Strict mode (default true)
bool utf8: Enable UTF-8 mode (default false)
func onDebug: Set a custom handler to catch debug log messages (default null)
+obj errors: Customize certain error messages (see below)
UTF-8 Mode
In UTF-8 mode, most characters in a user's message are left intact, except for
@@ -27,6 +28,51 @@
UTF-8 Mode
bot.unicodePunctuation = new RegExp(/[.,!?;:]/g);
+Custom Error Messages
+You can provide any or all of the following properties in the errors
+argument to the constructor to override certain internal error messages:
+
+replyNotMatched
: The message returned when the user's message does not
+ match any triggers in your RiveScript code.
+
+The default is "ERR: No Reply Matched"
+Note: the recommended way to handle this case is to provide a trigger of
+ simply *
, which serves as the catch-all trigger and is the default one
+ that will match if nothing else matches the user's message. Example:
++ *
+ - I don't know what to say to that!
+ replyNotFound
: This message is returned when the user did* in fact match
+ a trigger, but no response was found for the user. For example, if a trigger
+ only checks a set of conditions that are all false and provides no "normal"
+ reply, this error message is given to the user instead.
+The default is "ERR: No Reply Found"
+Note: the recommended way to handle this case is to provide at least one
+ normal reply (with the -
command) to every trigger to cover the cases
+ where none of the conditions are true. Example:
++ hello
+ * <get name> != undefined => Hello there, <get name>.
+ - Hi there.
+* objectNotFound
: This message is inserted into the bot's reply in-line when
+ it attempts to call an object macro which does not exist (for example, its
+ name was invalid or it was written in a programming language that the bot
+ couldn't parse, or that it had compile errors).
+The default is "[ERR: Object Not Found]"
+* deepRecursion
: This message is inserted when the bot encounters a deep
+ recursion situation, for example when a reply redirects to a trigger which
+ redirects back to the first trigger, creating an infinite loop.
+The default is "ERR: Deep Recursion Detected"
+These custom error messages can be provided during the construction of the
+RiveScript object, or set afterwards on the object's errors
property.
+Examples:
+var bot = new RiveScript({
+ errors: {
+ replyNotFound: "I don't know how to reply to that."
+ }
+});
+
+bot.errors.objectNotFound = "Something went terribly wrong.";
+
+
Constructor and Debug Methods
string version ()
Returns the version number of the RiveScript.js library.
@@ -68,7 +114,7 @@ int loadFile (string path || array path[, onSuccess[, onError]])
onSuccess
receives: int batchNumber
onError
receives: string errorMessage[, int batchNumber]
void loadDirectory (string path[, func onSuccess[, func onError]])
-Load RiveScript documents from a directory.
+Load RiveScript documents from a directory recursively.
This function is not supported in a web environment.
bool stream (string code[, func onError])
Stream in RiveScript code dynamically. code
should be the raw RiveScript
diff --git a/docs/rivescript.md b/docs/rivescript.md
index ee3d27e..be04163 100644
--- a/docs/rivescript.md
+++ b/docs/rivescript.md
@@ -8,6 +8,7 @@ following keys:
* bool strict: Strict mode (default true)
* bool utf8: Enable UTF-8 mode (default false)
* func onDebug: Set a custom handler to catch debug log messages (default null)
+* obj errors: Customize certain error messages (see below)
## UTF-8 Mode
@@ -24,6 +25,67 @@ var bot = new RiveScript({utf8: true});
bot.unicodePunctuation = new RegExp(/[.,!?;:]/g);
```
+## Custom Error Messages
+
+You can provide any or all of the following properties in the `errors`
+argument to the constructor to override certain internal error messages:
+
+* `replyNotMatched`: The message returned when the user's message does not
+ match any triggers in your RiveScript code.
+
+ The default is "ERR: No Reply Matched"
+
+ **Note:** the recommended way to handle this case is to provide a trigger of
+ simply `*`, which serves as the catch-all trigger and is the default one
+ that will match if nothing else matches the user's message. Example:
+
+ ```
+ + *
+ - I don't know what to say to that!
+ ```
+* `replyNotFound`: This message is returned when the user *did* in fact match
+ a trigger, but no response was found for the user. For example, if a trigger
+ only checks a set of conditions that are all false and provides no "normal"
+ reply, this error message is given to the user instead.
+
+ The default is "ERR: No Reply Found"
+
+ **Note:** the recommended way to handle this case is to provide at least one
+ normal reply (with the `-` command) to every trigger to cover the cases
+ where none of the conditions are true. Example:
+
+ ```
+ + hello
+ * != undefined => Hello there, .
+ - Hi there.
+ ```
+* `objectNotFound`: This message is inserted into the bot's reply in-line when
+ it attempts to call an object macro which does not exist (for example, its
+ name was invalid or it was written in a programming language that the bot
+ couldn't parse, or that it had compile errors).
+
+ The default is "[ERR: Object Not Found]"
+* `deepRecursion`: This message is inserted when the bot encounters a deep
+ recursion situation, for example when a reply redirects to a trigger which
+ redirects back to the first trigger, creating an infinite loop.
+
+ The default is "ERR: Deep Recursion Detected"
+
+These custom error messages can be provided during the construction of the
+RiveScript object, or set afterwards on the object's `errors` property.
+
+Examples:
+
+```javascript
+var bot = new RiveScript({
+ errors: {
+ replyNotFound: "I don't know how to reply to that."
+ }
+});
+
+bot.errors.objectNotFound = "Something went terribly wrong.";
+```
+
# Constructor and Debug Methods
## string version ()
@@ -85,7 +147,7 @@ argument, in case you want to correlate it with your call to `loadFile()`.
## void loadDirectory (string path[, func onSuccess[, func onError]])
-Load RiveScript documents from a directory.
+Load RiveScript documents from a directory recursively.
This function is not supported in a web environment.
diff --git a/src/brain.coffee b/src/brain.coffee
index ee8bf70..fa94708 100644
--- a/src/brain.coffee
+++ b/src/brain.coffee
@@ -110,7 +110,7 @@ class Brain
break
text = utils.strip(match[1])
-
+
# get subroutine name
subroutineNameMatch = (/(\S+)/ig).exec(text)
subroutineName = subroutineNameMatch[0]
@@ -142,7 +142,7 @@ class Brain
else
output = "[ERR: No Object Handler]"
else
- output = "[ERR: Object Not Found]"
+ output = @master.errors.objectNotFound
# if we get a promise back and we are not in the async mode,
# leave an error message to suggest using an async version of rs
@@ -185,7 +185,7 @@ class Brain
doubleQuoteRe = /"/ig
flushBuffer = () ->
- if buff.length isnt 0
+ if buff.length isnt 0
result.push(buff)
buff = ""
@@ -208,7 +208,7 @@ class Brain
# wrap arguments inside in {__call_arg__}{/__call_arg__}
callRegEx = /\s*(.*?)\s*<\/call>/ig
callArgsRegEx = /\s*[^\s]+ (.*)<\/call>/ig
-
+
callSignatures = []
while true
@@ -224,7 +224,7 @@ class Brain
argsMatch = callArgsRegEx.exec(originalCallSignature)
if not argsMatch
break
-
+
originalArgs = argsMatch[1]
args = @_parseCallArgsString(originalArgs)
wrappedArgs = []
@@ -232,12 +232,12 @@ class Brain
for a in args
wrappedArgs.push "{__call_arg__}#{a}{/__call_arg__}"
- wrappedCallSignature = wrappedCallSignature.replace(originalArgs,
+ wrappedCallSignature = wrappedCallSignature.replace(originalArgs,
wrappedArgs.join(' '))
callSignatures.push
original: originalCallSignature
- wrapped: wrappedCallSignature
+ wrapped: wrappedCallSignature
for cs in callSignatures
reply = reply.replace cs.original, cs.wrapped
@@ -277,7 +277,7 @@ class Brain
# Avoid deep recursion.
if step > @master._depth
- return "ERR: Deep Recursion Detected"
+ return @master.errors.deepRecursion
# Are we in the BEGIN block?
if context is "begin"
@@ -506,9 +506,9 @@ class Brain
# Still no reply?
if not foundMatch
- reply = "ERR: No Reply Matched"
+ reply = @master.errors.replyNotMatched
else if reply is undefined or reply.length is 0
- reply = "ERR: No Reply Found"
+ reply = @master.errors.replyNotFound
@say "Reply: #{reply}"
diff --git a/src/lang/coffee.coffee b/src/lang/coffee.coffee
index a41a6f5..ef7b036 100644
--- a/src/lang/coffee.coffee
+++ b/src/lang/coffee.coffee
@@ -48,7 +48,7 @@ class CoffeeObjectHandler
call: (rs, name, fields, scope) ->
# We have it?
if not @_objects[name]
- return "[ERR: Object Not Found]"
+ return @_master.errors.objectNotFound
# Call the dynamic method.
func = @_objects[name]
diff --git a/src/lang/javascript.coffee b/src/lang/javascript.coffee
index a6b2c1e..29bc52e 100644
--- a/src/lang/javascript.coffee
+++ b/src/lang/javascript.coffee
@@ -50,7 +50,7 @@ class JSObjectHandler
call: (rs, name, fields, scope) ->
# We have it?
if not @_objects[name]
- return "[ERR: Object Not Found]"
+ return @_master.errors.objectNotFound
# Call the dynamic method.
func = @_objects[name]
diff --git a/src/rivescript.coffee b/src/rivescript.coffee
index 2b3fdd7..dfded21 100644
--- a/src/rivescript.coffee
+++ b/src/rivescript.coffee
@@ -30,6 +30,7 @@ readDir = require("fs-readdir-recursive")
# * bool strict: Strict mode (default true)
# * bool utf8: Enable UTF-8 mode (default false)
# * func onDebug: Set a custom handler to catch debug log messages (default null)
+# * obj errors: Customize certain error messages (see below)
#
# ## UTF-8 Mode
#
@@ -45,6 +46,68 @@ readDir = require("fs-readdir-recursive")
# var bot = new RiveScript({utf8: true});
# bot.unicodePunctuation = new RegExp(/[.,!?;:]/g);
# ```
+#
+# ## Custom Error Messages
+#
+# You can provide any or all of the following properties in the `errors`
+# argument to the constructor to override certain internal error messages:
+#
+# * `replyNotMatched`: The message returned when the user's message does not
+# match any triggers in your RiveScript code.
+#
+# The default is "ERR: No Reply Matched"
+#
+# **Note:** the recommended way to handle this case is to provide a trigger of
+# simply `*`, which serves as the catch-all trigger and is the default one
+# that will match if nothing else matches the user's message. Example:
+#
+# ```
+# + *
+# - I don't know what to say to that!
+# ```
+# * `replyNotFound`: This message is returned when the user *did* in fact match
+# a trigger, but no response was found for the user. For example, if a trigger
+# only checks a set of conditions that are all false and provides no "normal"
+# reply, this error message is given to the user instead.
+#
+# The default is "ERR: No Reply Found"
+#
+# **Note:** the recommended way to handle this case is to provide at least one
+# normal reply (with the `-` command) to every trigger to cover the cases
+# where none of the conditions are true. Example:
+#
+# ```
+# + hello
+# * != undefined => Hello there, .
+# - Hi there.
+# ```
+# * `objectNotFound`: This message is inserted into the bot's reply in-line when
+# it attempts to call an object macro which does not exist (for example, its
+# name was invalid or it was written in a programming language that the bot
+# couldn't parse, or that it had compile errors).
+#
+# The default is "[ERR: Object Not Found]"
+# * `deepRecursion`: This message is inserted when the bot encounters a deep
+# recursion situation, for example when a reply redirects to a trigger which
+# redirects back to the first trigger, creating an infinite loop.
+#
+# The default is "ERR: Deep Recursion Detected"
+#
+# These custom error messages can be provided during the construction of the
+# RiveScript object, or set afterwards on the object's `errors` property.
+#
+# Examples:
+#
+# ```javascript
+# var bot = new RiveScript({
+# errors: {
+# replyNotFound: "I don't know how to reply to that."
+# }
+# });
+#
+# bot.errors.objectNotFound = "Something went terribly wrong.";
+# ```
+#
##
class RiveScript
@@ -66,6 +129,17 @@ class RiveScript
# UTF-8 punctuation, overridable by the user.
@unicodePunctuation = new RegExp(/[.,!?;:]/g)
+ # Customized error messages.
+ @errors =
+ replyNotMatched: "ERR: No Reply Matched"
+ replyNotFound: "ERR: No Reply Found"
+ objectNotFound: "[ERR: Object Not Found]"
+ deepRecursion: "ERR: Deep Recursion Detected"
+ if typeof(opts.errors) is "object"
+ for key, value of opts.errors
+ if opts.errors.hasOwnProperty(key)
+ @errors[key] = value
+
# Identify our runtime environment. Web, or node?
@_node = {} # NodeJS objects
@_runtime = @runtime()
diff --git a/test/test-begin.coffee b/test/test-begin.coffee
new file mode 100644
index 0000000..7e694ac
--- /dev/null
+++ b/test/test-begin.coffee
@@ -0,0 +1,62 @@
+TestCase = require("./test-base")
+
+################################################################################
+# BEGIN Block Tests
+################################################################################
+
+exports.test_no_begin_block = (test) ->
+ bot = new TestCase(test, """
+ + hello bot
+ - Hello human.
+ """)
+ bot.reply("Hello bot", "Hello human.")
+ test.done()
+
+exports.test_simple_begin_block = (test) ->
+ bot = new TestCase(test, """
+ > begin
+ + request
+ - {ok}
+ < begin
+
+ + hello bot
+ - Hello human.
+ """)
+ bot.reply("Hello bot.", "Hello human.")
+ test.done()
+
+exports.test_blocked_begin_block = (test) ->
+ bot = new TestCase(test, """
+ > begin
+ + request
+ - Nope.
+ < begin
+
+ + hello bot
+ - Hello human.
+ """)
+ bot.reply("Hello bot.", "Nope.")
+ test.done()
+
+exports.test_conditional_begin_block = (test) ->
+ bot = new TestCase(test, """
+ > begin
+ + request
+ * == undefined => {ok}
+ * != undefined => : {ok}
+ - {ok}
+ < begin
+
+ + hello bot
+ - Hello human.
+
+ + my name is *
+ - >Hello, .
+ """)
+ bot.reply("Hello bot.", "Hello human.")
+ bot.uservar("met", "true")
+ bot.uservar("name", "undefined")
+ bot.reply("My name is bob", "Hello, Bob.")
+ bot.uservar("name", "Bob")
+ bot.reply("Hello Bot", "Bob: Hello human.")
+ test.done()
diff --git a/test/test-bot-variables.coffee b/test/test-bot-variables.coffee
new file mode 100644
index 0000000..bcd7b98
--- /dev/null
+++ b/test/test-bot-variables.coffee
@@ -0,0 +1,44 @@
+TestCase = require("./test-base")
+
+################################################################################
+# Bot Variable Tests
+################################################################################
+
+exports.test_bot_variables = (test) ->
+ bot = new TestCase(test, """
+ ! var name = Aiden
+ ! var age = 5
+
+ + what is your name
+ - My name is .
+
+ + how old are you
+ - I am .
+
+ + what are you
+ - I'm .
+
+ + happy birthday
+ - Thanks!
+ """)
+ bot.reply("What is your name?", "My name is Aiden.")
+ bot.reply("How old are you?", "I am 5.")
+ bot.reply("What are you?", "I'm undefined.")
+ bot.reply("Happy birthday!", "Thanks!")
+ bot.reply("How old are you?", "I am 6.")
+ test.done()
+
+exports.test_global_variables = (test) ->
+ bot = new TestCase(test, """
+ ! global debug = false
+
+ + debug mode
+ - Debug mode is:
+
+ + set debug mode *
+ - >Switched to .
+ """)
+ bot.reply("Debug mode.", "Debug mode is: false")
+ bot.reply("Set debug mode true", "Switched to true.")
+ bot.reply("Debug mode?", "Debug mode is: true")
+ test.done()
diff --git a/test/test-math.coffee b/test/test-math.coffee
new file mode 100644
index 0000000..ee21ff8
--- /dev/null
+++ b/test/test-math.coffee
@@ -0,0 +1,44 @@
+TestCase = require("./test-base")
+
+################################################################################
+# calculation (add,sub) tests
+################################################################################
+
+exports.test_addition = (test) ->
+ bot = new TestCase(test, """
+ + test counter
+ - counter set
+
+ + show
+ - counter =
+
+ + add
+ - adding
+
+ + sub
+ - subbing
+
+ + div
+ -
+ ^
+ ^ divving
+
+ + mult
+ -
+ ^
+ ^ multing
+ """)
+ bot.reply("test counter", "counter set")
+ bot.reply("show", "counter = 0")
+ bot.reply("add", "adding")
+ bot.reply("show", "counter = 1")
+ bot.reply("sub", "subbing")
+ bot.reply("show", "counter = 0")
+
+ bot.reply("div", "divving")
+ bot.reply("show", "counter = 5")
+
+ bot.reply("mult", "multing")
+ bot.reply("show", "counter = 20")
+
+ test.done()
diff --git a/test/test-objects.coffee b/test/test-objects.coffee
new file mode 100644
index 0000000..2db315a
--- /dev/null
+++ b/test/test-objects.coffee
@@ -0,0 +1,317 @@
+TestCase = require("./test-base")
+
+################################################################################
+# Object Macro Tests
+################################################################################
+
+exports.test_js_objects = (test) ->
+ bot = new TestCase(test, """
+ > object nolang
+ return "Test w/o language."
+ < object
+
+ > object wlang javascript
+ return "Test w/ language."
+ < object
+
+ > object reverse javascript
+ var msg = args.join(" ");
+ console.log(msg);
+ return msg.split("").reverse().join("");
+ < object
+
+ > object broken javascript
+ return "syntax error
+ < object
+
+ > object foreign perl
+ return "Perl checking in!"
+ < object
+
+ + test nolang
+ - Nolang: nolang
+
+ + test wlang
+ - Wlang: wlang
+
+ + reverse *
+ - reverse
+
+ + test broken
+ - Broken: broken
+
+ + test fake
+ - Fake: fake
+
+ + test perl
+ - Perl: foreign
+ """)
+ bot.reply("Test nolang", "Nolang: Test w/o language.")
+ bot.reply("Test wlang", "Wlang: Test w/ language.")
+ bot.reply("Reverse hello world.", "dlrow olleh")
+ bot.reply("Test broken", "Broken: [ERR: Object Not Found]")
+ bot.reply("Test fake", "Fake: [ERR: Object Not Found]")
+ bot.reply("Test perl", "Perl: [ERR: Object Not Found]")
+ test.done()
+
+exports.test_disabled_js_language = (test) ->
+ bot = new TestCase(test, """
+ > object test javascript
+ return 'JavaScript here!'
+ < object
+
+ + test
+ - Result: test
+ """)
+ bot.reply("test", "Result: JavaScript here!")
+ bot.rs.setHandler("javascript", undefined)
+ bot.reply("test", "Result: [ERR: No Object Handler]")
+ test.done()
+
+exports.test_get_variable = (test) ->
+ bot = new TestCase(test, """
+ ! var test_var = test
+
+ > object test_get_var javascript
+ var uid = rs.currentUser();
+ var name = "test_var";
+ return rs.getVariable(uid, name);
+ < object
+
+ + show me var
+ - test_get_var
+ """)
+ bot.reply("show me var", "test")
+ test.done()
+
+exports.test_js_string_in_setSubroutine = (test) ->
+ bot = new TestCase(test, """
+ + hello
+ - hello helper
+ """)
+
+ input = "hello there"
+
+ bot.rs.setSubroutine("helper", ["return 'person';"])
+ bot.reply("hello", "hello person")
+ test.done()
+
+exports.test_function_in_setSubroutine = (test) ->
+ bot = new TestCase(test, """
+ + my name is *
+ - hello personhelper
+ """)
+
+ input = "my name is Rive"
+
+ bot.rs.setSubroutine("helper", (rs, args) ->
+ test.equal(rs, bot.rs)
+ test.equal(args.length, 1)
+ test.equal(args[0], "rive")
+ test.done()
+ )
+
+ bot.reply(input, "hello person")
+
+exports.test_function_in_setSubroutine_return_value = (test) ->
+ bot = new TestCase(test, """
+ + hello
+ - hello helper
+ """)
+
+ bot.rs.setSubroutine("helper", (rs, args) ->
+ "person"
+ )
+
+ bot.reply("hello", "hello person")
+ test.done()
+
+exports.test_arguments_in_setSubroutine = (test) ->
+ bot = new TestCase(test, """
+ + my name is *
+ - hello helper 12
+ """)
+
+ bot.rs.setSubroutine("helper", (rs, args) ->
+ test.equal(args.length, 2)
+ test.equal(args[0], "thomas edison")
+ test.equal(args[1], "12")
+ args[0]
+ )
+
+ bot.reply("my name is thomas edison", "hello thomas edison")
+ test.done()
+
+exports.test_quoted_strings_arguments_in_setSubroutine = (test) ->
+ bot = new TestCase(test, """
+ + my name is *
+ - hello helper 12 "another param"
+ """)
+
+ bot.rs.setSubroutine("helper", (rs, args) ->
+ test.equal(args.length, 3)
+ test.equal(args[0], "thomas edison")
+ test.equal(args[1], "12")
+ test.equal(args[2], "another param")
+ args[0]
+ )
+
+ bot.reply("my name is thomas edison", "hello thomas edison")
+ test.done()
+
+exports.test_arguments_with_funky_spacing_in_setSubroutine = (test) ->
+ bot = new TestCase(test, """
+ + my name is *
+ - hello helper 12 "another param"
+ """)
+
+ bot.rs.setSubroutine("helper", (rs, args) ->
+ test.equal(args.length, 3)
+ test.equal(args[0], "thomas edison")
+ test.equal(args[1], "12")
+ test.equal(args[2], "another param")
+ args[0]
+ )
+
+ bot.reply("my name is thomas edison", "hello thomas edison")
+ test.done()
+
+exports.test_promises_in_objects = (test) ->
+ bot = new TestCase(test, """
+ + my name is *
+ - hello there helperWithPromise with a anotherHelperWithPromise
+ """)
+
+ input = "my name is Rive"
+
+ bot.rs.setSubroutine("helperWithPromise", (rs, args) ->
+ return new rs.Promise((resolve, reject) ->
+ resolve("stranger")
+ )
+ )
+
+ bot.rs.setSubroutine("anotherHelperWithPromise", (rs) ->
+ return new rs.Promise((resolve, reject) ->
+ setTimeout () ->
+ resolve("delay")
+ , 1000
+ )
+ )
+
+ bot.rs.replyAsync(bot.username, input).then (reply) ->
+ test.equal(reply, "hello there stranger with a delay")
+ test.done()
+
+exports.test_replyAsync_supports_callbacks = (test) ->
+ bot = new TestCase(test, """
+ + my name is *
+ - hello there asyncHelper
+ """)
+
+ input = "my name is Rive"
+
+ bot.rs.setSubroutine("asyncHelper", (rs, args) ->
+ return new rs.Promise((resolve, reject) ->
+ resolve("stranger")
+ )
+ )
+
+ bot.rs.replyAsync(bot.username, input, null, (error, reply) ->
+ test.ok(!error)
+ test.equal(reply, "hello there stranger")
+ test.done()
+ )
+
+exports.test_use_reply_with_async_subroutines = (test) ->
+ bot = new TestCase(test, """
+ + my name is *
+ - hello there asyncHelper
+ """)
+
+ bot.rs.setSubroutine("asyncHelper", (rs, args) ->
+ return new rs.Promise((resolve, reject) ->
+ resolve("stranger")
+ )
+ )
+
+ bot.reply("my name is Rive", "hello there [ERR: Using async routine with reply: use replyAsync instead]")
+ test.done()
+
+exports.test_errors_in_async_subroutines_with_callbacks = (test) ->
+ bot = new TestCase(test, """
+ + my name is *
+ - hello there asyncHelper
+ """)
+
+ errorMessage = "Something went terribly wrong"
+
+ bot.rs.setSubroutine("asyncHelper", (rs, args) ->
+ return new rs.Promise((resolve, reject) ->
+ reject(new Error(errorMessage))
+ )
+ )
+
+ bot.rs.replyAsync(bot.username, "my name is Rive", null, (error, reply) ->
+ test.ok(error)
+ test.equal(error.message, errorMessage)
+ test.ok(!reply)
+ test.done()
+ )
+
+exports.test_errors_in_async_subroutines_with_promises = (test) ->
+ bot = new TestCase(test, """
+ + my name is *
+ - hello there asyncHelper
+ """)
+
+ errorMessage = "Something went terribly wrong"
+
+ bot.rs.setSubroutine("asyncHelper", (rs, args) ->
+ return new rs.Promise((resolve, reject) ->
+ reject(new Error(errorMessage))
+ )
+ )
+
+ bot.rs.replyAsync(bot.username, "my name is Rive").catch (error) ->
+ test.ok(error)
+ test.equal(error.message, errorMessage)
+ test.done()
+
+exports.test_async_and_sync_subroutines_together = (test) ->
+ bot = new TestCase(test, """
+ + my name is *
+ - hello there asyncHelperexclaim
+ """)
+
+
+ bot.rs.setSubroutine("exclaim", (rs, args) ->
+ return "!"
+ )
+
+ bot.rs.setSubroutine("asyncHelper", (rs, args) ->
+ return new rs.Promise((resolve, reject) ->
+ resolve("stranger")
+ )
+ )
+
+ bot.rs.replyAsync(bot.username, "my name is Rive").then (reply) ->
+ test.equal(reply, "hello there stranger!")
+ test.done()
+
+exports.test_stringify_with_objects = (test) ->
+ bot = new TestCase(test, """
+ > object hello javascript
+ return \"Hello\";
+ < object
+ + my name is *
+ - hello thereexclaim
+ """)
+
+ bot.rs.setSubroutine("exclaim", (rs) ->
+ return "!"
+ )
+
+ src = bot.rs.stringify()
+ expect = '! version = 2.0\n! local concat = none\n\n> object hello javascript\n\treturn "Hello";\n< object\n\n> object exclaim javascript\n\treturn "!";\n< object\n\n+ my name is *\n- hello thereexclaim\n'
+ test.equal(src, expect)
+ test.done()
diff --git a/test/test-options.coffee b/test/test-options.coffee
new file mode 100644
index 0000000..92d68d4
--- /dev/null
+++ b/test/test-options.coffee
@@ -0,0 +1,120 @@
+TestCase = require("./test-base")
+
+################################################################################
+# Parser option tests
+################################################################################
+
+exports.test_concat = (test) ->
+ bot = new TestCase(test, """
+ // Default concat mode = none
+ + test concat default
+ - Hello
+ ^ world!
+
+ ! local concat = space
+ + test concat space
+ - Hello
+ ^ world!
+
+ ! local concat = none
+ + test concat none
+ - Hello
+ ^ world!
+
+ ! local concat = newline
+ + test concat newline
+ - Hello
+ ^ world!
+
+ // invalid concat setting is equivalent to 'none'
+ ! local concat = foobar
+ + test concat foobar
+ - Hello
+ ^ world!
+
+ // the option is file scoped so it can be left at
+ // any setting and won't affect subsequent parses
+ ! local concat = newline
+ """)
+ bot.extend("""
+ // concat mode should be restored to the default in a
+ // separate file/stream parse
+ + test concat second file
+ - Hello
+ ^ world!
+ """)
+
+ bot.reply("test concat default", "Helloworld!")
+ bot.reply("test concat space", "Hello world!")
+ bot.reply("test concat none", "Helloworld!")
+ bot.reply("test concat newline", "Hello\nworld!")
+ bot.reply("test concat foobar", "Helloworld!")
+ bot.reply("test concat second file", "Helloworld!")
+
+ test.done()
+
+exports.test_concat_with_conditionals = (test) ->
+ # Newline
+ bot = new TestCase(test, """
+ ! local concat = newline
+
+ + test *
+ * == a => First A line
+ ^ Second A line
+ ^ Third A line
+ - First B line
+ ^ Second B line
+ ^ Third B line
+ """)
+
+ bot.reply("test a", "First A line\nSecond A line\nThird A line")
+ bot.reply("test b", "First B line\nSecond B line\nThird B line")
+
+ # Space
+ bot = new TestCase(test, """
+ ! local concat = space
+
+ + test *
+ * == a => First A line
+ ^ Second A line
+ ^ Third A line
+ - First B line
+ ^ Second B line
+ ^ Third B line
+ """)
+
+ bot.reply("test a", "First A line Second A line Third A line")
+ bot.reply("test b", "First B line Second B line Third B line")
+
+ # No concat
+ bot = new TestCase(test, """
+ + test *
+ * == a => First A line
+ ^ Second A line
+ ^ Third A line
+ - First B line
+ ^ Second B line
+ ^ Third B line
+ """)
+
+ bot.reply("test a", "First A lineSecond A lineThird A line")
+ bot.reply("test b", "First B lineSecond B lineThird B line")
+
+ test.done()
+
+exports.test_concat_space_with_conditionals = (test) ->
+ bot = new TestCase(test, """
+ ! local concat = newline
+
+ + test *
+ * == a => First A line
+ ^ Second A line
+ ^ Third A line
+ - First B line
+ ^ Second B line
+ ^ Third B line
+ """)
+
+ bot.reply("test a", "First A line\nSecond A line\nThird A line")
+ bot.reply("test b", "First B line\nSecond B line\nThird B line")
+ test.done()
diff --git a/test/test-replies.coffee b/test/test-replies.coffee
new file mode 100644
index 0000000..02f1ed0
--- /dev/null
+++ b/test/test-replies.coffee
@@ -0,0 +1,207 @@
+TestCase = require("./test-base")
+
+################################################################################
+# Reply Tests
+################################################################################
+
+exports.test_previous = (test) ->
+ bot = new TestCase(test, """
+ ! sub who's = who is
+ ! sub it's = it is
+ ! sub didn't = did not
+
+ + knock knock
+ - Who's there?
+
+ + *
+ % who is there
+ - who?
+
+ + *
+ % * who
+ - Haha! !
+
+ + *
+ - I don't know.
+ """)
+ bot.reply("knock knock", "Who's there?")
+ bot.reply("Canoe", "Canoe who?")
+ bot.reply("Canoe help me with my homework?", "Haha! Canoe help me with my homework!")
+ bot.reply("hello", "I don't know.")
+ test.done()
+
+exports.test_random = (test) ->
+ bot = new TestCase(test, """
+ + test random response
+ - One.
+ - Two.
+
+ + test random tag
+ - This sentence has a random {random}word|bit{/random}.
+ """)
+ bot.replyRandom("test random response", ["One.", "Two."])
+ bot.replyRandom("test random tag", [
+ "This sentence has a random word.",
+ "This sentence has a random bit.",
+ ])
+ test.done()
+
+exports.test_continuations = (test) ->
+ bot = new TestCase(test, """
+ + tell me a poem
+ - There once was a man named Tim,\\s
+ ^ who never quite learned how to swim.\\s
+ ^ He fell off a dock, and sank like a rock,\\s
+ ^ and that was the end of him.
+ """)
+ bot.reply("Tell me a poem.", "There once was a man named Tim,
+ who never quite learned how to swim.
+ He fell off a dock, and sank like a rock,
+ and that was the end of him.")
+ test.done()
+
+exports.test_redirects = (test) ->
+ bot = new TestCase(test, """
+ + hello
+ - Hi there!
+
+ + hey
+ @ hello
+
+ + hi there
+ - {@hello}
+ """)
+ bot.reply("hello", "Hi there!")
+ bot.reply("hey", "Hi there!")
+ bot.reply("hi there", "Hi there!")
+ test.done()
+
+exports.test_conditionals = (test) ->
+ bot = new TestCase(test, """
+ + i am # years old
+ - >OK.
+
+ + what can i do
+ * == undefined => I don't know.
+ * > 25 => Anything you want.
+ * == 25 => Rent a car for cheap.
+ * >= 21 => Drink.
+ * >= 18 => Vote.
+ * < 18 => Not much of anything.
+
+ + am i your master
+ * == true => Yes.
+ - No.
+ """)
+ age_q = "What can I do?"
+ bot.reply(age_q, "I don't know.")
+
+ ages =
+ '16' : "Not much of anything."
+ '18' : "Vote."
+ '20' : "Vote."
+ '22' : "Drink."
+ '24' : "Drink."
+ '25' : "Rent a car for cheap."
+ '27' : "Anything you want."
+ for age of ages
+ if (!ages.hasOwnProperty(age))
+ continue
+ bot.reply("I am " + age + " years old.", "OK.")
+ bot.reply(age_q, ages[age])
+
+ bot.reply("Am I your master?", "No.")
+ bot.rs.setUservar(bot.username, "master", "true")
+ bot.reply("Am I your master?", "Yes.")
+ test.done()
+
+exports.test_embedded_tags = (test) ->
+ bot = new TestCase(test, """
+ + my name is *
+ * != undefined => >I thought\\s
+ ^ your name was ?
+ ^ >
+ - >OK.
+
+ + what is my name
+ - Your name is , right?
+
+ + html test
+ - Name>This has some non-RS tags in it.
+ """)
+ bot.reply("What is my name?", "Your name is undefined, right?")
+ bot.reply("My name is Alice.", "OK.")
+ bot.reply("My name is Bob.", "I thought your name was Alice?")
+ bot.reply("What is my name?", "Your name is Bob, right?")
+ bot.reply("HTML Test", "This has some non-RS tags in it.")
+ test.done()
+
+exports.test_set_uservars = (test) ->
+ bot = new TestCase(test, """
+ + what is my name
+ - Your name is .
+
+ + how old am i
+ - You are .
+ """)
+ bot.rs.setUservars(bot.username, {
+ "name": "Aiden",
+ "age": 5,
+ })
+ bot.reply("What is my name?", "Your name is Aiden.")
+ bot.reply("How old am I?", "You are 5.")
+ test.done()
+
+exports.test_questionmark = (test) ->
+ bot = new TestCase(test, """
+ + google *
+ - Results are here
+ """)
+ bot.reply("google coffeescript",
+ 'Results are here'
+ )
+ test.done()
+
+exports.test_reply_arrays = (test) ->
+ bot = new TestCase(test, """
+ ! array greek = alpha beta gamma
+ ! array test = testing trying
+ ! array format = |||
+
+ + test random array
+ - Testing (@greek) array.
+
+ + test two random arrays
+ - {formal}(@test){/formal} another (@greek) array.
+
+ + test nonexistant array
+ - This (@array) does not exist.
+
+ + test more arrays
+ - I'm (@test) more (@greek) (@arrays).
+
+ + test weird syntax
+ - This (@ greek) shouldn't work, and neither should this @test.
+
+ + random format *
+ - (@format)
+ """)
+ bot.replyRandom("test random array", [
+ "Testing alpha array.", "Testing beta array.", "Testing gamma array.",
+ ])
+ bot.replyRandom("test two random arrays", [
+ "Testing another alpha array.", "Testing another beta array.",
+ "Testing another gamma array.", "Trying another alpha array.",
+ "Trying another beta array.", "Trying another gamma array.",
+ ])
+ bot.reply("test nonexistant array", "This (@array) does not exist.")
+ bot.replyRandom("test more arrays", [
+ "I'm testing more alpha (@arrays).", "I'm testing more beta (@arrays).",
+ "I'm testing more gamma (@arrays).", "I'm trying more alpha (@arrays).",
+ "I'm trying more beta (@arrays).", "I'm trying more gamma (@arrays)."
+ ])
+ bot.reply("test weird syntax", "This (@ greek) shouldn't work, and neither should this @test.")
+ bot.replyRandom("random format hello world", [
+ "HELLO WORLD", "hello world", "Hello World", "Hello world",
+ ])
+ test.done()
diff --git a/test/test-rivescript.coffee b/test/test-rivescript.coffee
index 7202519..12659b0 100644
--- a/test/test-rivescript.coffee
+++ b/test/test-rivescript.coffee
@@ -1,1093 +1,10 @@
TestCase = require("./test-base")
################################################################################
-# BEGIN Block Tests
+# RiveScript API Tests
################################################################################
-exports.test_no_begin_block = (test) ->
- bot = new TestCase(test, """
- + hello bot
- - Hello human.
- """)
- bot.reply("Hello bot", "Hello human.")
- test.done()
-
-exports.test_simple_begin_block = (test) ->
- bot = new TestCase(test, """
- > begin
- + request
- - {ok}
- < begin
-
- + hello bot
- - Hello human.
- """)
- bot.reply("Hello bot.", "Hello human.")
- test.done()
-
-exports.test_blocked_begin_block = (test) ->
- bot = new TestCase(test, """
- > begin
- + request
- - Nope.
- < begin
-
- + hello bot
- - Hello human.
- """)
- bot.reply("Hello bot.", "Nope.")
- test.done()
-
-exports.test_conditional_begin_block = (test) ->
- bot = new TestCase(test, """
- > begin
- + request
- * == undefined => {ok}
- * != undefined => : {ok}
- - {ok}
- < begin
-
- + hello bot
- - Hello human.
-
- + my name is *
- - >Hello, .
- """)
- bot.reply("Hello bot.", "Hello human.")
- bot.uservar("met", "true")
- bot.uservar("name", "undefined")
- bot.reply("My name is bob", "Hello, Bob.")
- bot.uservar("name", "Bob")
- bot.reply("Hello Bot", "Bob: Hello human.")
- test.done()
-
-################################################################################
-# Bot Variable Tests
-################################################################################
-
-exports.test_bot_variables = (test) ->
- bot = new TestCase(test, """
- ! var name = Aiden
- ! var age = 5
-
- + what is your name
- - My name is .
-
- + how old are you
- - I am .
-
- + what are you
- - I'm .
-
- + happy birthday
- - Thanks!
- """)
- bot.reply("What is your name?", "My name is Aiden.")
- bot.reply("How old are you?", "I am 5.")
- bot.reply("What are you?", "I'm undefined.")
- bot.reply("Happy birthday!", "Thanks!")
- bot.reply("How old are you?", "I am 6.")
- test.done()
-
-exports.test_global_variables = (test) ->
- bot = new TestCase(test, """
- ! global debug = false
-
- + debug mode
- - Debug mode is:
-
- + set debug mode *
- - >Switched to .
- """)
- bot.reply("Debug mode.", "Debug mode is: false")
- bot.reply("Set debug mode true", "Switched to true.")
- bot.reply("Debug mode?", "Debug mode is: true")
- test.done()
-
-################################################################################
-# Substitution Tests
-################################################################################
-
-exports.test_substitutions = (test) ->
- bot = new TestCase(test, """
- + whats up
- - nm.
-
- + what is up
- - Not much.
- """)
- bot.reply("whats up", "nm.")
- bot.reply("what's up?", "nm.")
- bot.reply("what is up?", "Not much.")
-
- bot.extend("""
- ! sub whats = what is
- ! sub what's = what is
- """)
- bot.reply("whats up", "Not much.")
- bot.reply("what's up?", "Not much.")
- bot.reply("What is up?", "Not much.")
- test.done()
-
-exports.test_person_substitutions = (test) ->
- bot = new TestCase(test, """
- + say *
- -
- """)
- bot.reply("say I am cool", "i am cool")
- bot.reply("say You are dumb", "you are dumb")
-
- bot.extend("""
- ! person i am = you are
- ! person you are = I am
- """)
- bot.reply("say I am cool", "you are cool")
- bot.reply("say You are dumb", "I am dumb")
- test.done()
-
-################################################################################
-# Trigger Tests
-################################################################################
-
-exports.test_atomic_triggers = (test) ->
- bot = new TestCase(test, """
- + hello bot
- - Hello human.
-
- + what are you
- - I am a RiveScript bot.
- """)
- bot.reply("Hello bot", "Hello human.")
- bot.reply("What are you?", "I am a RiveScript bot.")
- test.done()
-
-exports.test_wildcard_triggers = (test) ->
- bot = new TestCase(test, """
- + my name is *
- - Nice to meet you, .
-
- + * told me to say *
- - Why did tell you to say ?
-
- + i am # years old
- - A lot of people are .
-
- + i am _ years old
- - Say that with numbers.
-
- + i am * years old
- - Say that with fewer words.
- """)
- bot.reply("my name is Bob", "Nice to meet you, bob.")
- bot.reply("bob told me to say hi", "Why did bob tell you to say hi?")
- bot.reply("i am 5 years old", "A lot of people are 5.")
- bot.reply("i am five years old", "Say that with numbers.")
- bot.reply("i am twenty five years old", "Say that with fewer words.")
- test.done()
-
-exports.test_alternatives_and_optionals = (test) ->
- bot = new TestCase(test, """
- + what (are|is) you
- - I am a robot.
-
- + what is your (home|office|cell) [phone] number
- - It is 555-1234.
-
- + [please|can you] ask me a question
- - Why is the sky blue?
-
- + (aa|bb|cc) [bogus]
- - Matched.
-
- + (yo|hi) [computer|bot] *
- - Matched.
- """)
- bot.reply("What are you?", "I am a robot.")
- bot.reply("What is you?", "I am a robot.")
-
- bot.reply("What is your home phone number?", "It is 555-1234.")
- bot.reply("What is your home number?", "It is 555-1234.")
- bot.reply("What is your cell phone number?", "It is 555-1234.")
- bot.reply("What is your office number?", "It is 555-1234.")
-
- bot.reply("Can you ask me a question?", "Why is the sky blue?")
- bot.reply("Please ask me a question?", "Why is the sky blue?")
- bot.reply("Ask me a question.", "Why is the sky blue?")
-
- bot.reply("aa", "Matched.")
- bot.reply("bb", "Matched.")
- bot.reply("aa bogus", "Matched.")
- bot.reply("aabogus", "ERR: No Reply Matched")
- bot.reply("bogus", "ERR: No Reply Matched")
-
- bot.reply("hi Aiden", "Matched.")
- bot.reply("hi bot how are you?", "Matched.")
- bot.reply("yo computer what time is it?", "Matched.")
- bot.reply("yoghurt is yummy", "ERR: No Reply Matched")
- bot.reply("hide and seek is fun", "ERR: No Reply Matched")
- bot.reply("hip hip hurrah", "ERR: No Reply Matched")
- test.done()
-
-exports.test_trigger_arrays = (test) ->
- bot = new TestCase(test, """
- ! array colors = red blue green yellow white
- ^ dark blue|light blue
-
- + what color is my (@colors) *
- - Your is .
-
- + what color was * (@colors) *
- - It was .
-
- + i have a @colors *
- - Tell me more about your .
- """)
- bot.reply("What color is my red shirt?", "Your shirt is red.")
- bot.reply("What color is my blue car?", "Your car is blue.")
- bot.reply("What color is my pink house?", "ERR: No Reply Matched")
- bot.reply("What color is my dark blue jacket?", "Your jacket is dark blue.")
- bot.reply("What color was Napoleoan's white horse?", "It was white.")
- bot.reply("What color was my red shirt?", "It was red.")
- bot.reply("I have a blue car.", "Tell me more about your car.")
- bot.reply("I have a cyan car.", "ERR: No Reply Matched")
- test.done()
-
-exports.test_weighted_triggers = (test) ->
- bot = new TestCase(test, """
- + * or something{weight=10}
- - Or something. <@>
-
- + can you run a google search for *
- - Sure!
-
- + hello *{weight=20}
- - Hi there!
- """)
- bot.reply("Hello robot.", "Hi there!")
- bot.reply("Hello or something.", "Hi there!")
- bot.reply("Can you run a Google search for Node", "Sure!")
- bot.reply("Can you run a Google search for Node or something", "Or something. Sure!")
- test.done()
-
-################################################################################
-# Reply Tests
-################################################################################
-
-exports.test_previous = (test) ->
- bot = new TestCase(test, """
- ! sub who's = who is
- ! sub it's = it is
- ! sub didn't = did not
-
- + knock knock
- - Who's there?
-
- + *
- % who is there
- - who?
-
- + *
- % * who
- - Haha! !
-
- + *
- - I don't know.
- """)
- bot.reply("knock knock", "Who's there?")
- bot.reply("Canoe", "Canoe who?")
- bot.reply("Canoe help me with my homework?", "Haha! Canoe help me with my homework!")
- bot.reply("hello", "I don't know.")
- test.done()
-
-exports.test_random = (test) ->
- bot = new TestCase(test, """
- + test random response
- - One.
- - Two.
-
- + test random tag
- - This sentence has a random {random}word|bit{/random}.
- """)
- bot.replyRandom("test random response", ["One.", "Two."])
- bot.replyRandom("test random tag", [
- "This sentence has a random word.",
- "This sentence has a random bit.",
- ])
- test.done()
-
-exports.test_continuations = (test) ->
- bot = new TestCase(test, """
- + tell me a poem
- - There once was a man named Tim,\\s
- ^ who never quite learned how to swim.\\s
- ^ He fell off a dock, and sank like a rock,\\s
- ^ and that was the end of him.
- """)
- bot.reply("Tell me a poem.", "There once was a man named Tim,
- who never quite learned how to swim.
- He fell off a dock, and sank like a rock,
- and that was the end of him.")
- test.done()
-
-exports.test_redirects = (test) ->
- bot = new TestCase(test, """
- + hello
- - Hi there!
-
- + hey
- @ hello
-
- + hi there
- - {@hello}
- """)
- bot.reply("hello", "Hi there!")
- bot.reply("hey", "Hi there!")
- bot.reply("hi there", "Hi there!")
- test.done()
-
-exports.test_conditionals = (test) ->
- bot = new TestCase(test, """
- + i am # years old
- - >OK.
-
- + what can i do
- * == undefined => I don't know.
- * > 25 => Anything you want.
- * == 25 => Rent a car for cheap.
- * >= 21 => Drink.
- * >= 18 => Vote.
- * < 18 => Not much of anything.
-
- + am i your master
- * == true => Yes.
- - No.
- """)
- age_q = "What can I do?"
- bot.reply(age_q, "I don't know.")
-
- ages =
- '16' : "Not much of anything."
- '18' : "Vote."
- '20' : "Vote."
- '22' : "Drink."
- '24' : "Drink."
- '25' : "Rent a car for cheap."
- '27' : "Anything you want."
- for age of ages
- if (!ages.hasOwnProperty(age))
- continue
- bot.reply("I am " + age + " years old.", "OK.")
- bot.reply(age_q, ages[age])
-
- bot.reply("Am I your master?", "No.")
- bot.rs.setUservar(bot.username, "master", "true")
- bot.reply("Am I your master?", "Yes.")
- test.done()
-
-exports.test_embedded_tags = (test) ->
- bot = new TestCase(test, """
- + my name is *
- * != undefined => >I thought\\s
- ^ your name was ?
- ^ >
- - >OK.
-
- + what is my name
- - Your name is , right?
-
- + html test
- - Name>This has some non-RS tags in it.
- """)
- bot.reply("What is my name?", "Your name is undefined, right?")
- bot.reply("My name is Alice.", "OK.")
- bot.reply("My name is Bob.", "I thought your name was Alice?")
- bot.reply("What is my name?", "Your name is Bob, right?")
- bot.reply("HTML Test", "This has some non-RS tags in it.")
- test.done()
-
-exports.test_set_uservars = (test) ->
- bot = new TestCase(test, """
- + what is my name
- - Your name is .
-
- + how old am i
- - You are .
- """)
- bot.rs.setUservars(bot.username, {
- "name": "Aiden",
- "age": 5,
- })
- bot.reply("What is my name?", "Your name is Aiden.")
- bot.reply("How old am I?", "You are 5.")
- test.done()
-
-exports.test_questionmark = (test) ->
- bot = new TestCase(test, """
- + google *
- - Results are here
- """)
- bot.reply("google coffeescript",
- 'Results are here'
- )
- test.done()
-
-exports.test_reply_arrays = (test) ->
- bot = new TestCase(test, """
- ! array greek = alpha beta gamma
- ! array test = testing trying
- ! array format = |||
-
- + test random array
- - Testing (@greek) array.
-
- + test two random arrays
- - {formal}(@test){/formal} another (@greek) array.
-
- + test nonexistant array
- - This (@array) does not exist.
-
- + test more arrays
- - I'm (@test) more (@greek) (@arrays).
-
- + test weird syntax
- - This (@ greek) shouldn't work, and neither should this @test.
-
- + random format *
- - (@format)
- """)
- bot.replyRandom("test random array", [
- "Testing alpha array.", "Testing beta array.", "Testing gamma array.",
- ])
- bot.replyRandom("test two random arrays", [
- "Testing another alpha array.", "Testing another beta array.",
- "Testing another gamma array.", "Trying another alpha array.",
- "Trying another beta array.", "Trying another gamma array.",
- ])
- bot.reply("test nonexistant array", "This (@array) does not exist.")
- bot.replyRandom("test more arrays", [
- "I'm testing more alpha (@arrays).", "I'm testing more beta (@arrays).",
- "I'm testing more gamma (@arrays).", "I'm trying more alpha (@arrays).",
- "I'm trying more beta (@arrays).", "I'm trying more gamma (@arrays)."
- ])
- bot.reply("test weird syntax", "This (@ greek) shouldn't work, and neither should this @test.")
- bot.replyRandom("random format hello world", [
- "HELLO WORLD", "hello world", "Hello World", "Hello world",
- ])
- test.done()
-
-################################################################################
-# Object Macro Tests
-################################################################################
-
-exports.test_js_objects = (test) ->
- bot = new TestCase(test, """
- > object nolang
- return "Test w/o language."
- < object
-
- > object wlang javascript
- return "Test w/ language."
- < object
-
- > object reverse javascript
- var msg = args.join(" ");
- console.log(msg);
- return msg.split("").reverse().join("");
- < object
-
- > object broken javascript
- return "syntax error
- < object
-
- > object foreign perl
- return "Perl checking in!"
- < object
-
- + test nolang
- - Nolang: nolang
-
- + test wlang
- - Wlang: wlang
-
- + reverse *
- - reverse
-
- + test broken
- - Broken: broken
-
- + test fake
- - Fake: fake
-
- + test perl
- - Perl: foreign
- """)
- bot.reply("Test nolang", "Nolang: Test w/o language.")
- bot.reply("Test wlang", "Wlang: Test w/ language.")
- bot.reply("Reverse hello world.", "dlrow olleh")
- bot.reply("Test broken", "Broken: [ERR: Object Not Found]")
- bot.reply("Test fake", "Fake: [ERR: Object Not Found]")
- bot.reply("Test perl", "Perl: [ERR: Object Not Found]")
- test.done()
-
-exports.test_disabled_js_language = (test) ->
- bot = new TestCase(test, """
- > object test javascript
- return 'JavaScript here!'
- < object
-
- + test
- - Result: test
- """)
- bot.reply("test", "Result: JavaScript here!")
- bot.rs.setHandler("javascript", undefined)
- bot.reply("test", "Result: [ERR: No Object Handler]")
- test.done()
-
-exports.test_get_variable = (test) ->
- bot = new TestCase(test, """
- ! var test_var = test
-
- > object test_get_var javascript
- var uid = rs.currentUser();
- var name = "test_var";
- return rs.getVariable(uid, name);
- < object
-
- + show me var
- - test_get_var
- """)
- bot.reply("show me var", "test")
- test.done()
-
-
-################################################################################
-# Topic Tests
-################################################################################
-
-exports.test_punishment_topic = (test) ->
- bot = new TestCase(test, """
- + hello
- - Hi there!
-
- + swear word
- - How rude! Apologize or I won't talk to you again.{topic=sorry}
-
- + *
- - Catch-all.
-
- > topic sorry
- + sorry
- - It's ok!{topic=random}
-
- + *
- - Say you're sorry!
- < topic
- """)
- bot.reply("hello", "Hi there!")
- bot.reply("How are you?", "Catch-all.")
- bot.reply("Swear word!", "How rude! Apologize or I won't talk to you again.")
- bot.reply("hello", "Say you're sorry!")
- bot.reply("How are you?", "Say you're sorry!")
- bot.reply("Sorry!", "It's ok!")
- bot.reply("hello", "Hi there!")
- bot.reply("How are you?", "Catch-all.")
- test.done()
-
-exports.test_topic_inheritance = (test) ->
- RS_ERR_MATCH = "ERR: No Reply Matched"
- bot = new TestCase(test, """
- > topic colors
- + what color is the sky
- - Blue.
-
- + what color is the sun
- - Yellow.
- < topic
-
- > topic linux
- + name a red hat distro
- - Fedora.
-
- + name a debian distro
- - Ubuntu.
- < topic
-
- > topic stuff includes colors linux
- + say stuff
- - \"Stuff.\"
- < topic
-
- > topic override inherits colors
- + what color is the sun
- - Purple.
- < topic
-
- > topic morecolors includes colors
- + what color is grass
- - Green.
- < topic
-
- > topic evenmore inherits morecolors
- + what color is grass
- - Blue, sometimes.
- < topic
- """)
- bot.rs.setUservar(bot.username, "topic", "colors")
- bot.reply("What color is the sky?", "Blue.")
- bot.reply("What color is the sun?", "Yellow.")
- bot.reply("What color is grass?", RS_ERR_MATCH)
- bot.reply("Name a Red Hat distro.", RS_ERR_MATCH)
- bot.reply("Name a Debian distro.", RS_ERR_MATCH)
- bot.reply("Say stuff.", RS_ERR_MATCH)
-
- bot.rs.setUservar(bot.username, "topic", "linux")
- bot.reply("What color is the sky?", RS_ERR_MATCH)
- bot.reply("What color is the sun?", RS_ERR_MATCH)
- bot.reply("What color is grass?", RS_ERR_MATCH)
- bot.reply("Name a Red Hat distro.", "Fedora.")
- bot.reply("Name a Debian distro.", "Ubuntu.")
- bot.reply("Say stuff.", RS_ERR_MATCH)
-
- bot.rs.setUservar(bot.username, "topic", "stuff")
- bot.reply("What color is the sky?", "Blue.")
- bot.reply("What color is the sun?", "Yellow.")
- bot.reply("What color is grass?", RS_ERR_MATCH)
- bot.reply("Name a Red Hat distro.", "Fedora.")
- bot.reply("Name a Debian distro.", "Ubuntu.")
- bot.reply("Say stuff.", '"Stuff."')
-
- bot.rs.setUservar(bot.username, "topic", "override")
- bot.reply("What color is the sky?", "Blue.")
- bot.reply("What color is the sun?", "Purple.")
- bot.reply("What color is grass?", RS_ERR_MATCH)
- bot.reply("Name a Red Hat distro.", RS_ERR_MATCH)
- bot.reply("Name a Debian distro.", RS_ERR_MATCH)
- bot.reply("Say stuff.", RS_ERR_MATCH)
-
- bot.rs.setUservar(bot.username, "topic", "morecolors")
- bot.reply("What color is the sky?", "Blue.")
- bot.reply("What color is the sun?", "Yellow.")
- bot.reply("What color is grass?", "Green.")
- bot.reply("Name a Red Hat distro.", RS_ERR_MATCH)
- bot.reply("Name a Debian distro.", RS_ERR_MATCH)
- bot.reply("Say stuff.", RS_ERR_MATCH)
-
- bot.rs.setUservar(bot.username, "topic", "evenmore")
- bot.reply("What color is the sky?", "Blue.")
- bot.reply("What color is the sun?", "Yellow.")
- bot.reply("What color is grass?", "Blue, sometimes.")
- bot.reply("Name a Red Hat distro.", RS_ERR_MATCH)
- bot.reply("Name a Debian distro.", RS_ERR_MATCH)
- bot.reply("Say stuff.", RS_ERR_MATCH)
-
- test.done()
-
-
-################################################################################
-# calculation (add,sub) tests
-################################################################################
-
-exports.test_addition = (test) ->
- bot = new TestCase(test, """
- + test counter
- - counter set
-
- + show
- - counter =
-
- + add
- - adding
-
- + sub
- - subbing
-
- + div
- -
- ^
- ^ divving
-
- + mult
- -
- ^
- ^ multing
- """)
- bot.reply("test counter", "counter set")
- bot.reply("show", "counter = 0")
- bot.reply("add", "adding")
- bot.reply("show", "counter = 1")
- bot.reply("sub", "subbing")
- bot.reply("show", "counter = 0")
-
- bot.reply("div", "divving")
- bot.reply("show", "counter = 5")
-
- bot.reply("mult", "multing")
- bot.reply("show", "counter = 20")
-
- test.done()
-
-################################################################################
-# Parser option tests
-################################################################################
-
-exports.test_concat = (test) ->
- bot = new TestCase(test, """
- // Default concat mode = none
- + test concat default
- - Hello
- ^ world!
-
- ! local concat = space
- + test concat space
- - Hello
- ^ world!
-
- ! local concat = none
- + test concat none
- - Hello
- ^ world!
-
- ! local concat = newline
- + test concat newline
- - Hello
- ^ world!
-
- // invalid concat setting is equivalent to 'none'
- ! local concat = foobar
- + test concat foobar
- - Hello
- ^ world!
-
- // the option is file scoped so it can be left at
- // any setting and won't affect subsequent parses
- ! local concat = newline
- """)
- bot.extend("""
- // concat mode should be restored to the default in a
- // separate file/stream parse
- + test concat second file
- - Hello
- ^ world!
- """)
-
- bot.reply("test concat default", "Helloworld!")
- bot.reply("test concat space", "Hello world!")
- bot.reply("test concat none", "Helloworld!")
- bot.reply("test concat newline", "Hello\nworld!")
- bot.reply("test concat foobar", "Helloworld!")
- bot.reply("test concat second file", "Helloworld!")
-
- test.done()
-
-################################################################################
-# Unicode Tests
-################################################################################
-
-exports.test_unicode = (test) ->
- bot = new TestCase(test, """
- ! sub who's = who is
-
- + äh
- - What's the matter?
-
- + ブラッキー
- - エーフィ
-
- // Make sure %Previous continues working in UTF-8 mode.
- + knock knock
- - Who's there?
-
- + *
- % who is there
- - who?
-
- + *
- % * who
- - Haha! !
-
- // And with UTF-8.
- + tëll më ä pöëm
- - Thërë öncë wäs ä män nämëd Tïm
-
- + more
- % thërë öncë wäs ä män nämëd tïm
- - Whö nëvër qüïtë lëärnëd höw tö swïm
-
- + more
- % whö nëvër qüïtë lëärnëd höw tö swïm
- - Hë fëll öff ä döck, änd sänk lïkë ä röck
-
- + more
- % hë fëll öff ä döck änd sänk lïkë ä röck
- - Änd thät wäs thë ënd öf hïm.
- """, {"utf8": true})
-
- bot.reply("äh", "What's the matter?")
- bot.reply("ブラッキー", "エーフィ")
- bot.reply("knock knock", "Who's there?")
- bot.reply("Orange", "Orange who?")
- bot.reply("banana", "Haha! Banana!")
- bot.reply("tëll më ä pöëm", "Thërë öncë wäs ä män nämëd Tïm")
- bot.reply("more", "Whö nëvër qüïtë lëärnëd höw tö swïm")
- bot.reply("more", "Hë fëll öff ä döck, änd sänk lïkë ä röck")
- bot.reply("more", "Änd thät wäs thë ënd öf hïm.")
- test.done()
-
-exports.test_punctuation = (test) ->
- bot = new TestCase(test, """
- + hello bot
- - Hello human!
- """, {"utf8": true})
-
- bot.reply("Hello bot", "Hello human!")
- bot.reply("Hello, bot!", "Hello human!")
- bot.reply("Hello: Bot", "Hello human!")
- bot.reply("Hello... bot?", "Hello human!")
-
- bot.rs.unicodePunctuation = new RegExp(/xxx/g)
- bot.reply("Hello bot", "Hello human!")
- bot.reply("Hello, bot!", "ERR: No Reply Matched")
- test.done()
-
-################################################################################
-# Promise Tests
-################################################################################
-
-exports.test_js_string_in_setSubroutine = (test) ->
- bot = new TestCase(test, """
- + hello
- - hello helper
- """)
-
- input = "hello there"
-
- bot.rs.setSubroutine("helper", ["return 'person';"])
- bot.reply("hello", "hello person")
- test.done()
-
-exports.test_function_in_setSubroutine = (test) ->
- bot = new TestCase(test, """
- + my name is *
- - hello personhelper
- """)
-
- input = "my name is Rive"
-
- bot.rs.setSubroutine("helper", (rs, args) ->
- test.equal(rs, bot.rs)
- test.equal(args.length, 1)
- test.equal(args[0], "rive")
- test.done()
- )
-
- bot.reply(input, "hello person")
-
-exports.test_function_in_setSubroutine_return_value = (test) ->
- bot = new TestCase(test, """
- + hello
- - hello helper
- """)
-
- bot.rs.setSubroutine("helper", (rs, args) ->
- "person"
- )
-
- bot.reply("hello", "hello person")
- test.done()
-
-exports.test_arguments_in_setSubroutine = (test) ->
- bot = new TestCase(test, """
- + my name is *
- - hello helper 12
- """)
-
- bot.rs.setSubroutine("helper", (rs, args) ->
- test.equal(args.length, 2)
- test.equal(args[0], "thomas edison")
- test.equal(args[1], "12")
- args[0]
- )
-
- bot.reply("my name is thomas edison", "hello thomas edison")
- test.done()
-
-exports.test_quoted_strings_arguments_in_setSubroutine = (test) ->
- bot = new TestCase(test, """
- + my name is *
- - hello helper 12 "another param"
- """)
-
- bot.rs.setSubroutine("helper", (rs, args) ->
- test.equal(args.length, 3)
- test.equal(args[0], "thomas edison")
- test.equal(args[1], "12")
- test.equal(args[2], "another param")
- args[0]
- )
-
- bot.reply("my name is thomas edison", "hello thomas edison")
- test.done()
-
-exports.test_arguments_with_funky_spacing_in_setSubroutine = (test) ->
- bot = new TestCase(test, """
- + my name is *
- - hello helper 12 "another param"
- """)
-
- bot.rs.setSubroutine("helper", (rs, args) ->
- test.equal(args.length, 3)
- test.equal(args[0], "thomas edison")
- test.equal(args[1], "12")
- test.equal(args[2], "another param")
- args[0]
- )
-
- bot.reply("my name is thomas edison", "hello thomas edison")
- test.done()
-
-exports.test_promises_in_objects = (test) ->
- bot = new TestCase(test, """
- + my name is *
- - hello there helperWithPromise with a anotherHelperWithPromise
- """)
-
- input = "my name is Rive"
-
- bot.rs.setSubroutine("helperWithPromise", (rs, args) ->
- return new rs.Promise((resolve, reject) ->
- resolve("stranger")
- )
- )
-
- bot.rs.setSubroutine("anotherHelperWithPromise", (rs) ->
- return new rs.Promise((resolve, reject) ->
- setTimeout () ->
- resolve("delay")
- , 1000
- )
- )
-
- bot.rs.replyAsync(bot.username, input).then (reply) ->
- test.equal(reply, "hello there stranger with a delay")
- test.done()
-
-exports.test_replyAsync_supports_callbacks = (test) ->
- bot = new TestCase(test, """
- + my name is *
- - hello there asyncHelper
- """)
-
- input = "my name is Rive"
-
- bot.rs.setSubroutine("asyncHelper", (rs, args) ->
- return new rs.Promise((resolve, reject) ->
- resolve("stranger")
- )
- )
-
- bot.rs.replyAsync(bot.username, input, null, (error, reply) ->
- test.ok(!error)
- test.equal(reply, "hello there stranger")
- test.done()
- )
-
-exports.test_use_reply_with_async_subroutines = (test) ->
- bot = new TestCase(test, """
- + my name is *
- - hello there asyncHelper
- """)
-
- bot.rs.setSubroutine("asyncHelper", (rs, args) ->
- return new rs.Promise((resolve, reject) ->
- resolve("stranger")
- )
- )
-
- bot.reply("my name is Rive", "hello there [ERR: Using async routine with reply: use replyAsync instead]")
- test.done()
-
-exports.test_errors_in_async_subroutines_with_callbacks = (test) ->
- bot = new TestCase(test, """
- + my name is *
- - hello there asyncHelper
- """)
-
- errorMessage = "Something went terribly wrong"
-
- bot.rs.setSubroutine("asyncHelper", (rs, args) ->
- return new rs.Promise((resolve, reject) ->
- reject(new Error(errorMessage))
- )
- )
-
- bot.rs.replyAsync(bot.username, "my name is Rive", null, (error, reply) ->
- test.ok(error)
- test.equal(error.message, errorMessage)
- test.ok(!reply)
- test.done()
- )
-
-exports.test_errors_in_async_subroutines_with_promises = (test) ->
- bot = new TestCase(test, """
- + my name is *
- - hello there asyncHelper
- """)
-
- errorMessage = "Something went terribly wrong"
-
- bot.rs.setSubroutine("asyncHelper", (rs, args) ->
- return new rs.Promise((resolve, reject) ->
- reject(new Error(errorMessage))
- )
- )
-
- bot.rs.replyAsync(bot.username, "my name is Rive").catch (error) ->
- test.ok(error)
- test.equal(error.message, errorMessage)
- test.done()
-
-exports.test_async_and_sync_subroutines_together = (test) ->
- bot = new TestCase(test, """
- + my name is *
- - hello there asyncHelperexclaim
- """)
-
-
- bot.rs.setSubroutine("exclaim", (rs, args) ->
- return "!"
- )
-
- bot.rs.setSubroutine("asyncHelper", (rs, args) ->
- return new rs.Promise((resolve, reject) ->
- resolve("stranger")
- )
- )
-
- bot.rs.replyAsync(bot.username, "my name is Rive").then (reply) ->
- test.equal(reply, "hello there stranger!")
- test.done()
-
-
-exports.test_stringify_with_objects = (test) ->
- bot = new TestCase(test, """
- > object hello javascript
- return \"Hello\";
- < object
- + my name is *
- - hello thereexclaim
- """)
-
- bot.rs.setSubroutine("exclaim", (rs) ->
- return "!"
- )
-
- src = bot.rs.stringify()
- expect = '! version = 2.0\n! local concat = none\n\n> object hello javascript\n\treturn "Hello";\n< object\n\n> object exclaim javascript\n\treturn "!";\n< object\n\n+ my name is *\n- hello thereexclaim\n'
- test.equal(src, expect)
- test.done()
-
-
-exports.load_directory_recursively = (test) ->
+exports.test_load_directory_recursively = (test) ->
bot = new TestCase(test, """
+ *
- No, this failed.
@@ -1102,69 +19,84 @@ exports.load_directory_recursively = (test) ->
test.equal(true, false) # Throw error
)
-exports.test_concat_with_conditionals = (test) ->
- # Newline
+exports.test_default_error_messages = (test) ->
bot = new TestCase(test, """
- ! local concat = newline
+ + condition only
+ * == Aiden => Your name is Aiden!
+
+ + recursion
+ - {@recursion}
+
+ + impossible object
+ - Here we go: unhandled
- + test *
- * == a => First A line
- ^ Second A line
- ^ Third A line
- - First B line
- ^ Second B line
- ^ Third B line
+ > object unhandled rust
+ return "Hello world"
+ < object
""")
- bot.reply("test a", "First A line\nSecond A line\nThird A line")
- bot.reply("test b", "First B line\nSecond B line\nThird B line")
+ DEF_NOT_FOUND = "ERR: No Reply Found"
+ DEF_NOT_MATCH = "ERR: No Reply Matched"
+ DEF_NO_OBJECT = "[ERR: Object Not Found]"
+ DEF_RECURSION = "ERR: Deep Recursion Detected"
- # Space
- bot = new TestCase(test, """
- ! local concat = space
+ bot.reply("condition only", DEF_NOT_FOUND)
+ bot.reply("hello bot", DEF_NOT_MATCH)
+ bot.reply("impossible object", "Here we go: #{DEF_NO_OBJECT}")
+ bot.reply("recursion", DEF_RECURSION)
- + test *
- * == a => First A line
- ^ Second A line
- ^ Third A line
- - First B line
- ^ Second B line
- ^ Third B line
- """)
+ # Set some error handlers manually, one at a time.
+ bot.rs.errors.replyNotFound = "I didn't find a reply!"
+ bot.reply("condition only", "I didn't find a reply!")
+ bot.reply("hello bot", DEF_NOT_MATCH)
+ bot.reply("impossible object", "Here we go: #{DEF_NO_OBJECT}")
+ bot.reply("recursion", DEF_RECURSION)
- bot.reply("test a", "First A line Second A line Third A line")
- bot.reply("test b", "First B line Second B line Third B line")
+ bot.rs.errors.replyNotMatched = "I don't even know what to say to that!"
+ bot.reply("condition only", "I didn't find a reply!")
+ bot.reply("hello bot", "I don't even know what to say to that!")
+ bot.reply("impossible object", "Here we go: #{DEF_NO_OBJECT}")
+ bot.reply("recursion", DEF_RECURSION)
- # No concat
- bot = new TestCase(test, """
- + test *
- * == a => First A line
- ^ Second A line
- ^ Third A line
- - First B line
- ^ Second B line
- ^ Third B line
- """)
+ bot.rs.errors.objectNotFound = "I can't handle this object!"
+ bot.reply("condition only", "I didn't find a reply!")
+ bot.reply("hello bot", "I don't even know what to say to that!")
+ bot.reply("impossible object", "Here we go: I can't handle this object!")
+ bot.reply("recursion", DEF_RECURSION)
- bot.reply("test a", "First A lineSecond A lineThird A line")
- bot.reply("test b", "First B lineSecond B lineThird B line")
+ bot.rs.errors.deepRecursion = "I'm going too far down the rabbit hole."
+ bot.reply("condition only", "I didn't find a reply!")
+ bot.reply("hello bot", "I don't even know what to say to that!")
+ bot.reply("impossible object", "Here we go: I can't handle this object!")
+ bot.reply("recursion", "I'm going too far down the rabbit hole.")
test.done()
-
-exports.test_concat_space_with_conditionals = (test) ->
+exports.test_error_constructor_configuration = (test) ->
bot = new TestCase(test, """
- ! local concat = newline
+ + condition only
+ * == Aiden => Your name is Aiden!
- + test *
- * == a => First A line
- ^ Second A line
- ^ Third A line
- - First B line
- ^ Second B line
- ^ Third B line
- """)
+ + recursion
+ - {@recursion}
+
+ + impossible object
+ - Here we go: unhandled
+
+ > object unhandled rust
+ return "Hello world"
+ < object
+ """, {
+ errors:
+ replyNotFound: "I didn't find a reply!"
+ replyNotMatched: "I don't even know what to say to that!"
+ objectNotFound: "I can't handle this object!"
+ deepRecursion: "I'm going too far down the rabbit hole."
+ })
+
+ bot.reply("condition only", "I didn't find a reply!")
+ bot.reply("hello bot", "I don't even know what to say to that!")
+ bot.reply("impossible object", "Here we go: I can't handle this object!")
+ bot.reply("recursion", "I'm going too far down the rabbit hole.")
- bot.reply("test a", "First A line\nSecond A line\nThird A line")
- bot.reply("test b", "First B line\nSecond B line\nThird B line")
test.done()
diff --git a/test/test-substitutions.coffee b/test/test-substitutions.coffee
new file mode 100644
index 0000000..bc6d207
--- /dev/null
+++ b/test/test-substitutions.coffee
@@ -0,0 +1,42 @@
+TestCase = require("./test-base")
+
+################################################################################
+# Substitution Tests
+################################################################################
+
+exports.test_substitutions = (test) ->
+ bot = new TestCase(test, """
+ + whats up
+ - nm.
+
+ + what is up
+ - Not much.
+ """)
+ bot.reply("whats up", "nm.")
+ bot.reply("what's up?", "nm.")
+ bot.reply("what is up?", "Not much.")
+
+ bot.extend("""
+ ! sub whats = what is
+ ! sub what's = what is
+ """)
+ bot.reply("whats up", "Not much.")
+ bot.reply("what's up?", "Not much.")
+ bot.reply("What is up?", "Not much.")
+ test.done()
+
+exports.test_person_substitutions = (test) ->
+ bot = new TestCase(test, """
+ + say *
+ -
+ """)
+ bot.reply("say I am cool", "i am cool")
+ bot.reply("say You are dumb", "you are dumb")
+
+ bot.extend("""
+ ! person i am = you are
+ ! person you are = I am
+ """)
+ bot.reply("say I am cool", "you are cool")
+ bot.reply("say You are dumb", "I am dumb")
+ test.done()
diff --git a/test/test-topics.coffee b/test/test-topics.coffee
new file mode 100644
index 0000000..efc2475
--- /dev/null
+++ b/test/test-topics.coffee
@@ -0,0 +1,123 @@
+TestCase = require("./test-base")
+
+################################################################################
+# Topic Tests
+################################################################################
+
+exports.test_punishment_topic = (test) ->
+ bot = new TestCase(test, """
+ + hello
+ - Hi there!
+
+ + swear word
+ - How rude! Apologize or I won't talk to you again.{topic=sorry}
+
+ + *
+ - Catch-all.
+
+ > topic sorry
+ + sorry
+ - It's ok!{topic=random}
+
+ + *
+ - Say you're sorry!
+ < topic
+ """)
+ bot.reply("hello", "Hi there!")
+ bot.reply("How are you?", "Catch-all.")
+ bot.reply("Swear word!", "How rude! Apologize or I won't talk to you again.")
+ bot.reply("hello", "Say you're sorry!")
+ bot.reply("How are you?", "Say you're sorry!")
+ bot.reply("Sorry!", "It's ok!")
+ bot.reply("hello", "Hi there!")
+ bot.reply("How are you?", "Catch-all.")
+ test.done()
+
+exports.test_topic_inheritance = (test) ->
+ RS_ERR_MATCH = "ERR: No Reply Matched"
+ bot = new TestCase(test, """
+ > topic colors
+ + what color is the sky
+ - Blue.
+
+ + what color is the sun
+ - Yellow.
+ < topic
+
+ > topic linux
+ + name a red hat distro
+ - Fedora.
+
+ + name a debian distro
+ - Ubuntu.
+ < topic
+
+ > topic stuff includes colors linux
+ + say stuff
+ - \"Stuff.\"
+ < topic
+
+ > topic override inherits colors
+ + what color is the sun
+ - Purple.
+ < topic
+
+ > topic morecolors includes colors
+ + what color is grass
+ - Green.
+ < topic
+
+ > topic evenmore inherits morecolors
+ + what color is grass
+ - Blue, sometimes.
+ < topic
+ """)
+ bot.rs.setUservar(bot.username, "topic", "colors")
+ bot.reply("What color is the sky?", "Blue.")
+ bot.reply("What color is the sun?", "Yellow.")
+ bot.reply("What color is grass?", RS_ERR_MATCH)
+ bot.reply("Name a Red Hat distro.", RS_ERR_MATCH)
+ bot.reply("Name a Debian distro.", RS_ERR_MATCH)
+ bot.reply("Say stuff.", RS_ERR_MATCH)
+
+ bot.rs.setUservar(bot.username, "topic", "linux")
+ bot.reply("What color is the sky?", RS_ERR_MATCH)
+ bot.reply("What color is the sun?", RS_ERR_MATCH)
+ bot.reply("What color is grass?", RS_ERR_MATCH)
+ bot.reply("Name a Red Hat distro.", "Fedora.")
+ bot.reply("Name a Debian distro.", "Ubuntu.")
+ bot.reply("Say stuff.", RS_ERR_MATCH)
+
+ bot.rs.setUservar(bot.username, "topic", "stuff")
+ bot.reply("What color is the sky?", "Blue.")
+ bot.reply("What color is the sun?", "Yellow.")
+ bot.reply("What color is grass?", RS_ERR_MATCH)
+ bot.reply("Name a Red Hat distro.", "Fedora.")
+ bot.reply("Name a Debian distro.", "Ubuntu.")
+ bot.reply("Say stuff.", '"Stuff."')
+
+ bot.rs.setUservar(bot.username, "topic", "override")
+ bot.reply("What color is the sky?", "Blue.")
+ bot.reply("What color is the sun?", "Purple.")
+ bot.reply("What color is grass?", RS_ERR_MATCH)
+ bot.reply("Name a Red Hat distro.", RS_ERR_MATCH)
+ bot.reply("Name a Debian distro.", RS_ERR_MATCH)
+ bot.reply("Say stuff.", RS_ERR_MATCH)
+
+ bot.rs.setUservar(bot.username, "topic", "morecolors")
+ bot.reply("What color is the sky?", "Blue.")
+ bot.reply("What color is the sun?", "Yellow.")
+ bot.reply("What color is grass?", "Green.")
+ bot.reply("Name a Red Hat distro.", RS_ERR_MATCH)
+ bot.reply("Name a Debian distro.", RS_ERR_MATCH)
+ bot.reply("Say stuff.", RS_ERR_MATCH)
+
+ bot.rs.setUservar(bot.username, "topic", "evenmore")
+ bot.reply("What color is the sky?", "Blue.")
+ bot.reply("What color is the sun?", "Yellow.")
+ bot.reply("What color is grass?", "Blue, sometimes.")
+ bot.reply("Name a Red Hat distro.", RS_ERR_MATCH)
+ bot.reply("Name a Debian distro.", RS_ERR_MATCH)
+ bot.reply("Say stuff.", RS_ERR_MATCH)
+
+ test.done()
diff --git a/test/test-triggers.coffee b/test/test-triggers.coffee
new file mode 100644
index 0000000..0fb13b3
--- /dev/null
+++ b/test/test-triggers.coffee
@@ -0,0 +1,125 @@
+TestCase = require("./test-base")
+
+################################################################################
+# Trigger Tests
+################################################################################
+
+exports.test_atomic_triggers = (test) ->
+ bot = new TestCase(test, """
+ + hello bot
+ - Hello human.
+
+ + what are you
+ - I am a RiveScript bot.
+ """)
+ bot.reply("Hello bot", "Hello human.")
+ bot.reply("What are you?", "I am a RiveScript bot.")
+ test.done()
+
+exports.test_wildcard_triggers = (test) ->
+ bot = new TestCase(test, """
+ + my name is *
+ - Nice to meet you, .
+
+ + * told me to say *
+ - Why did tell you to say ?
+
+ + i am # years old
+ - A lot of people are .
+
+ + i am _ years old
+ - Say that with numbers.
+
+ + i am * years old
+ - Say that with fewer words.
+ """)
+ bot.reply("my name is Bob", "Nice to meet you, bob.")
+ bot.reply("bob told me to say hi", "Why did bob tell you to say hi?")
+ bot.reply("i am 5 years old", "A lot of people are 5.")
+ bot.reply("i am five years old", "Say that with numbers.")
+ bot.reply("i am twenty five years old", "Say that with fewer words.")
+ test.done()
+
+exports.test_alternatives_and_optionals = (test) ->
+ bot = new TestCase(test, """
+ + what (are|is) you
+ - I am a robot.
+
+ + what is your (home|office|cell) [phone] number
+ - It is 555-1234.
+
+ + [please|can you] ask me a question
+ - Why is the sky blue?
+
+ + (aa|bb|cc) [bogus]
+ - Matched.
+
+ + (yo|hi) [computer|bot] *
+ - Matched.
+ """)
+ bot.reply("What are you?", "I am a robot.")
+ bot.reply("What is you?", "I am a robot.")
+
+ bot.reply("What is your home phone number?", "It is 555-1234.")
+ bot.reply("What is your home number?", "It is 555-1234.")
+ bot.reply("What is your cell phone number?", "It is 555-1234.")
+ bot.reply("What is your office number?", "It is 555-1234.")
+
+ bot.reply("Can you ask me a question?", "Why is the sky blue?")
+ bot.reply("Please ask me a question?", "Why is the sky blue?")
+ bot.reply("Ask me a question.", "Why is the sky blue?")
+
+ bot.reply("aa", "Matched.")
+ bot.reply("bb", "Matched.")
+ bot.reply("aa bogus", "Matched.")
+ bot.reply("aabogus", "ERR: No Reply Matched")
+ bot.reply("bogus", "ERR: No Reply Matched")
+
+ bot.reply("hi Aiden", "Matched.")
+ bot.reply("hi bot how are you?", "Matched.")
+ bot.reply("yo computer what time is it?", "Matched.")
+ bot.reply("yoghurt is yummy", "ERR: No Reply Matched")
+ bot.reply("hide and seek is fun", "ERR: No Reply Matched")
+ bot.reply("hip hip hurrah", "ERR: No Reply Matched")
+ test.done()
+
+exports.test_trigger_arrays = (test) ->
+ bot = new TestCase(test, """
+ ! array colors = red blue green yellow white
+ ^ dark blue|light blue
+
+ + what color is my (@colors) *
+ - Your is .
+
+ + what color was * (@colors) *
+ - It was .
+
+ + i have a @colors *
+ - Tell me more about your .
+ """)
+ bot.reply("What color is my red shirt?", "Your shirt is red.")
+ bot.reply("What color is my blue car?", "Your car is blue.")
+ bot.reply("What color is my pink house?", "ERR: No Reply Matched")
+ bot.reply("What color is my dark blue jacket?", "Your jacket is dark blue.")
+ bot.reply("What color was Napoleoan's white horse?", "It was white.")
+ bot.reply("What color was my red shirt?", "It was red.")
+ bot.reply("I have a blue car.", "Tell me more about your car.")
+ bot.reply("I have a cyan car.", "ERR: No Reply Matched")
+ test.done()
+
+exports.test_weighted_triggers = (test) ->
+ bot = new TestCase(test, """
+ + * or something{weight=10}
+ - Or something. <@>
+
+ + can you run a google search for *
+ - Sure!
+
+ + hello *{weight=20}
+ - Hi there!
+ """)
+ bot.reply("Hello robot.", "Hi there!")
+ bot.reply("Hello or something.", "Hi there!")
+ bot.reply("Can you run a Google search for Node", "Sure!")
+ bot.reply("Can you run a Google search for Node or something", "Or something. Sure!")
+ test.done()
diff --git a/test/test-unicode.coffee b/test/test-unicode.coffee
new file mode 100644
index 0000000..cf00595
--- /dev/null
+++ b/test/test-unicode.coffee
@@ -0,0 +1,71 @@
+TestCase = require("./test-base")
+
+################################################################################
+# Unicode Tests
+################################################################################
+
+exports.test_unicode = (test) ->
+ bot = new TestCase(test, """
+ ! sub who's = who is
+
+ + äh
+ - What's the matter?
+
+ + ブラッキー
+ - エーフィ
+
+ // Make sure %Previous continues working in UTF-8 mode.
+ + knock knock
+ - Who's there?
+
+ + *
+ % who is there
+ - who?
+
+ + *
+ % * who
+ - Haha! !
+
+ // And with UTF-8.
+ + tëll më ä pöëm
+ - Thërë öncë wäs ä män nämëd Tïm
+
+ + more
+ % thërë öncë wäs ä män nämëd tïm
+ - Whö nëvër qüïtë lëärnëd höw tö swïm
+
+ + more
+ % whö nëvër qüïtë lëärnëd höw tö swïm
+ - Hë fëll öff ä döck, änd sänk lïkë ä röck
+
+ + more
+ % hë fëll öff ä döck änd sänk lïkë ä röck
+ - Änd thät wäs thë ënd öf hïm.
+ """, {"utf8": true})
+
+ bot.reply("äh", "What's the matter?")
+ bot.reply("ブラッキー", "エーフィ")
+ bot.reply("knock knock", "Who's there?")
+ bot.reply("Orange", "Orange who?")
+ bot.reply("banana", "Haha! Banana!")
+ bot.reply("tëll më ä pöëm", "Thërë öncë wäs ä män nämëd Tïm")
+ bot.reply("more", "Whö nëvër qüïtë lëärnëd höw tö swïm")
+ bot.reply("more", "Hë fëll öff ä döck, änd sänk lïkë ä röck")
+ bot.reply("more", "Änd thät wäs thë ënd öf hïm.")
+ test.done()
+
+exports.test_punctuation = (test) ->
+ bot = new TestCase(test, """
+ + hello bot
+ - Hello human!
+ """, {"utf8": true})
+
+ bot.reply("Hello bot", "Hello human!")
+ bot.reply("Hello, bot!", "Hello human!")
+ bot.reply("Hello: Bot", "Hello human!")
+ bot.reply("Hello... bot?", "Hello human!")
+
+ bot.rs.unicodePunctuation = new RegExp(/xxx/g)
+ bot.reply("Hello bot", "Hello human!")
+ bot.reply("Hello, bot!", "ERR: No Reply Matched")
+ test.done()