1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     test_Suite.cpp
4 
5   Copyright (C)2009-2012 Nintendo Co., Ltd.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Rev: 46347 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn/test/test_Suite.h>
17 #include <nn/test/test_Output.h>
18 #include <nn/test/test_Time.h>
19 #include <nn/test/test_Api.h>
20 
21 #if !defined(NN_HARDWARE_CTR_CTTS) && defined(NN_PLATFORM_HAS_MMU) && defined(TEST_WITH_GUI) && !defined(NN_PROCESSOR_ARM946ES)
22 #include <nn/test/gui/test_Gui.h>
23 #endif
24 
25 #include <nn/dbg/dbg_PrintResult.h>
26 
27 namespace nn{ namespace test{
28 
29     namespace {
30         Suite* s_CurrentSuite = 0;
31 
32 #ifdef NN_PROCESSOR_ARM946ES
33         const int NUM_RESULTHOLDER = 32;
34         const bit32 INVALID_THREADID = 0xffffffff;
35 
36         struct ThreadLocalStrageArm9 {
37             bit32 threadId;
38             uptr  value;
39         } s_ResultHolderArm9[NUM_RESULTHOLDER];
40 #endif
41     }
42 
Suite()43     Suite::Suite() :
44         m_pOutput(NULL), m_TotalTestsNum(0), m_pExitTestJumpBuffer(NULL),
45             m_IsSuccess(false), m_Continue(false), m_IsInitialized(false), m_MainThreadId(nn::os::Thread::GetCurrentId())
46     {
47 #ifdef NN_PROCESSOR_ARM946ES
48         for ( int i = 0; i < NUM_RESULTHOLDER; i++ )
49         {
50             s_ResultHolderArm9[i].threadId = INVALID_THREADID;
51             s_ResultHolderArm9[i].value = 0;
52         }
53 #endif
54     }
55 
~Suite()56     Suite::~Suite()
57     {
58     }
59 
IsOnMainThread() const60     bool Suite::IsOnMainThread() const
61     {
62         return m_MainThreadId == nn::os::Thread::GetCurrentId();
63     }
64 
AddSubSuite(Suite * pSuite)65     void Suite::AddSubSuite(Suite* pSuite)
66     {
67         m_SubSuites.PushBack(pSuite);
68         m_TotalTestsNum += pSuite->m_TotalTestsNum;
69     }
70 
Run(Output & output,bool isContinue)71     bool Suite::Run(Output& output, bool isContinue)
72     {
73         int total = TotalTests();               // Number of tests including sub-suites
74         int subSuiteNum = m_SubSuites.GetNum();
75 
76         // Initialization before starting test
77         m_Continue = isContinue;
78         output.OnInitialize(total, (subSuiteNum+1));
79         Initialize();
80 
81         Time    time;
82         time.Start();
83         DoRun(&output, isContinue);
84         time.End();
85         output.OnFinished(total, time);
86         Finalize();
87         return m_IsSuccess;
88     }
89 
DoRun(Output * pOutput,bool isContinue)90     void Suite::DoRun(Output* pOutput, bool isContinue)
91     {
92         m_IsSuccess = true;
93         int testsNum = m_Tests.GetNum();        // Number of tests not including sub-suites
94         m_pOutput = pOutput;
95 
96         // Executing test maintained by this suite
97         pOutput->OnSuiteStart(testsNum, m_TestName);
98         Time timeSuite;
99         timeSuite.Start();
100         while(!m_Tests.IsEmpty())
101         {
102             TestInfo info = m_Tests.PopFront();
103             bool testResult = DoRunSpecificTest(info, pOutput);
104             m_IsSuccess &= testResult;
105         }
106         timeSuite.End();
107         pOutput->OnSuiteEnd(testsNum, m_TestName, timeSuite);
108 
109         // Execute child suite
110         while(!m_SubSuites.IsEmpty())
111         {
112             Suite* pSuite = m_SubSuites.PopFront();
113             pSuite->Initialize();
114             pSuite->DoRun(pOutput, isContinue);
115             pSuite->Finalize();
116             m_IsSuccess &= pSuite->m_IsSuccess;
117         }
118     }
119 
AddAssertInfo(AssertInfo info)120     void Suite::AddAssertInfo(AssertInfo info)
121     {
122         m_pOutput->OnAssert(info);
123         // Test fails if caught by an assert even once.
124         m_IsTestSuccess = false;
125     }
126 
RegisterTest(TestFunc func,const String & name)127     void Suite::RegisterTest(TestFunc func, const String& name)
128     {
129         m_Tests.PushBack(TestInfo(func, name));
130         m_TotalTestsNum++;
131     }
132 
UnregisterTest(TestFunc func)133     void Suite::UnregisterTest(TestFunc func)
134     {
135         NN_TASSERT_(m_TotalTestsNum == m_Tests.GetNum());
136         for (int i = 0; i < m_TotalTestsNum; i++)
137         {
138             if (m_Tests.GetElement(i).testFunc == func)
139             {
140                 m_Tests.DeleteElement(i);
141                 i--;
142                 m_TotalTestsNum--;
143             }
144         }
145     }
146 
RegisterTestWithInfo(TestFunc func,const String & name,const String & info)147     void Suite::RegisterTestWithInfo(TestFunc func, const String& name, const String& info)
148     {
149         m_Tests.PushBack(TestInfo(func, name, info));
150         m_TotalTestsNum++;
151     }
152 
ExitCurrentTest()153     void Suite::ExitCurrentTest()
154     {
155         if (!IsOnMainThread())
156         {
157             // Force thread to terminate if it is not the main thread
158             nn::svc::ExitThread();
159             NN_TASSERT_(0);
160         }
161         if(m_pExitTestJumpBuffer)
162         {
163             ::std::longjmp(*m_pExitTestJumpBuffer, 1);
164         }
165         else
166         {
167             NN_TPANIC_("Failed long jump, Suite::ExitCurrentTest()");
168         }
169     }
170 
OnPanic(const char * pFilename,int lineNo,const char * pMessage)171     void Suite::OnPanic(const char* pFilename, int lineNo, const char* pMessage)
172     {
173         AddAssertInfo(AssertInfo(pFilename, lineNo, pMessage));
174         ExitCurrentTest();
175     }
176 
177     nn::os::ThreadLocalStorage Suite::ResultHolder::tls_pExpectedResult;
178 
GetCurrent()179     inline Suite::ResultHolder* Suite::ResultHolder::GetCurrent()
180     {
181 #ifndef NN_PROCESSOR_ARM946ES
182         return reinterpret_cast<Suite::ResultHolder*>(tls_pExpectedResult.GetValue());
183 #else
184         bit32 threadId = nn::os::Thread::GetCurrentId();
185         for ( int i = 0; i < NUM_RESULTHOLDER; i++ )
186         {
187             if ( threadId == s_ResultHolderArm9[i].threadId )
188             {
189                 return reinterpret_cast<Suite::ResultHolder*>(s_ResultHolderArm9[i].value);
190             }
191         }
192         return 0;
193 #endif
194     }
195 
SetCurrent(Suite::ResultHolder * result)196     inline void Suite::ResultHolder::SetCurrent(Suite::ResultHolder* result)
197     {
198 #ifndef NN_PROCESSOR_ARM946ES
199         tls_pExpectedResult.SetValue(reinterpret_cast<uptr>(result));
200 #else
201         bit32 threadId = nn::os::Thread::GetCurrentId();
202         int lastBlank = -1;
203         for ( int i = 0; i < NUM_RESULTHOLDER; i++ )
204         {
205             if ( threadId == s_ResultHolderArm9[i].threadId )
206             {
207                 s_ResultHolderArm9[i].value = reinterpret_cast<uptr>(result);
208                 return;
209             }
210             if ( s_ResultHolderArm9[i].threadId == INVALID_THREADID )
211             {
212                 lastBlank = i;
213             }
214         }
215         if ( lastBlank != -1 )
216         {
217             s_ResultHolderArm9[lastBlank].threadId = threadId;
218             s_ResultHolderArm9[lastBlank].value = reinterpret_cast<uptr>(result);
219             return;
220         }
221         NN_TPANIC_("Is not empty ThreadLocalStorage for Arm9");
222 #endif
223     }
224 
GetCurrentResult()225     Result Suite::ResultHolder::GetCurrentResult()
226     {
227         return GetCurrent()->m_Result;
228     }
229 
ResultHolder()230     Suite::ResultHolder::ResultHolder()
231     {
232         NN_TASSERT_(!GetCurrent());
233         SetCurrent(this);
234     }
235 
~ResultHolder()236     Suite::ResultHolder::~ResultHolder()
237     {
238         NN_TASSERT_(GetCurrent());
239 #ifndef NN_PROCESSOR_ARM946ES
240         SetCurrent(0);
241 #else
242         bit32 threadId = nn::os::Thread::GetCurrentId();
243         bool foundStorage = false;
244         for ( int i = 0; i < NUM_RESULTHOLDER; i++ )
245         {
246             if ( threadId == s_ResultHolderArm9[i].threadId )
247             {
248                 s_ResultHolderArm9[i].threadId = INVALID_THREADID;
249                 s_ResultHolderArm9[i].value = 0;
250                 foundStorage = true;
251             }
252         }
253         if ( !foundStorage )
254         {
255             NN_TPANIC_("Not found ThreadLocalStorage for Arm9");
256         }
257 #endif
258     }
259 
GetJmpbuf()260     ::std::jmp_buf* Suite::ResultHolder::GetJmpbuf()
261     {
262         return &m_Jmpbuf;
263     }
264 
ResultFailureHandler(Result result,const char * filename,int lineno,const char * fmt,::std::va_list vlist)265     void Suite::ResultHolder::ResultFailureHandler(Result result, const char* filename, int lineno, const char* fmt, ::std::va_list vlist)
266     {
267         if (GetCurrent())
268         {
269             GetCurrent()->m_Result = result;
270             longjmp(GetCurrent()->m_Jmpbuf, 1);
271             NN_TPANIC_("longjmp failed.");
272         }
273         else
274         {
275             char buf[256];
276             ::std::vsnprintf(buf, sizeof(buf), fmt, vlist);
277             NN_TLOG_("Result Failure\n");
278             NN_DBG_TPRINT_RESULT_(result);
279 
280             NN_TASSERT_(s_CurrentSuite);
281             s_CurrentSuite->OnPanic(filename, lineno, buf);
282             // Should not return
283             NN_TPANIC_("Failed OnPanic\n");
284         }
285     }
286 
ResultPanicHandler(Result result,const char * filename,int lineno,const char * fmt,::std::va_list vlist)287     void Suite::ResultHolder::ResultPanicHandler(Result result, const char* filename, int lineno, const char* fmt, ::std::va_list vlist)
288     {
289         if (GetCurrent())
290         {
291             GetCurrent()->m_Result = result;
292             longjmp(GetCurrent()->m_Jmpbuf, 1);
293             NN_TPANIC_("longjmp failed.");
294         }
295         else
296         {
297             NN_TASSERT_(s_CurrentSuite);
298             char buf[256];
299             ::std::vsnprintf(buf, sizeof(buf), fmt, vlist);
300             NN_TLOG_("Panic Result\n");
301             NN_DBG_TPRINT_RESULT_(result);
302             s_CurrentSuite->OnPanic(filename, lineno, buf);
303             // Should not return
304             NN_TPANIC_("Failed OnPanic\n");
305         }
306     }
307 
RunSpecificTestFunc(const char * testFuncName,Output & output,bool contAfterFail)308     bool    Suite::RunSpecificTestFunc(const char* testFuncName, Output& output, bool contAfterFail)
309     {
310         //Get TestInfo that includes the appropriate test functions
311         String funcNameStr = String(testFuncName);
312         TestInfo testInfo;
313         if(GetTestInfo(funcNameStr, testInfo) == false)
314         {
315             //When the appropriate test functions are not registered in the Suite
316             return false;
317         }
318 
319         PreProcessForSpecificTest(&output, contAfterFail);
320         bool result = DoRunSpecificTest(testInfo, &output);
321         PostProcessForSpecificTest();
322 
323         return result;
324     }
325 
RunSpecificTestFunc(const char * subSuiteName,const char * testFuncName,Output & output,bool contAfterFail)326     bool    Suite::RunSpecificTestFunc(const char* subSuiteName, const char* testFuncName, Output& output, bool contAfterFail)
327     {
328         //Get the sub Suite
329         Suite* correspondSuite = NULL;
330         String suiteNameStr = String(subSuiteName);
331         if(GetSubSuite(suiteNameStr, &correspondSuite) == false)
332         {
333             //When the specified sub Suite does not exist
334             return false;
335         }
336 
337         return correspondSuite->RunSpecificTestFunc(testFuncName, output, contAfterFail);
338     }
339 
RunSpecificTestFunc(s32 testFuncId,Output & output,bool contAfterFail)340     bool    Suite::RunSpecificTestFunc(s32 testFuncId, Output& output, bool contAfterFail)
341     {
342         //Get TestInfo that includes the appropriate test functions
343         TestInfo testInfo;
344         if(GetTestSuiteAndInfo(testFuncId, NULL, testInfo) == false)
345         {
346             //When the appropriate test functions are not registered in the Suite
347             return false;
348         }
349 
350         PreProcessForSpecificTest(&output, contAfterFail);
351         bool result = DoRunSpecificTest(testInfo, &output);
352         PostProcessForSpecificTest();
353 
354 #if defined(TEST_WITH_GUI)
355         nn::test::FlushLog();
356 #endif
357         return result;
358     }
359 
GetTestFuncInfos(s32 testId,String & suiteName,String & testFuncName)360     bool Suite::GetTestFuncInfos(s32 testId, String& suiteName, String& testFuncName)
361     {
362        Suite* correspondSuite = NULL;
363        TestInfo correspondTestInfo;
364        bool resultGetInfo = GetTestSuiteAndInfo(testId, &correspondSuite, correspondTestInfo);
365        if(resultGetInfo == true)
366        {
367            suiteName = correspondSuite->GetTestName();
368            testFuncName = correspondTestInfo.testName;
369            return true;
370        }
371        else
372        {
373            return false;
374        }
375     }
376 
GetTestFuncInfos(s32 testId,String & suiteName,String & testFuncName,String & testInfo)377     bool Suite::GetTestFuncInfos(s32 testId, String& suiteName, String& testFuncName, String& testInfo)
378     {
379        Suite* correspondSuite = NULL;
380        TestInfo correspondTestInfo;
381        bool resultGetInfo = GetTestSuiteAndInfo(testId, &correspondSuite, correspondTestInfo);
382        if(resultGetInfo == true)
383        {
384            suiteName = correspondSuite->GetTestName();
385            testFuncName = correspondTestInfo.testName;
386            testInfo = correspondTestInfo.testInfo;
387            return true;
388        }
389        else
390        {
391            return false;
392        }
393     }
394 
UnregisterTest(s32 testId)395     void Suite::UnregisterTest(s32 testId)
396     {
397         NN_TASSERT_(m_TotalTestsNum == m_Tests.GetNum());
398         if (m_TotalTestsNum < testId)
399         {
400             return;
401         }
402 
403         m_Tests.DeleteElement(testId - 1);
404         m_TotalTestsNum--;
405     }
406 
407 
DoRunSpecificTest(Suite::TestInfo & testInfo,Output * pOutput)408     bool    Suite::DoRunSpecificTest(Suite::TestInfo& testInfo, Output* pOutput)
409     {
410         /*
411          * Success or failure of the test is set in m_IsTestSuccess. Before the test starts, m_IsTestSuccess is set to true. When it fails, it is reset to false.
412          */
413         m_IsTestSuccess = true;
414         Time timeCase;
415         bool testResult = true;
416 
417         SetUp();
418 
419         pOutput->OnTestStart(testInfo.testName);
420 
421         timeCase.Start();
422         ::std::jmp_buf jumpBuf;
423         m_pExitTestJumpBuffer = &jumpBuf;
424         s_CurrentSuite = this;
425         if(setjmp(jumpBuf) == 0)
426         {
427             (this->*testInfo.testFunc)();
428         }
429         else
430         {
431             /*
432                                       For test in the "do not proceed to subsequent tests when an assert is encountered" mode, ExitCurrentTest is called and this path is taken.
433               (Mode is specified by the Run() or RunSpecificTestFunc() argument)
434                                       For test in the "do not proceed to subsequent tests when an assert is encountered" mode,this path is not taken at the time of the assert.
435                                       Instead enters Suite::AddAssertInfo() and sets m_IsTestSuccess.
436              */
437             m_IsTestSuccess = false;
438         }
439         m_pExitTestJumpBuffer = NULL;
440         s_CurrentSuite = 0;
441         timeCase.End();
442         pOutput->OnTestEnd(testInfo.testName, testResult, timeCase);
443 
444         TearDown();
445 
446         return m_IsTestSuccess;
447     }
448 
GetSubSuite(String & subSuiteName,Suite ** ppSuite)449     bool Suite::GetSubSuite(String& subSuiteName, Suite** ppSuite)
450     {
451         NN_TASSERT_(ppSuite != NULL);
452         bool isSuiteFound = false;
453         const u32 subSuiteNum = m_SubSuites.GetNum();
454 
455         for(unsigned int i = 0; i < subSuiteNum; ++i)
456         {
457             Suite* suitPos = m_SubSuites.GetElement(i);
458             if(suitPos->GetTestName() == subSuiteName)
459             {
460                 *ppSuite = suitPos;
461                 isSuiteFound = true;
462                 break;
463             }
464         }
465 
466         return isSuiteFound;
467     }
468 
GetTestSuiteAndInfo(s32 testId,Suite ** ppSuite,Suite::TestInfo & testInfoBuf)469     bool Suite::GetTestSuiteAndInfo(s32 testId, Suite** ppSuite, Suite::TestInfo& testInfoBuf)
470     {
471         //Confirms whether the test function corresponding to the ID exists
472          if(testId > m_TotalTestsNum)
473          {
474              //When it does not exist
475              return false;
476          }
477 
478          //Confirms whether the test corresponding to the ID exists in this Suite itself or in a sub-Suite
479          if(testId <= m_Tests.GetNum())
480          {
481              //When it exists in this Suite itself
482              if(GetTestInfo(testId, testInfoBuf) == false)
483              {
484                  return false;
485              }
486 
487              if(ppSuite != NULL)
488              {
489                 *ppSuite = this;
490              }
491              return true;
492          }
493          else
494          {
495              //When it exists in a sub-Suite
496              u32 checkedIdMax = m_Tests.GetNum();//Maximum value of the confirmed ID. Used to check in which sub-Suite the function corresponding to the ID exists.//
497              const u32 subSuiteNum = m_SubSuites.GetNum();
498              for(unsigned int i = 0; i < subSuiteNum; ++i)
499              {
500                  Suite* pSuit = m_SubSuites.GetElement(i);
501                  const u32 subSuiteMaxId = checkedIdMax + pSuit->GetTotalTestNum();
502                  if(testId > subSuiteMaxId)
503                  {
504                      //Because the ID is not included in the sub-Suite indicated by pSuit, updates the checked ID and moves on to check the next sub-Suite.
505                      checkedIdMax = subSuiteMaxId;
506                  }
507                  else
508                  {
509                      /*
510                       * When the ID is included in the sub-Suite indicated by pSuit, the Suite and TestInfo is obtained with GetTestSuiteAndInfo() of that sub-Suite.
511                       * The argument ID is converted to testID in the sub-Suite origin.
512                       */
513                      const u32 testIdInSubSuite = testId - checkedIdMax;
514                      pSuit->GetTestSuiteAndInfo(testIdInSubSuite, ppSuite, testInfoBuf);
515                      break;
516                  }
517              }
518 
519              return true;
520          }
521     }
522 
523 
GetTestInfo(String funcName,Suite::TestInfo & testInfoBuf)524     bool Suite::GetTestInfo(String funcName, Suite::TestInfo& testInfoBuf)
525     {
526         bool isInfoFound = false;
527         const u32 infoNum = m_Tests.GetNum();
528         for(unsigned int i = 0; i < infoNum; ++i)
529         {
530             TestInfo pTestInfo = m_Tests.GetElement(i);
531             if(pTestInfo.testName == funcName)
532             {
533                 isInfoFound = true;
534                 testInfoBuf = pTestInfo;
535                 break;
536             }
537         }
538 
539         return isInfoFound;
540     }
541 
542 
GetTestInfo(s32 testInfoId,Suite::TestInfo & testInfoBuf)543     bool Suite::GetTestInfo(s32 testInfoId, Suite::TestInfo& testInfoBuf)
544     {
545         //Confirms whether TestInfo corresponding to the ID exists
546         if((testInfoId > m_Tests.GetNum()) || (testInfoId == 0))
547         {
548             //When it does not exist
549             return false;
550         }
551 
552         testInfoBuf = m_Tests.GetElement((testInfoId-1));
553         return true;
554     }
555 
Initialize()556     void Suite::Initialize()
557     {
558         if(m_IsInitialized == false)
559         {
560             InitializeSuite();
561             m_IsInitialized = true;
562         }
563     }
564 
Finalize()565     void Suite::Finalize()
566     {
567         if(m_IsInitialized == true)
568         {
569             FinalizeSuite();
570 #if defined(TEST_WITH_GUI)
571             nn::test::FlushLog();
572 #endif
573             m_IsInitialized = false;
574         }
575     }
576 
PreProcessForSpecificTest(Output * pOutput,bool contAfterFail)577     void Suite::PreProcessForSpecificTest(Output* pOutput, bool contAfterFail)
578     {
579         Initialize();
580         m_Continue = contAfterFail;
581         m_pOutput = pOutput;
582         m_pOutput->OnInitialize(1, 1);
583         m_pOutput->OnSuiteStart(1, GetTestName());
584     }
585 
PostProcessForSpecificTest()586     void Suite::PostProcessForSpecificTest()
587     {
588         Time time;//In the operation of a specific test, the operation time is output as 0 since it is meaningless to measure the operation time as a Suite (only the single unit test operation time needs to be known) //
589         m_pOutput->OnSuiteEnd(1, GetTestName(), time);
590         m_pOutput->OnFinished(1, time);
591         Finalize();
592     }
593 
GetCurrentSuite()594     Suite* Suite::GetCurrentSuite()
595     {
596         if ( !s_CurrentSuite )
597         {
598             NN_PANIC("No running test suite");
599         }
600         return s_CurrentSuite;
601     }
602 }}
603 
nnResultFailureHandler(nnResult result,const char * filename,int lineno,const char * fmt,...)604 extern "C" int nnResultFailureHandler(nnResult result, const char* filename, int lineno, const char* fmt, ...)
605 {
606     va_list vlist;
607     va_start(vlist, fmt);
608     nn::test::Suite::ResultHolder::ResultFailureHandler(reinterpret_cast<nn::Result&>(result), filename, lineno, fmt, vlist);
609     va_end(vlist);
610     return 0;
611 }
612 
nnResultTFailureHandler(nnResult result,const char * filename,int lineno,const char * fmt,...)613 extern "C" int nnResultTFailureHandler(nnResult result, const char* filename, int lineno, const char* fmt, ...)
614 {
615     va_list vlist;
616     va_start(vlist, fmt);
617     nn::test::Suite::ResultHolder::ResultFailureHandler(reinterpret_cast<nn::Result&>(result), filename, lineno, fmt, vlist);
618     va_end(vlist);
619     return 0;
620 }
621 
nnResultPanicHandler(nnResult result,const char * filename,int lineno,const char * fmt,...)622 extern "C" int nnResultPanicHandler(nnResult result, const char* filename, int lineno, const char* fmt, ...)
623 {
624     va_list vlist;
625     va_start(vlist, fmt);
626     nn::test::Suite::ResultHolder::ResultPanicHandler(reinterpret_cast<nn::Result&>(result), filename, lineno, fmt, vlist);
627     va_end(vlist);
628     return 0;
629 }
630 
nnResultTPanicHandler(nnResult result,const char * filename,int lineno,const char * fmt,...)631 extern "C" int nnResultTPanicHandler(nnResult result, const char* filename, int lineno, const char* fmt, ...)
632 {
633     va_list vlist;
634     va_start(vlist, fmt);
635     nn::test::Suite::ResultHolder::ResultPanicHandler(reinterpret_cast<nn::Result&>(result), filename, lineno, fmt, vlist);
636     va_end(vlist);
637     return 0;
638 }
639 /*
640 void nn::dbg::Panic(const char* filename, int lineno, const char* fmt, va_list vlist)
641 {
642     nn::Result result = nnMakeInvalidResult();
643     nn::test::Suite::ResultHolder::ResultPanicHandler(reinterpret_cast<nn::Result&>(result), filename, lineno, fmt, vlist);
644 }
645 
646 void nn::dbg::TVPanic(const char* filename, int lineno, const char* fmt, va_list vlist)
647 {
648     nn::Result result = nnMakeInvalidResult();
649     nn::test::Suite::ResultHolder::ResultPanicHandler(reinterpret_cast<nn::Result&>(result), filename, lineno, fmt, vlist);
650 }
651 */
652