1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     test_Suite.cpp
4 
5   Copyright (C)2009 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: 25571 $
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 #include <nn/dbg/dbg_PrintResult.h>
21 namespace nn{ namespace test{
22 
23     namespace {
24         Suite* s_CurrentSuite = 0;
25 
26 #ifdef NN_PROCESSOR_ARM946ES
27         const int NUM_RESULTHOLDER = 32;
28         const bit32 INVALID_THREADID = 0xffffffff;
29 
30         struct ThreadLocalStrageArm9 {
31             bit32 threadId;
32             uptr  value;
33         } s_ResultHolderArm9[NUM_RESULTHOLDER];
34 #endif
35     }
36 
Suite()37     Suite::Suite() :
38         m_pOutput(NULL), m_TotalTestsNum(0), m_pExitTestJumpBuffer(NULL),
39             m_IsSuccess(false), m_Continue(false), m_IsInitialized(false), m_MainThreadId(nn::os::Thread::GetCurrentId())
40     {
41 #ifdef NN_PROCESSOR_ARM946ES
42         for ( int i = 0; i < NUM_RESULTHOLDER; i++ )
43         {
44             s_ResultHolderArm9[i].threadId = INVALID_THREADID;
45             s_ResultHolderArm9[i].value = 0;
46         }
47 #endif
48     }
49 
~Suite()50     Suite::~Suite()
51     {
52     }
53 
IsOnMainThread() const54     bool Suite::IsOnMainThread() const
55     {
56         return m_MainThreadId == nn::os::Thread::GetCurrentId();
57     }
58 
AddSubSuite(Suite * pSuite)59     void Suite::AddSubSuite(Suite* pSuite)
60     {
61         m_SubSuites.PushBack(pSuite);
62         m_TotalTestsNum += pSuite->m_TotalTestsNum;
63     }
64 
Run(Output & output,bool isContinue)65     bool Suite::Run(Output& output, bool isContinue)
66     {
67         int total = TotalTests();               // サブスイートを含むテスト数
68         int subSuiteNum = m_SubSuites.GetNum();
69 
70         // テスト開始前の初期化
71         m_Continue = isContinue;
72         output.OnInitialize(total, (subSuiteNum+1));
73         Initialize();
74 
75         Time    time;
76         time.Start();
77         DoRun(&output, isContinue);
78         time.End();
79         output.OnFinished(total, time);
80         Finalize();
81         return m_IsSuccess;
82     }
83 
DoRun(Output * pOutput,bool isContinue)84     void Suite::DoRun(Output* pOutput, bool isContinue)
85     {
86         m_IsSuccess = true;
87         int testsNum = m_Tests.GetNum();        // サブスイートを含まないテスト数
88         m_pOutput = pOutput;
89 
90         // このスイートが保持するテストを実行
91         pOutput->OnSuiteStart(testsNum, m_TestName);
92         Time timeSuite;
93         timeSuite.Start();
94         while(!m_Tests.IsEmpty())
95         {
96             TestInfo info = m_Tests.PopFront();
97             bool testResult = DoRunSpecificTest(info, pOutput);
98             m_IsSuccess &= testResult;
99         }
100         timeSuite.End();
101         pOutput->OnSuiteEnd(testsNum, m_TestName, timeSuite);
102 
103         // 子スイートの実行
104         while(!m_SubSuites.IsEmpty())
105         {
106             Suite* pSuite = m_SubSuites.PopFront();
107             pSuite->Initialize();
108             pSuite->DoRun(pOutput, isContinue);
109             pSuite->Finalize();
110             m_IsSuccess &= pSuite->m_IsSuccess;
111         }
112     }
113 
AddAssertInfo(AssertInfo info)114     void Suite::AddAssertInfo(AssertInfo info)
115     {
116         m_pOutput->OnAssert(info);
117         // 1回でもアサートに引っかかっているならこのテストは失敗
118         m_IsTestSuccess = false;
119     }
120 
RegisterTest(TestFunc func,const String & name)121     void Suite::RegisterTest(TestFunc func, const String& name)
122     {
123         m_Tests.PushBack(TestInfo(func, name));
124         m_TotalTestsNum++;
125     }
126 
UnregisterTest(TestFunc func)127     void Suite::UnregisterTest(TestFunc func)
128     {
129         NN_TASSERT_(m_TotalTestsNum == m_Tests.GetNum());
130         for (int i = 0; i < m_TotalTestsNum; i++)
131         {
132             if (m_Tests.GetElement(i).testFunc == func)
133             {
134                 m_Tests.DeleteElement(i);
135                 i--;
136                 m_TotalTestsNum--;
137             }
138         }
139     }
140 
RegisterTestWithInfo(TestFunc func,const String & name,const String & info)141     void Suite::RegisterTestWithInfo(TestFunc func, const String& name, const String& info)
142     {
143         m_Tests.PushBack(TestInfo(func, name, info));
144         m_TotalTestsNum++;
145     }
146 
ExitCurrentTest()147     void Suite::ExitCurrentTest()
148     {
149         if (!IsOnMainThread())
150         {
151             // メインスレッドでなかったらスレッドを強制終了
152             nn::svc::ExitThread();
153             NN_TASSERT_(0);
154         }
155         if(m_pExitTestJumpBuffer)
156         {
157             ::std::longjmp(*m_pExitTestJumpBuffer, 1);
158         }
159         else
160         {
161             NN_TPANIC_("Failed long jump, Suite::ExitCurrentTest()");
162         }
163     }
164 
OnPanic(const char * pFilename,int lineNo,const char * pMessage)165     void Suite::OnPanic(const char* pFilename, int lineNo, const char* pMessage)
166     {
167         AddAssertInfo(AssertInfo(pFilename, lineNo, pMessage));
168         ExitCurrentTest();
169     }
170 
171     nn::os::ThreadLocalStorage Suite::ResultHolder::tls_pExpectedResult;
172 
GetCurrent()173     inline Suite::ResultHolder* Suite::ResultHolder::GetCurrent()
174     {
175 #ifndef NN_PROCESSOR_ARM946ES
176         return reinterpret_cast<Suite::ResultHolder*>(tls_pExpectedResult.GetValue());
177 #else
178         bit32 threadId = nn::os::Thread::GetCurrentId();
179         for ( int i = 0; i < NUM_RESULTHOLDER; i++ )
180         {
181             if ( threadId == s_ResultHolderArm9[i].threadId )
182             {
183                 return reinterpret_cast<Suite::ResultHolder*>(s_ResultHolderArm9[i].value);
184             }
185         }
186         return 0;
187 #endif
188     }
189 
SetCurrent(Suite::ResultHolder * result)190     inline void Suite::ResultHolder::SetCurrent(Suite::ResultHolder* result)
191     {
192 #ifndef NN_PROCESSOR_ARM946ES
193         tls_pExpectedResult.SetValue(reinterpret_cast<uptr>(result));
194 #else
195         bit32 threadId = nn::os::Thread::GetCurrentId();
196         int lastBlank = -1;
197         for ( int i = 0; i < NUM_RESULTHOLDER; i++ )
198         {
199             if ( threadId == s_ResultHolderArm9[i].threadId )
200             {
201                 s_ResultHolderArm9[i].value = reinterpret_cast<uptr>(result);
202                 return;
203             }
204             if ( s_ResultHolderArm9[i].threadId == INVALID_THREADID )
205             {
206                 lastBlank = i;
207             }
208         }
209         if ( lastBlank != -1 )
210         {
211             s_ResultHolderArm9[lastBlank].threadId = threadId;
212             s_ResultHolderArm9[lastBlank].value = reinterpret_cast<uptr>(result);
213             return;
214         }
215         NN_LOG("Is not empty ThreadLocalStorage for Arm9");
216         nn::svc::Break(nn::dbg::BREAK_REASON_PANIC);
217 #endif
218     }
219 
GetCurrentResult()220     Result Suite::ResultHolder::GetCurrentResult()
221     {
222         return GetCurrent()->m_Result;
223     }
224 
ResultHolder()225     Suite::ResultHolder::ResultHolder()
226     {
227         NN_TASSERT_(!GetCurrent());
228         SetCurrent(this);
229     }
230 
~ResultHolder()231     Suite::ResultHolder::~ResultHolder()
232     {
233         NN_TASSERT_(GetCurrent());
234 #ifndef NN_PROCESSOR_ARM946ES
235         SetCurrent(0);
236 #else
237         bit32 threadId = nn::os::Thread::GetCurrentId();
238         bool foundStorage = false;
239         for ( int i = 0; i < NUM_RESULTHOLDER; i++ )
240         {
241             if ( threadId == s_ResultHolderArm9[i].threadId )
242             {
243                 s_ResultHolderArm9[i].threadId = INVALID_THREADID;
244                 s_ResultHolderArm9[i].value = 0;
245                 foundStorage = true;
246             }
247         }
248         if ( !foundStorage )
249         {
250             NN_LOG("Not found ThreadLocalStorage for Arm9");
251             nn::svc::Break(nn::dbg::BREAK_REASON_PANIC);
252         }
253 #endif
254     }
255 
GetJmpbuf()256     ::std::jmp_buf* Suite::ResultHolder::GetJmpbuf()
257     {
258         return &m_Jmpbuf;
259     }
260 
ResultFailureHandler(Result result,const char * filename,int lineno,const char * fmt,::std::va_list vlist)261     void Suite::ResultHolder::ResultFailureHandler(Result result, const char* filename, int lineno, const char* fmt, ::std::va_list vlist)
262     {
263         if (GetCurrent())
264         {
265             GetCurrent()->m_Result = result;
266             longjmp(GetCurrent()->m_Jmpbuf, 1);
267             NN_TLOG_("longjmp failed.");
268             nn::svc::Break(nn::dbg::BREAK_REASON_PANIC);
269         }
270         else
271         {
272             NN_TASSERT_(s_CurrentSuite);
273             char buf[256];
274             ::std::vsnprintf(buf, sizeof(buf), fmt, vlist);
275             NN_TLOG_("Result Failure\n");
276             nn::dbg::PrintResult(result);
277             s_CurrentSuite->OnPanic(filename, lineno, buf);
278             // 戻ってこないはず
279             NN_TLOG_("Failed OnPanic\n");
280             nn::svc::Break(nn::dbg::BREAK_REASON_PANIC);
281         }
282     }
283 
ResultPanicHandler(Result result,const char * filename,int lineno,const char * fmt,::std::va_list vlist)284     void Suite::ResultHolder::ResultPanicHandler(Result result, const char* filename, int lineno, const char* fmt, ::std::va_list vlist)
285     {
286         if (GetCurrent())
287         {
288             GetCurrent()->m_Result = result;
289             longjmp(GetCurrent()->m_Jmpbuf, 1);
290             NN_TLOG_("longjmp failed.");
291             nn::svc::Break(nn::dbg::BREAK_REASON_PANIC);
292         }
293         else
294         {
295             NN_TASSERT_(s_CurrentSuite);
296             char buf[256];
297             ::std::vsnprintf(buf, sizeof(buf), fmt, vlist);
298             NN_TLOG_("Panic Result\n");
299             nn::dbg::PrintResult(result);
300             s_CurrentSuite->OnPanic(filename, lineno, buf);
301             // 戻ってこないはず
302             NN_TLOG_("Failed OnPanic\n");
303             nn::svc::Break(nn::dbg::BREAK_REASON_PANIC);
304         }
305     }
306 
RunSpecificTestFunc(const char * testFuncName,Output & output,bool contAfterFail)307     bool    Suite::RunSpecificTestFunc(const char* testFuncName, Output& output, bool contAfterFail)
308     {
309         //該当するテスト関数の含んだTestInfoの取得
310         String funcNameStr = String(testFuncName);
311         TestInfo testInfo;
312         if(GetTestInfo(funcNameStr, testInfo) == false)
313         {
314             //Suiteに該当するテスト関数が登録されていない場合
315             return false;
316         }
317 
318         PreProcessForSpecificTest(&output, contAfterFail);
319         bool result = DoRunSpecificTest(testInfo, &output);
320         PostProcessForSpecificTest();
321 
322         return result;
323     }
324 
RunSpecificTestFunc(const char * subSuiteName,const char * testFuncName,Output & output,bool contAfterFail)325     bool    Suite::RunSpecificTestFunc(const char* subSuiteName, const char* testFuncName, Output& output, bool contAfterFail)
326     {
327         //サブSuiteの取得
328         Suite* correspondSuite = NULL;
329         String suiteNameStr = String(subSuiteName);
330         if(GetSubSuite(suiteNameStr, &correspondSuite) == false)
331         {
332             //指定されたサブSuiteが存在しない場合
333             return false;
334         }
335 
336         return correspondSuite->RunSpecificTestFunc(testFuncName, output, contAfterFail);
337     }
338 
RunSpecificTestFunc(s32 testFuncId,Output & output,bool contAfterFail)339     bool    Suite::RunSpecificTestFunc(s32 testFuncId, Output& output, bool contAfterFail)
340     {
341         //該当するテスト関数の含んだTestInfoの取得
342         TestInfo testInfo;
343         if(GetTestSuiteAndInfo(testFuncId, NULL, testInfo) == false)
344         {
345             //Suiteに該当するテスト関数が登録されていない場合
346             return false;
347         }
348 
349         PreProcessForSpecificTest(&output, contAfterFail);
350         bool result = DoRunSpecificTest(testInfo, &output);
351         PostProcessForSpecificTest();
352 
353         return result;
354     }
355 
GetTestFuncInfos(s32 testId,String & suiteName,String & testFuncName)356     bool Suite::GetTestFuncInfos(s32 testId, String& suiteName, String& testFuncName)
357     {
358        Suite* correspondSuite = NULL;
359        TestInfo correspondTestInfo;
360        bool resultGetInfo = GetTestSuiteAndInfo(testId, &correspondSuite, correspondTestInfo);
361        if(resultGetInfo == true)
362        {
363            suiteName = correspondSuite->GetTestName();
364            testFuncName = correspondTestInfo.testName;
365            return true;
366        }
367        else
368        {
369            return false;
370        }
371     }
372 
GetTestFuncInfos(s32 testId,String & suiteName,String & testFuncName,String & testInfo)373     bool Suite::GetTestFuncInfos(s32 testId, String& suiteName, String& testFuncName, String& testInfo)
374     {
375        Suite* correspondSuite = NULL;
376        TestInfo correspondTestInfo;
377        bool resultGetInfo = GetTestSuiteAndInfo(testId, &correspondSuite, correspondTestInfo);
378        if(resultGetInfo == true)
379        {
380            suiteName = correspondSuite->GetTestName();
381            testFuncName = correspondTestInfo.testName;
382            testInfo = correspondTestInfo.testInfo;
383            return true;
384        }
385        else
386        {
387            return false;
388        }
389     }
390 
391 
DoRunSpecificTest(Suite::TestInfo & testInfo,Output * pOutput)392     bool    Suite::DoRunSpecificTest(Suite::TestInfo& testInfo, Output* pOutput)
393     {
394         /*
395          * テストの成否は、m_IsTestSuccessに設定する。テスト開始前にm_IsTestSuccessをtrueに設定し、失敗時にはfalseを再設定する
396          */
397         m_IsTestSuccess = true;
398         Time timeCase;
399         bool testResult = true;
400 
401         SetUp();
402 
403         pOutput->OnTestStart(testInfo.testName);
404 
405         timeCase.Start();
406         ::std::jmp_buf jumpBuf;
407         m_pExitTestJumpBuffer = &jumpBuf;
408         s_CurrentSuite = this;
409         if(setjmp(jumpBuf) == 0)
410         {
411             (this->*testInfo.testFunc)();
412         }
413         else
414         {
415             /*
416                                       「assertにかかると、以降のテストを継続しない」モードのテストでは、ExitCurrentTest が呼ばれこのパスに入る。
417               (モードはRun()やRunSpecificTestFunc()の引数で指定)
418                                       「assertにかかっても、以降のテストを継続する」モードのテストでは、assert時はこのパスに入らない。
419                                       代わりにSuite::AddAssertInfo()に入り、m_IsTestSuccessを設定する。
420              */
421             m_IsTestSuccess = false;
422         }
423         m_pExitTestJumpBuffer = NULL;
424         s_CurrentSuite = 0;
425         timeCase.End();
426         pOutput->OnTestEnd(testInfo.testName, testResult, timeCase);
427 
428         TearDown();
429 
430         return m_IsTestSuccess;
431     }
432 
GetSubSuite(String & subSuiteName,Suite ** ppSuite)433     bool Suite::GetSubSuite(String& subSuiteName, Suite** ppSuite)
434     {
435         NN_TASSERT_(ppSuite != NULL);
436         bool isSuiteFound = false;
437         const u32 subSuiteNum = m_SubSuites.GetNum();
438 
439         for(unsigned int i = 0; i < subSuiteNum; ++i)
440         {
441             Suite* suitPos = m_SubSuites.GetElement(i);
442             if(suitPos->GetTestName() == subSuiteName)
443             {
444                 *ppSuite = suitPos;
445                 isSuiteFound = true;
446                 break;
447             }
448         }
449 
450         return isSuiteFound;
451     }
452 
GetTestSuiteAndInfo(s32 testId,Suite ** ppSuite,Suite::TestInfo & testInfoBuf)453     bool Suite::GetTestSuiteAndInfo(s32 testId, Suite** ppSuite, Suite::TestInfo& testInfoBuf)
454     {
455         //IDに該当するテスト関数が存在するかを確認
456          if(testId > m_TotalTestsNum)
457          {
458              //存在しない場合
459              return false;
460          }
461 
462          //IDに該当するテスト関数が、このSuite自身に存在するのか、サブSuite内に存在するかを確認
463          if(testId <= m_Tests.GetNum())
464          {
465              //このSuite自身に存在する場合
466              if(GetTestInfo(testId, testInfoBuf) == false)
467              {
468                  return false;
469              }
470 
471              if(ppSuite != NULL)
472              {
473                 *ppSuite = this;
474              }
475              return true;
476          }
477          else
478          {
479              //サブSuiteに存在する場合
480              u32 checkedIdMax = m_Tests.GetNum();//確認済みのIDの最大値。IDに該当する関数がどのサブSuiteに存在するかを調査するために用いる。//
481              const u32 subSuiteNum = m_SubSuites.GetNum();
482              for(unsigned int i = 0; i < subSuiteNum; ++i)
483              {
484                  Suite* pSuit = m_SubSuites.GetElement(i);
485                  const u32 subSuiteMaxId = checkedIdMax + pSuit->GetTotalTestNum();
486                  if(testId > subSuiteMaxId)
487                  {
488                      //pSuitが示すサブSuiteにIDが含まれないため、調査済みIDを更新し、次のサブSuiteの調査に移る。
489                      checkedIdMax = subSuiteMaxId;
490                  }
491                  else
492                  {
493                      /*
494                       * pSuitが示すサブSuiteにIDが含まれる場合は、そのサブSuiteのGetTestSuiteAndInfo()でSuiteとTestInfoを得る。
495                       * 引数のIDは、サブSuite基点でのtestIDに変換する。
496                       */
497                      const u32 testIdInSubSuite = testId - checkedIdMax;
498                      pSuit->GetTestSuiteAndInfo(testIdInSubSuite, ppSuite, testInfoBuf);
499                      break;
500                  }
501              }
502 
503              return true;
504          }
505     }
506 
507 
GetTestInfo(String funcName,Suite::TestInfo & testInfoBuf)508     bool Suite::GetTestInfo(String funcName, Suite::TestInfo& testInfoBuf)
509     {
510         bool isInfoFound = false;
511         const u32 infoNum = m_Tests.GetNum();
512         for(unsigned int i = 0; i < infoNum; ++i)
513         {
514             TestInfo pTestInfo = m_Tests.GetElement(i);
515             if(pTestInfo.testName == funcName)
516             {
517                 isInfoFound = true;
518                 testInfoBuf = pTestInfo;
519                 break;
520             }
521         }
522 
523         return isInfoFound;
524     }
525 
526 
GetTestInfo(s32 testInfoId,Suite::TestInfo & testInfoBuf)527     bool Suite::GetTestInfo(s32 testInfoId, Suite::TestInfo& testInfoBuf)
528     {
529         //IDに該当するTestInfoが存在するかを確認
530         if((testInfoId > m_Tests.GetNum()) || (testInfoId == 0))
531         {
532             //存在しない場合
533             return false;
534         }
535 
536         testInfoBuf = m_Tests.GetElement((testInfoId-1));
537         return true;
538     }
539 
Initialize()540     void Suite::Initialize()
541     {
542         if(m_IsInitialized == false)
543         {
544             InitializeSuite();
545             m_IsInitialized = true;
546         }
547     }
548 
Finalize()549     void Suite::Finalize()
550     {
551         if(m_IsInitialized == true)
552         {
553             FinalizeSuite();
554             m_IsInitialized = false;
555         }
556     }
557 
PreProcessForSpecificTest(Output * pOutput,bool contAfterFail)558     void Suite::PreProcessForSpecificTest(Output* pOutput, bool contAfterFail)
559     {
560         Initialize();
561         m_Continue = contAfterFail;
562         m_pOutput = pOutput;
563         m_pOutput->OnInitialize(1, 1);
564         m_pOutput->OnSuiteStart(1, GetTestName());
565     }
566 
PostProcessForSpecificTest()567     void Suite::PostProcessForSpecificTest()
568     {
569         Time time;//特定テストの実施では、Suiteとしての実施時間を計測して意味がない(テスト単体の実施時間がわかればよい)ため、実施時刻には0を出力する//
570         m_pOutput->OnSuiteEnd(1, GetTestName(), time);
571         m_pOutput->OnFinished(1, time);
572         Finalize();
573     }
574 
GetCurrentSuite()575     Suite* Suite::GetCurrentSuite()
576     {
577         if ( !s_CurrentSuite )
578         {
579             NN_PANIC("No running test suite");
580         }
581         return s_CurrentSuite;
582     }
583 }}
584 
nnResultFailureHandler(nnResult result,const char * filename,int lineno,const char * fmt,...)585 extern "C" int nnResultFailureHandler(nnResult result, const char* filename, int lineno, const char* fmt, ...)
586 {
587     va_list vlist;
588     va_start(vlist, fmt);
589     nn::test::Suite::ResultHolder::ResultFailureHandler(reinterpret_cast<nn::Result&>(result), filename, lineno, fmt, vlist);
590     va_end(vlist);
591     return 0;
592 }
593 
nnResultTFailureHandler(nnResult result,const char * filename,int lineno,const char * fmt,...)594 extern "C" int nnResultTFailureHandler(nnResult result, const char* filename, int lineno, const char* fmt, ...)
595 {
596     va_list vlist;
597     va_start(vlist, fmt);
598     nn::test::Suite::ResultHolder::ResultFailureHandler(reinterpret_cast<nn::Result&>(result), filename, lineno, fmt, vlist);
599     va_end(vlist);
600     return 0;
601 }
602 
nnResultPanicHandler(nnResult result,const char * filename,int lineno,const char * fmt,...)603 extern "C" int nnResultPanicHandler(nnResult result, const char* filename, int lineno, const char* fmt, ...)
604 {
605     va_list vlist;
606     va_start(vlist, fmt);
607     nn::test::Suite::ResultHolder::ResultPanicHandler(reinterpret_cast<nn::Result&>(result), filename, lineno, fmt, vlist);
608     va_end(vlist);
609     return 0;
610 }
611 
nnResultTPanicHandler(nnResult result,const char * filename,int lineno,const char * fmt,...)612 extern "C" int nnResultTPanicHandler(nnResult result, const char* filename, int lineno, const char* fmt, ...)
613 {
614     va_list vlist;
615     va_start(vlist, fmt);
616     nn::test::Suite::ResultHolder::ResultPanicHandler(reinterpret_cast<nn::Result&>(result), filename, lineno, fmt, vlist);
617     va_end(vlist);
618     return 0;
619 }
620 /*
621 void nn::dbg::Panic(const char* filename, int lineno, const char* fmt, va_list vlist)
622 {
623     nn::Result result = nnMakeInvalidResult();
624     nn::test::Suite::ResultHolder::ResultPanicHandler(reinterpret_cast<nn::Result&>(result), filename, lineno, fmt, vlist);
625 }
626 
627 void nn::dbg::TVPanic(const char* filename, int lineno, const char* fmt, va_list vlist)
628 {
629     nn::Result result = nnMakeInvalidResult();
630     nn::test::Suite::ResultHolder::ResultPanicHandler(reinterpret_cast<nn::Result&>(result), filename, lineno, fmt, vlist);
631 }
632 */
633