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