Nasal unit-testing: allow deep struct equality.
Add a deep comparison of vecs and hashes, when deciding equality in test assertions.
This commit is contained in:
parent
2bb15866b8
commit
f0d3663102
6 changed files with 139 additions and 13 deletions
|
@ -1956,3 +1956,54 @@ naRef NasalXMLVisitor::make_string(const char* s, int n)
|
|||
return naStr_fromdata(naNewString(_c), const_cast<char *>(s),
|
||||
n < 0 ? strlen(s) : n);
|
||||
}
|
||||
|
||||
// like naEqual, but checks vector/hash recursively
|
||||
// note this will not tolerate a recursively defined Nasal structure
|
||||
// (such as globals.)
|
||||
int nasalStructEqual(naContext ctx, naRef a, naRef b)
|
||||
{
|
||||
if (naIsVector(a) && naIsVector(b)) {
|
||||
const int aSz = naVec_size(a),
|
||||
bSz = naVec_size(b);
|
||||
|
||||
if (aSz != bSz)
|
||||
return 0;
|
||||
|
||||
for (int i = 0; i < aSz; ++i) {
|
||||
int eq = nasalStructEqual(ctx, naVec_get(a, i), naVec_get(b, i));
|
||||
if (!eq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// all elements equal, we're done
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (naIsHash(a) && naIsHash(b)) {
|
||||
naRef keysVec = naNewVector(ctx);
|
||||
naHash_keys(keysVec, a);
|
||||
const auto aSz = naVec_size(keysVec);
|
||||
|
||||
// first check key count, that's fast
|
||||
if (aSz != naHash_size(b))
|
||||
return 0;
|
||||
|
||||
for (int i = 0; i < aSz; i++) {
|
||||
naRef key = naVec_get(keysVec, i);
|
||||
naRef aValue, bValue;
|
||||
if (!naHash_get(a, key, &aValue) || !naHash_get(b, key, &bValue)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eq = nasalStructEqual(ctx, aValue, bValue);
|
||||
if (!eq) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// all values matched, we're good
|
||||
return 1;
|
||||
}
|
||||
|
||||
return naEqual(a, b);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,12 @@
|
|||
#include <simgear/nasal/nasal.h>
|
||||
#include <simgear/xml/easyxml.hxx>
|
||||
|
||||
/**
|
||||
@breif wrapper for naEqual which recursively checks vec/hash equality
|
||||
Probably not very performant.
|
||||
*/
|
||||
int nasalStructEqual(naContext ctx, naRef a, naRef b);
|
||||
|
||||
class FGNasalListener : public SGPropertyChangeListener {
|
||||
public:
|
||||
FGNasalListener(SGPropertyNode* node, naRef code, FGNasalSys* nasal,
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include <Main/globals.hxx>
|
||||
#include <Main/util.hxx>
|
||||
#include <Scripting/NasalSys.hxx>
|
||||
#include <Scripting/NasalSys_private.hxx>
|
||||
|
||||
#include <Main/fg_commands.hxx>
|
||||
|
||||
#include <simgear/nasal/cppbind/from_nasal.hxx>
|
||||
|
@ -106,7 +108,7 @@ static naRef f_assert_equal(const nasal::CallContext& ctx )
|
|||
naRef argB = ctx.requireArg<naRef>(1);
|
||||
auto msg = ctx.getArg<string>(2, "assert_equal failed");
|
||||
|
||||
bool same = naEqual(argA, argB);
|
||||
bool same = nasalStructEqual(ctx.c_ctx(), argA, argB);
|
||||
if (!same) {
|
||||
string aStr = ctx.from_nasal<string>(argA);
|
||||
string bStr = ctx.from_nasal<string>(argB);
|
||||
|
@ -142,6 +144,15 @@ static naRef f_assert_doubles_equal(const nasal::CallContext& ctx )
|
|||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_equal(const nasal::CallContext& ctx)
|
||||
{
|
||||
naRef argA = ctx.requireArg<naRef>(0);
|
||||
naRef argB = ctx.requireArg<naRef>(1);
|
||||
|
||||
bool same = nasalStructEqual(ctx.c_ctx(), argA, argB);
|
||||
return naNum(same);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// commands
|
||||
|
||||
|
@ -187,6 +198,7 @@ naRef initNasalUnitTestInSim(naRef nasalGlobals, naContext c)
|
|||
unitTest.set("fail", f_fail);
|
||||
unitTest.set("assert_equal", f_assert_equal);
|
||||
unitTest.set("assert_doubles_equal", f_assert_doubles_equal);
|
||||
unitTest.set("equal", f_equal);
|
||||
|
||||
globals->get_commands()->addCommand("nasal-test", &command_executeNasalTest);
|
||||
globals->get_commands()->addCommand("nasal-test-dir", &command_executeNasalTestDir);
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
#include <Main/globals.hxx>
|
||||
#include <Main/util.hxx>
|
||||
|
||||
#include <Scripting/NasalSys.hxx>
|
||||
#include <Scripting/NasalSys_private.hxx>
|
||||
|
||||
#include <cppunit/TestAssert.h>
|
||||
|
||||
#include <simgear/nasal/cppbind/from_nasal.hxx>
|
||||
|
@ -50,9 +53,6 @@ static naRef f_assert(const nasal::CallContext& ctx )
|
|||
auto msg = ctx.getArg<string>(1, "assert failed:");
|
||||
|
||||
CppUnit::Asserter::failIf(!pass, "assertion failed:" + msg, nasalSourceLine(ctx));
|
||||
if (!pass) {
|
||||
ctx.runtimeError(msg.c_str());
|
||||
}
|
||||
return naNil();
|
||||
}
|
||||
|
||||
|
@ -62,8 +62,6 @@ static naRef f_fail(const nasal::CallContext& ctx )
|
|||
|
||||
CppUnit::Asserter::fail("assertion failed:" + msg,
|
||||
nasalSourceLine(ctx));
|
||||
|
||||
ctx.runtimeError("Test failed: %s", msg.c_str());
|
||||
return naNil();
|
||||
}
|
||||
|
||||
|
@ -73,7 +71,7 @@ static naRef f_assert_equal(const nasal::CallContext& ctx )
|
|||
naRef argB = ctx.requireArg<naRef>(1);
|
||||
auto msg = ctx.getArg<string>(2, "assert_equal failed");
|
||||
|
||||
bool same = naEqual(argA, argB);
|
||||
bool same = nasalStructEqual(ctx.c_ctx(), argA, argB);
|
||||
if (!same) {
|
||||
|
||||
string aStr = ctx.from_nasal<string>(argA);
|
||||
|
@ -81,12 +79,20 @@ static naRef f_assert_equal(const nasal::CallContext& ctx )
|
|||
msg += "; expected:" + aStr + ", actual:" + bStr;
|
||||
|
||||
CppUnit::Asserter::fail(msg, nasalSourceLine(ctx));
|
||||
ctx.runtimeError(msg.c_str());
|
||||
}
|
||||
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_equal(const nasal::CallContext& ctx)
|
||||
{
|
||||
naRef argA = ctx.requireArg<naRef>(0);
|
||||
naRef argB = ctx.requireArg<naRef>(1);
|
||||
|
||||
bool same = nasalStructEqual(ctx.c_ctx(), argA, argB);
|
||||
return naNum(same);
|
||||
}
|
||||
|
||||
static naRef f_assert_doubles_equal(const nasal::CallContext& ctx )
|
||||
{
|
||||
double argA = ctx.requireArg<double>(0);
|
||||
|
@ -99,7 +105,6 @@ static naRef f_assert_doubles_equal(const nasal::CallContext& ctx )
|
|||
if (!same) {
|
||||
msg += "; expected:" + std::to_string(argA) + ", actual:" + std::to_string(argB);
|
||||
CppUnit::Asserter::fail(msg, nasalSourceLine(ctx));
|
||||
ctx.runtimeError(msg.c_str());
|
||||
}
|
||||
|
||||
return naNil();
|
||||
|
@ -114,6 +119,7 @@ naRef initNasalUnitTestCppUnit(naRef nasalGlobals, naContext c)
|
|||
unitTest.set("assert", f_assert);
|
||||
unitTest.set("fail", f_fail);
|
||||
unitTest.set("assert_equal", f_assert_equal);
|
||||
unitTest.set("equal", f_equal);
|
||||
unitTest.set("assert_doubles_equal", f_assert_doubles_equal);
|
||||
|
||||
return naNil();
|
||||
|
|
|
@ -20,21 +20,72 @@
|
|||
|
||||
#include "testNasalSys.hxx"
|
||||
|
||||
#include "test_suite/FGTestApi/testGlobals.hxx"
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/util.hxx>
|
||||
#include <Scripting/NasalSys.hxx>
|
||||
|
||||
#include <Main/FGInterpolator.hxx>
|
||||
|
||||
// Set up function for each test.
|
||||
void NasalSysTests::setUp()
|
||||
{
|
||||
FGTestApi::setUp::initTestGlobals("NasalSys");
|
||||
|
||||
fgInitAllowedPaths();
|
||||
globals->get_props()->getNode("nasal", true);
|
||||
|
||||
globals->add_subsystem("prop-interpolator", new FGInterpolator, SGSubsystemMgr::INIT);
|
||||
|
||||
globals->get_subsystem_mgr()->bind();
|
||||
globals->get_subsystem_mgr()->init();
|
||||
|
||||
globals->add_new_subsystem<FGNasalSys>(SGSubsystemMgr::INIT);
|
||||
|
||||
globals->get_subsystem_mgr()->postinit();
|
||||
}
|
||||
|
||||
|
||||
// Clean up after each test.
|
||||
void NasalSysTests::tearDown()
|
||||
{
|
||||
FGTestApi::tearDown::shutdownTestGlobals();
|
||||
}
|
||||
|
||||
|
||||
// Test test
|
||||
void NasalSysTests::testDummy()
|
||||
void NasalSysTests::testStructEquality()
|
||||
{
|
||||
CPPUNIT_ASSERT(1 != 2);
|
||||
bool ok = FGTestApi::executeNasal(R"(
|
||||
var foo = {
|
||||
"name": "Bob",
|
||||
"size": [512, 512],
|
||||
"mipmapping": 1.9
|
||||
};
|
||||
|
||||
var bar = {
|
||||
"name": "Bob",
|
||||
"size": [512, 512],
|
||||
"mipmapping": 1.9
|
||||
};
|
||||
|
||||
unitTest.assert_equal(foo, bar);
|
||||
|
||||
append(bar.size, "Wowow");
|
||||
unitTest.assert(unitTest.equal(foo, bar) == 0);
|
||||
|
||||
append(foo.size, "Wowow");
|
||||
unitTest.assert_equal(foo, bar);
|
||||
|
||||
foo.wibble = 99.1;
|
||||
unitTest.assert(unitTest.equal(foo, bar) == 0);
|
||||
|
||||
bar.wibble = 99;
|
||||
unitTest.assert(unitTest.equal(foo, bar) == 0);
|
||||
bar.wibble = 99.1;
|
||||
unitTest.assert_equal(foo, bar);
|
||||
|
||||
)");
|
||||
CPPUNIT_ASSERT(ok);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ class NasalSysTests : public CppUnit::TestFixture
|
|||
{
|
||||
// Set up the test suite.
|
||||
CPPUNIT_TEST_SUITE(NasalSysTests);
|
||||
CPPUNIT_TEST(testDummy);
|
||||
CPPUNIT_TEST(testStructEquality);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
|
@ -42,7 +42,7 @@ public:
|
|||
void tearDown();
|
||||
|
||||
// The tests.
|
||||
void testDummy();
|
||||
void testStructEquality();
|
||||
};
|
||||
|
||||
#endif // _FG_NASALSYS_UNIT_TESTS_HXX
|
||||
|
|
Loading…
Reference in a new issue