From ce6bd859b39d9529b5b4fff938b1b66fc5b03a44 Mon Sep 17 00:00:00 2001
From: James Turner <zakalawe@mac.com>
Date: Fri, 22 May 2020 17:35:24 +0100
Subject: [PATCH] Add Nasal source location to unit-tests

---
 src/Scripting/NasalUnitTesting.cxx            | 23 ++++++++++++-------
 .../FGTestApi/NasalUnitTesting_TestSuite.cxx  | 22 +++++++++++-------
 2 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/src/Scripting/NasalUnitTesting.cxx b/src/Scripting/NasalUnitTesting.cxx
index 354a35450..4651a2504 100644
--- a/src/Scripting/NasalUnitTesting.cxx
+++ b/src/Scripting/NasalUnitTesting.cxx
@@ -47,7 +47,8 @@ struct ActiveTest
 {
     bool failure = false;
     std::string failureMessage;
-    std::string failureLocation;
+    std::string failureFileName;
+    int failLineNumber;
 };
 
 static std::unique_ptr<ActiveTest> static_activeTest;
@@ -68,9 +69,9 @@ static naRef f_assert(const nasal::CallContext& ctx )
         
         static_activeTest->failure = true;
         static_activeTest->failureMessage = msg;
-        // capture location
-        
-        
+        static_activeTest->failureFileName = ctx.from_nasal<string>(naGetSourceFile(ctx.c_ctx(), 0));
+        static_activeTest->failLineNumber = naGetLine(ctx.c_ctx(), 0);
+
         ctx.runtimeError("Test assert failed");
     }
     
@@ -91,9 +92,12 @@ static naRef f_fail(const nasal::CallContext& ctx )
    
    static_activeTest->failure = true;
    static_activeTest->failureMessage = msg;
-    ctx.runtimeError("Test failed");
+   static_activeTest->failureFileName = ctx.from_nasal<string>(naGetSourceFile(ctx.c_ctx(), 0));
+   static_activeTest->failLineNumber = naGetLine(ctx.c_ctx(), 0);
 
-    return naNil();
+   ctx.runtimeError("Test failed");
+
+   return naNil();
 }
 
 static naRef f_assert_equal(const nasal::CallContext& ctx )
@@ -109,6 +113,8 @@ static naRef f_assert_equal(const nasal::CallContext& ctx )
         msg += "; expected:" + aStr + ", actual:" + bStr;
         static_activeTest->failure = true;
         static_activeTest->failureMessage = msg;
+        static_activeTest->failureFileName = ctx.from_nasal<string>(naGetSourceFile(ctx.c_ctx(), 0));
+        static_activeTest->failLineNumber = naGetLine(ctx.c_ctx(), 0);
         ctx.runtimeError(msg.c_str());
     }
     
@@ -128,6 +134,8 @@ static naRef f_assert_doubles_equal(const nasal::CallContext& ctx )
         msg += "; expected:" + std::to_string(argA) + ", actual:" + std::to_string(argB);
         static_activeTest->failure = true;
         static_activeTest->failureMessage = msg;
+        static_activeTest->failureFileName = ctx.from_nasal<string>(naGetSourceFile(ctx.c_ctx(), 0));
+        static_activeTest->failLineNumber = naGetLine(ctx.c_ctx(), 0);
         ctx.runtimeError(msg.c_str());
     }
     
@@ -256,10 +264,9 @@ bool executeNasalTest(const SGPath& path)
            
            nasalSys->callWithContext(ctx, value.getValue<naRef>(), 0, nullptr, localNS.get_naRef());
            if (static_activeTest->failure) {
-               SG_LOG(SG_NASAL, SG_DEV_WARN, value.getKey() << ": Test failure:" << static_activeTest->failureMessage);
+               SG_LOG(SG_NASAL, SG_DEV_WARN, value.getKey() << ": Test failure:" << static_activeTest->failureMessage << "\n\tat: " << static_activeTest->failureFileName << ": " << static_activeTest->failLineNumber);
            } else {
                SG_LOG(SG_NASAL, SG_INFO, value.getKey() << ": Test passed");
-
            }
            
            if (naIsFunc(tearDown)) {
diff --git a/test_suite/FGTestApi/NasalUnitTesting_TestSuite.cxx b/test_suite/FGTestApi/NasalUnitTesting_TestSuite.cxx
index b0f84f8d8..186b236b5 100644
--- a/test_suite/FGTestApi/NasalUnitTesting_TestSuite.cxx
+++ b/test_suite/FGTestApi/NasalUnitTesting_TestSuite.cxx
@@ -37,13 +37,19 @@
 #include <simgear/nasal/cppbind/NasalHash.hxx>
 #include <simgear/nasal/cppbind/Ghost.hxx>
 
+static CppUnit::SourceLine nasalSourceLine(onst nasal::CallContext& ctx)
+{
+    const string fileName = ctx.from_nasal<string>(naGetSourceFile(ctx.c_ctx(), 0));
+    const int lineNumber = naGetLine(ctx.c_ctx(), 0);
+    return CppUnit::SourceLine(fileName, lineNumber);
+}
+
 static naRef f_assert(const nasal::CallContext& ctx )
 {
     bool pass = ctx.requireArg<bool>(0);
     auto msg = ctx.getArg<string>(1, "assert failed:");
-    
-    CppUnit::Asserter::failIf(!pass, "assertion failed:" + msg,
-                              CppUnit::SourceLine{"Nasal source line", 0});
+
+    CppUnit::Asserter::failIf(!pass, "assertion failed:" + msg, nasalSourceLine(ctx));
     if (!pass) {
         ctx.runtimeError(msg.c_str());
     }
@@ -53,10 +59,10 @@ static naRef f_assert(const nasal::CallContext& ctx )
 static naRef f_fail(const nasal::CallContext& ctx )
 {
     auto msg = ctx.getArg<string>(0);
-    
+
     CppUnit::Asserter::fail("assertion failed:" + msg,
-                              CppUnit::SourceLine{"Nasal source line", 0});
-    
+                            nasalSourceLine(ctx));
+
     ctx.runtimeError("Test failed: %s", msg.c_str());
     return naNil();
 }
@@ -74,6 +80,7 @@ static naRef f_assert_equal(const nasal::CallContext& ctx )
         string bStr = ctx.from_nasal<string>(argB);
         msg += "; expected:" + aStr + ", actual:" + bStr;
 
+        CppUnit::Asserter::fail(msg, nasalSourceLine(ctx));
         ctx.runtimeError(msg.c_str());
     }
     
@@ -91,8 +98,7 @@ static naRef f_assert_doubles_equal(const nasal::CallContext& ctx )
     const bool same = fabs(argA - argB) < tolerance;
     if (!same) {
         msg += "; expected:" + std::to_string(argA) + ", actual:" + std::to_string(argB);
-    //    static_activeTest->failure = true;
-    //    static_activeTest->failureMessage = msg;
+        CppUnit::Asserter::fail(msg, nasalSourceLine(ctx));
         ctx.runtimeError(msg.c_str());
     }