7b46de3e27
- Making run_tests accept a target namespace as an argument. - Fixed asynchronous trigger callback mechanism. MCBF triggers working again. - Fixed numerical problems when calculating standard deviation for rand triggers.
139 lines
3.9 KiB
Text
139 lines
3.9 KiB
Text
# Minimalistic framework for automated testing in Nasal
|
|
#
|
|
# Copyright (C) 2014 Anton Gomez Alvedro
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License as
|
|
# published by the Free Software Foundation; either version 2 of the
|
|
# License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
|
# TestSuite
|
|
#
|
|
# Tests are organized in test suites. Each test suite contains an arbitrary
|
|
# number of tests, and two special methods "setup" and "cleanup". Setup is
|
|
# called before every test, and cleanup is called after every test.
|
|
#
|
|
# In order to define a test suite, you have to create an object parented to
|
|
# TestSuite. The testing framework will identify any method in your object whose
|
|
# name starts with "test_" as a test case to be run.
|
|
#
|
|
# Important: The order in which test cases and test suites are executed
|
|
# is undefined!
|
|
#
|
|
# Example:
|
|
#
|
|
# var MyTestSuite = {
|
|
#
|
|
# parents: [TestSuite],
|
|
#
|
|
# setup: func {
|
|
# Stuff to do before every test...
|
|
# This is optional. You don't need to provide it if you don't use it.
|
|
# },
|
|
#
|
|
# cleanup: func {
|
|
# Stuff to do after every test...
|
|
# Also optional.
|
|
# },
|
|
#
|
|
# my_auxiliary_function: func {
|
|
# Methods that do not start with "test_" will not be executed by the
|
|
# test runner. You can define as many auxiliary functions in the test
|
|
# suite as you wish.
|
|
# },
|
|
#
|
|
# test_trivial_test: func {
|
|
# This is a real test (starts with "test_"), and it will be run by the
|
|
# framework when test_run() is called.#
|
|
# }
|
|
# };
|
|
|
|
var TestSuite = {
|
|
setup: func 0,
|
|
cleanup: func 0
|
|
};
|
|
|
|
# run_tests([namespace])
|
|
#
|
|
# Executes all test suites found in the given namespace. If no namespace is
|
|
# specified, then the namespace where run_tests is defined is used by default.
|
|
#
|
|
# An effective way to work with the framework is to just include the framework
|
|
# from your test files:
|
|
#
|
|
# io.include(".../test.nas");
|
|
#
|
|
# and then execute a script like this in the Nasal Console:
|
|
#
|
|
# delete(globals, "test");
|
|
# io.load_nasal(".../my_test_suite.nas", "test");
|
|
# test.run_tests();
|
|
#
|
|
# What this script does is: it empties the "test" namespace and then loads your
|
|
# script into that namespace. The test framework will be loaded in there as
|
|
# well if it was io.include'd in my_test_suite.nas. Finally, all test suites
|
|
# in the "test" namespace are executed.
|
|
|
|
var run_tests = func(namespace=nil) {
|
|
|
|
var ns = namespace != nil ? namespace : closure(run_tests, 1);
|
|
|
|
var passed = 0;
|
|
var failed = 0;
|
|
var err = [];
|
|
|
|
foreach(var suite_name; keys(ns)) {
|
|
var suite = ns[suite_name];
|
|
|
|
if (!isa(suite, TestSuite))
|
|
continue;
|
|
|
|
print("Running test suite ", suite_name);
|
|
|
|
foreach (var test_name; keys(suite)) {
|
|
|
|
if (find("test_", test_name) != 0)
|
|
continue;
|
|
|
|
# Run the test case
|
|
setsize(err, 0);
|
|
contains(suite, "setup") and call(suite.setup, [], suite, err);
|
|
size(err) == 0 and call(suite[test_name], [], suite, err);
|
|
size(err) == 0 and contains(suite, "cleanup") and call(suite.cleanup, [], suite, err);
|
|
|
|
if (size(err) == 0) {
|
|
passed += 1;
|
|
continue;
|
|
}
|
|
|
|
failed += 1;
|
|
print("Test ", test_name, " FAILED\n");
|
|
debug.printerror(err);
|
|
}
|
|
}
|
|
|
|
print(sprintf("\n%d tests run. %d passed, %d failed",
|
|
passed + failed, passed, failed));
|
|
}
|
|
|
|
|
|
var assert_prop_exists = func (prop) {
|
|
assert(props.globals.getNode(prop) != nil,
|
|
sprintf("Property %s does not exist", prop));
|
|
}
|
|
|
|
|
|
var fail_if_prop_exists = func (prop) {
|
|
assert(props.globals.getNode(prop) == nil,
|
|
sprintf("Property %s exists", prop));
|
|
}
|