4 Copyright (c) Microsoft Corporation.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <Library/UnitTestLib.h>
10 #include <Library/BaseLib.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/MemoryAllocationLib.h>
13 #include <Library/DebugLib.h>
14 #include <Library/UnitTestPersistenceLib.h>
15 #include <Library/UnitTestResultReportLib.h>
18 /// Forward declaration of prototype
23 IN OUT UNIT_TEST
*Test
,
24 IN UNIT_TEST_SAVE_HEADER
*SavedState
28 This function will determine whether the short name violates any rules that would
29 prevent it from being used as a reporting name or as a serialization name.
31 Example: If the name cannot be serialized to a filesystem file name.
33 @param[in] ShortTitleString A pointer to the short title string to be evaluated.
35 @retval TRUE The string is acceptable.
36 @retval FALSE The string should not be used.
41 IsFrameworkShortNameValid (
42 IN CHAR8
*ShortTitleString
45 // TODO: Finish this function.
51 AllocateAndCopyString (
52 IN CHAR8
*StringToCopy
56 UINTN NewStringLength
;
59 NewStringLength
= AsciiStrnLenS (StringToCopy
, UNIT_TEST_MAX_STRING_LENGTH
) + 1;
60 NewString
= AllocatePool (NewStringLength
* sizeof (CHAR8
));
61 if (NewString
!= NULL
) {
62 AsciiStrCpyS (NewString
, NewStringLength
, StringToCopy
);
70 SetFrameworkFingerprint (
71 OUT UINT8
*Fingerprint
,
72 IN UNIT_TEST_FRAMEWORK
*Framework
75 UINT32 NewFingerprint
;
77 // For this one we'll just use the title and version as the unique fingerprint.
78 NewFingerprint
= CalculateCrc32 (Framework
->Title
, (AsciiStrLen (Framework
->Title
) * sizeof (CHAR8
)));
79 NewFingerprint
= (NewFingerprint
>> 8) ^ CalculateCrc32 (Framework
->VersionString
, (AsciiStrLen (Framework
->VersionString
) * sizeof (CHAR8
)));
81 CopyMem (Fingerprint
, &NewFingerprint
, UNIT_TEST_FINGERPRINT_SIZE
);
88 OUT UINT8
*Fingerprint
,
89 IN UNIT_TEST_FRAMEWORK
*Framework
,
90 IN UNIT_TEST_SUITE
*Suite
93 UINT32 NewFingerprint
;
95 // For this one, we'll use the fingerprint from the framework, and the title of the suite.
96 NewFingerprint
= CalculateCrc32 (&Framework
->Fingerprint
[0], UNIT_TEST_FINGERPRINT_SIZE
);
97 NewFingerprint
= (NewFingerprint
>> 8) ^ CalculateCrc32 (Suite
->Title
, (AsciiStrLen (Suite
->Title
) * sizeof (CHAR8
)));
98 NewFingerprint
= (NewFingerprint
>> 8) ^ CalculateCrc32 (Suite
->Name
, (AsciiStrLen (Suite
->Name
) * sizeof (CHAR8
)));
100 CopyMem (Fingerprint
, &NewFingerprint
, UNIT_TEST_FINGERPRINT_SIZE
);
107 OUT UINT8
*Fingerprint
,
108 IN UNIT_TEST_SUITE
*Suite
,
112 UINT32 NewFingerprint
;
114 // For this one, we'll use the fingerprint from the suite, and the description and classname of the test.
115 NewFingerprint
= CalculateCrc32 (&Suite
->Fingerprint
[0], UNIT_TEST_FINGERPRINT_SIZE
);
116 NewFingerprint
= (NewFingerprint
>> 8) ^ CalculateCrc32 (Test
->Description
, (AsciiStrLen (Test
->Description
) * sizeof (CHAR8
)));
117 NewFingerprint
= (NewFingerprint
>> 8) ^ CalculateCrc32 (Test
->Name
, (AsciiStrLen (Test
->Name
) * sizeof (CHAR8
)));
119 CopyMem (Fingerprint
, &NewFingerprint
, UNIT_TEST_FINGERPRINT_SIZE
);
125 CompareFingerprints (
126 IN UINT8
*FingerprintA
,
127 IN UINT8
*FingerprintB
130 return (CompareMem (FingerprintA
, FingerprintB
, UNIT_TEST_FINGERPRINT_SIZE
) == 0);
134 Cleanup a test framework.
136 After tests are run, this will teardown the entire framework and free all
137 allocated data within.
139 @param[in] FrameworkHandle A handle to the current running framework that
140 dispatched the test. Necessary for recording
141 certain test events with the framework.
143 @retval EFI_SUCCESS All resources associated with framework were
145 @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
149 FreeUnitTestFramework (
150 IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
153 // TODO: Finish this function.
159 FreeUnitTestSuiteEntry (
160 IN UNIT_TEST_SUITE_LIST_ENTRY
*SuiteEntry
163 // TODO: Finish this function.
169 FreeUnitTestTestEntry (
170 IN UNIT_TEST_LIST_ENTRY
*TestEntry
173 // TODO: Finish this function.
178 Method to Initialize the Unit Test framework. This function registers the
179 test name and also initializes the internal state of the test framework to
180 receive any new suites and tests.
182 @param[out] FrameworkHandle Unit test framework to be created.
183 @param[in] Title Null-terminated ASCII string that is the user
184 friendly name of the framework. String is
186 @param[in] ShortTitle Null-terminated ASCII short string that is the
187 short name of the framework with no spaces.
189 @param[in] VersionString Null-terminated ASCII version string for the
190 framework. String is copied.
192 @retval EFI_SUCCESS The unit test framework was initialized.
193 @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
194 @retval EFI_INVALID_PARAMETER Title is NULL.
195 @retval EFI_INVALID_PARAMETER ShortTitle is NULL.
196 @retval EFI_INVALID_PARAMETER VersionString is NULL.
197 @retval EFI_INVALID_PARAMETER ShortTitle is invalid.
198 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
199 initialize the unit test framework.
203 InitUnitTestFramework (
204 OUT UNIT_TEST_FRAMEWORK_HANDLE
*FrameworkHandle
,
206 IN CHAR8
*ShortTitle
,
207 IN CHAR8
*VersionString
211 UNIT_TEST_FRAMEWORK_HANDLE NewFrameworkHandle
;
212 UNIT_TEST_FRAMEWORK
*NewFramework
;
214 Status
= EFI_SUCCESS
;
218 // First, check all pointers and make sure nothing's broked.
220 if ((FrameworkHandle
== NULL
) || (Title
== NULL
) ||
221 (ShortTitle
== NULL
) || (VersionString
== NULL
))
223 return EFI_INVALID_PARAMETER
;
227 // Next, determine whether all of the strings are good to use.
229 if (!IsFrameworkShortNameValid (ShortTitle
)) {
230 return EFI_INVALID_PARAMETER
;
234 // Next, set aside some space to start messing with the framework.
236 NewFramework
= AllocateZeroPool (sizeof (UNIT_TEST_FRAMEWORK
));
237 if (NewFramework
== NULL
) {
238 return EFI_OUT_OF_RESOURCES
;
242 // Next, set up all the test data.
244 NewFrameworkHandle
= (UNIT_TEST_FRAMEWORK_HANDLE
)NewFramework
;
245 NewFramework
->Title
= AllocateAndCopyString (Title
);
246 NewFramework
->ShortTitle
= AllocateAndCopyString (ShortTitle
);
247 NewFramework
->VersionString
= AllocateAndCopyString (VersionString
);
248 NewFramework
->Log
= NULL
;
249 NewFramework
->CurrentTest
= NULL
;
250 NewFramework
->SavedState
= NULL
;
251 if ((NewFramework
->Title
== NULL
) ||
252 (NewFramework
->ShortTitle
== NULL
) ||
253 (NewFramework
->VersionString
== NULL
))
255 Status
= EFI_OUT_OF_RESOURCES
;
259 InitializeListHead (&(NewFramework
->TestSuiteList
));
262 // Create the framework fingerprint.
264 SetFrameworkFingerprint (&NewFramework
->Fingerprint
[0], NewFramework
);
267 // If there is a persisted context, load it now.
269 if (DoesCacheExist (NewFrameworkHandle
)) {
270 Status
= LoadUnitTestCache (NewFrameworkHandle
, (UNIT_TEST_SAVE_HEADER
**)(&NewFramework
->SavedState
));
271 if (EFI_ERROR (Status
)) {
273 // Don't actually report it as an error, but emit a warning.
275 DEBUG ((DEBUG_ERROR
, "%a - Cache was detected, but failed to load.\n", __FUNCTION__
));
276 Status
= EFI_SUCCESS
;
282 // If we're good, then let's copy the framework.
284 if (!EFI_ERROR (Status
)) {
285 *FrameworkHandle
= NewFrameworkHandle
;
288 // Otherwise, we need to undo this horrible thing that we've done.
290 FreeUnitTestFramework (NewFrameworkHandle
);
297 Registers a Unit Test Suite in the Unit Test Framework.
298 At least one test suite must be registered, because all test cases must be
299 within a unit test suite.
301 @param[out] SuiteHandle Unit test suite to create
302 @param[in] FrameworkHandle Unit test framework to add unit test suite to
303 @param[in] Title Null-terminated ASCII string that is the user
304 friendly name of the test suite. String is
306 @param[in] Name Null-terminated ASCII string that is the short
307 name of the test suite with no spaces. String
309 @param[in] Setup Setup function, runs before suite. This is an
310 optional parameter that may be NULL.
311 @param[in] Teardown Teardown function, runs after suite. This is an
312 optional parameter that may be NULL.
314 @retval EFI_SUCCESS The unit test suite was created.
315 @retval EFI_INVALID_PARAMETER SuiteHandle is NULL.
316 @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
317 @retval EFI_INVALID_PARAMETER Title is NULL.
318 @retval EFI_INVALID_PARAMETER Name is NULL.
319 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
320 initialize the unit test suite.
324 CreateUnitTestSuite (
325 OUT UNIT_TEST_SUITE_HANDLE
*SuiteHandle
,
326 IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
,
329 IN UNIT_TEST_SUITE_SETUP Setup OPTIONAL
,
330 IN UNIT_TEST_SUITE_TEARDOWN Teardown OPTIONAL
334 UNIT_TEST_SUITE_LIST_ENTRY
*NewSuiteEntry
;
335 UNIT_TEST_FRAMEWORK
*Framework
;
337 Status
= EFI_SUCCESS
;
338 Framework
= (UNIT_TEST_FRAMEWORK
*)FrameworkHandle
;
341 // First, let's check to make sure that our parameters look good.
343 if ((SuiteHandle
== NULL
) || (Framework
== NULL
) || (Title
== NULL
) || (Name
== NULL
)) {
344 return EFI_INVALID_PARAMETER
;
348 // Create the new entry.
350 NewSuiteEntry
= AllocateZeroPool (sizeof (UNIT_TEST_SUITE_LIST_ENTRY
));
351 if (NewSuiteEntry
== NULL
) {
352 return EFI_OUT_OF_RESOURCES
;
356 // Copy the fields we think we need.
358 NewSuiteEntry
->UTS
.NumTests
= 0;
359 NewSuiteEntry
->UTS
.Title
= AllocateAndCopyString (Title
);
360 NewSuiteEntry
->UTS
.Name
= AllocateAndCopyString (Name
);
361 NewSuiteEntry
->UTS
.Setup
= Setup
;
362 NewSuiteEntry
->UTS
.Teardown
= Teardown
;
363 NewSuiteEntry
->UTS
.ParentFramework
= FrameworkHandle
;
364 InitializeListHead (&(NewSuiteEntry
->Entry
)); // List entry for sibling suites.
365 InitializeListHead (&(NewSuiteEntry
->UTS
.TestCaseList
)); // List entry for child tests.
366 if (NewSuiteEntry
->UTS
.Title
== NULL
) {
367 Status
= EFI_OUT_OF_RESOURCES
;
371 if (NewSuiteEntry
->UTS
.Name
== NULL
) {
372 Status
= EFI_OUT_OF_RESOURCES
;
377 // Create the suite fingerprint.
379 SetSuiteFingerprint (&NewSuiteEntry
->UTS
.Fingerprint
[0], Framework
, &NewSuiteEntry
->UTS
);
383 // If everything is going well, add the new suite to the tail list for the framework.
385 if (!EFI_ERROR (Status
)) {
386 InsertTailList (&(Framework
->TestSuiteList
), (LIST_ENTRY
*)NewSuiteEntry
);
387 *SuiteHandle
= (UNIT_TEST_SUITE_HANDLE
)(&NewSuiteEntry
->UTS
);
390 // Otherwise, make with the destruction.
392 FreeUnitTestSuiteEntry (NewSuiteEntry
);
399 Adds test case to Suite
401 @param[in] SuiteHandle Unit test suite to add test to.
402 @param[in] Description Null-terminated ASCII string that is the user
403 friendly description of a test. String is copied.
404 @param[in] Name Null-terminated ASCII string that is the short name
405 of the test with no spaces. String is copied.
406 @param[in] Function Unit test function.
407 @param[in] Prerequisite Prerequisite function, runs before test. This is
408 an optional parameter that may be NULL.
409 @param[in] CleanUp Clean up function, runs after test. This is an
410 optional parameter that may be NULL.
411 @param[in] Context Pointer to context. This is an optional parameter
414 @retval EFI_SUCCESS The unit test case was added to Suite.
415 @retval EFI_INVALID_PARAMETER SuiteHandle is NULL.
416 @retval EFI_INVALID_PARAMETER Description is NULL.
417 @retval EFI_INVALID_PARAMETER Name is NULL.
418 @retval EFI_INVALID_PARAMETER Function is NULL.
419 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
420 add the unit test case to Suite.
425 IN UNIT_TEST_SUITE_HANDLE SuiteHandle
,
426 IN CHAR8
*Description
,
428 IN UNIT_TEST_FUNCTION Function
,
429 IN UNIT_TEST_PREREQUISITE Prerequisite OPTIONAL
,
430 IN UNIT_TEST_CLEANUP CleanUp OPTIONAL
,
431 IN UNIT_TEST_CONTEXT Context OPTIONAL
435 UNIT_TEST_LIST_ENTRY
*NewTestEntry
;
436 UNIT_TEST_FRAMEWORK
*ParentFramework
;
437 UNIT_TEST_SUITE
*Suite
;
439 Status
= EFI_SUCCESS
;
440 Suite
= (UNIT_TEST_SUITE
*)SuiteHandle
;
443 // First, let's check to make sure that our parameters look good.
445 if ((Suite
== NULL
) || (Description
== NULL
) || (Name
== NULL
) || (Function
== NULL
)) {
446 return EFI_INVALID_PARAMETER
;
449 ParentFramework
= (UNIT_TEST_FRAMEWORK
*)Suite
->ParentFramework
;
451 // Create the new entry.
452 NewTestEntry
= AllocateZeroPool (sizeof (UNIT_TEST_LIST_ENTRY
));
453 if (NewTestEntry
== NULL
) {
454 return EFI_OUT_OF_RESOURCES
;
458 // Copy the fields we think we need.
459 NewTestEntry
->UT
.Description
= AllocateAndCopyString (Description
);
460 NewTestEntry
->UT
.Name
= AllocateAndCopyString (Name
);
461 NewTestEntry
->UT
.FailureType
= FAILURETYPE_NOFAILURE
;
462 NewTestEntry
->UT
.FailureMessage
[0] = '\0';
463 NewTestEntry
->UT
.Log
= NULL
;
464 NewTestEntry
->UT
.Prerequisite
= Prerequisite
;
465 NewTestEntry
->UT
.CleanUp
= CleanUp
;
466 NewTestEntry
->UT
.RunTest
= Function
;
467 NewTestEntry
->UT
.Context
= Context
;
468 NewTestEntry
->UT
.Result
= UNIT_TEST_PENDING
;
469 NewTestEntry
->UT
.ParentSuite
= SuiteHandle
;
470 InitializeListHead (&(NewTestEntry
->Entry
)); // List entry for sibling tests.
471 if (NewTestEntry
->UT
.Description
== NULL
) {
472 Status
= EFI_OUT_OF_RESOURCES
;
476 if (NewTestEntry
->UT
.Name
== NULL
) {
477 Status
= EFI_OUT_OF_RESOURCES
;
482 // Create the test fingerprint.
484 SetTestFingerprint (&NewTestEntry
->UT
.Fingerprint
[0], Suite
, &NewTestEntry
->UT
);
486 // TODO: Make sure that duplicate fingerprints cannot be created.
489 // If there is saved test data, update this record.
491 if (ParentFramework
->SavedState
!= NULL
) {
492 UpdateTestFromSave (&NewTestEntry
->UT
, ParentFramework
->SavedState
);
497 // If everything is going well, add the new suite to the tail list for the framework.
499 if (!EFI_ERROR (Status
)) {
500 InsertTailList (&(Suite
->TestCaseList
), (LIST_ENTRY
*)NewTestEntry
);
504 // Otherwise, make with the destruction.
506 FreeUnitTestTestEntry (NewTestEntry
);
515 IN OUT UNIT_TEST
*Test
,
516 IN UNIT_TEST_SAVE_HEADER
*SavedState
519 UNIT_TEST_SAVE_TEST
*CurrentTest
;
520 UNIT_TEST_SAVE_TEST
*MatchingTest
;
521 UINT8
*FloatingPointer
;
522 UNIT_TEST_SAVE_CONTEXT
*SavedContext
;
526 // First, evaluate the inputs.
528 if ((Test
== NULL
) || (SavedState
== NULL
)) {
532 if (SavedState
->TestCount
== 0) {
537 // Next, determine whether a matching test can be found.
538 // Start at the beginning.
541 FloatingPointer
= (UINT8
*)SavedState
+ sizeof (*SavedState
);
542 for (Index
= 0; Index
< SavedState
->TestCount
; Index
++) {
543 CurrentTest
= (UNIT_TEST_SAVE_TEST
*)FloatingPointer
;
544 if (CompareFingerprints (&Test
->Fingerprint
[0], &CurrentTest
->Fingerprint
[0])) {
545 MatchingTest
= CurrentTest
;
547 // If there's a saved context, it's important that we iterate through the entire list.
549 if (!SavedState
->HasSavedContext
) {
555 // If we didn't find it, we have to increment to the next test.
557 FloatingPointer
= (UINT8
*)CurrentTest
+ CurrentTest
->Size
;
561 // If a matching test was found, copy the status.
565 // Override the test status with the saved status.
567 Test
->Result
= MatchingTest
->Result
;
569 Test
->FailureType
= MatchingTest
->FailureType
;
571 &Test
->FailureMessage
[0],
572 UNIT_TEST_TESTFAILUREMSG_LENGTH
,
573 &MatchingTest
->FailureMessage
[0],
574 UNIT_TEST_TESTFAILUREMSG_LENGTH
578 // If there is a log string associated, grab that.
579 // We can tell that there's a log string because the "size" will be larger than
580 // the structure size.
581 // IMPORTANT NOTE: There are security implications here.
582 // This data is user-supplied and we're about to play kinda
583 // fast and loose with data buffers.
585 if (MatchingTest
->Size
> sizeof (UNIT_TEST_SAVE_TEST
)) {
586 UnitTestLogInit (Test
, (UINT8
*)MatchingTest
->Log
, MatchingTest
->Size
- sizeof (UNIT_TEST_SAVE_TEST
));
591 // If the saved context exists and matches this test, grab it, too.
593 if (SavedState
->HasSavedContext
) {
595 // If there was a saved context, the "matching test" loop will have placed the FloatingPointer
596 // at the beginning of the context structure.
598 SavedContext
= (UNIT_TEST_SAVE_CONTEXT
*)FloatingPointer
;
599 if (((SavedContext
->Size
- sizeof (UNIT_TEST_SAVE_CONTEXT
)) > 0) &&
600 CompareFingerprints (&Test
->Fingerprint
[0], &SavedContext
->Fingerprint
[0]))
603 // Override the test context with the saved context.
605 Test
->Context
= (VOID
*)SavedContext
->Data
;
611 UNIT_TEST_SAVE_HEADER
*
613 IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
,
614 IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL
,
615 IN UINTN ContextToSaveSize
618 UNIT_TEST_FRAMEWORK
*Framework
;
619 UNIT_TEST_SAVE_HEADER
*Header
;
620 LIST_ENTRY
*SuiteListHead
;
622 LIST_ENTRY
*TestListHead
;
627 UNIT_TEST_SAVE_TEST
*TestSaveData
;
628 UNIT_TEST_SAVE_CONTEXT
*TestSaveContext
;
630 UINT8
*FloatingPointer
;
632 Framework
= (UNIT_TEST_FRAMEWORK
*)FrameworkHandle
;
636 // First, let's not make assumptions about the parameters.
638 if ((Framework
== NULL
) ||
639 ((ContextToSave
!= NULL
) && (ContextToSaveSize
== 0)) ||
640 (ContextToSaveSize
> MAX_UINT32
))
646 // Next, we've gotta figure out the resources that will be required to serialize the
647 // the framework state so that we can persist it.
648 // To start with, we're gonna need a header.
650 TotalSize
= sizeof (UNIT_TEST_SAVE_HEADER
);
652 // Now we need to figure out how many tests there are.
656 // Iterate all suites.
658 SuiteListHead
= &Framework
->TestSuiteList
;
659 for (Suite
= GetFirstNode (SuiteListHead
); Suite
!= SuiteListHead
; Suite
= GetNextNode (SuiteListHead
, Suite
)) {
661 // Iterate all tests within the suite.
663 TestListHead
= &((UNIT_TEST_SUITE_LIST_ENTRY
*)Suite
)->UTS
.TestCaseList
;
664 for (Test
= GetFirstNode (TestListHead
); Test
!= TestListHead
; Test
= GetNextNode (TestListHead
, Test
)) {
665 UnitTest
= &((UNIT_TEST_LIST_ENTRY
*)Test
)->UT
;
667 // Account for the size of a test structure.
669 TotalSize
+= sizeof (UNIT_TEST_SAVE_TEST
);
671 // If there's a log, make sure to account for the log size.
673 if (UnitTest
->Log
!= NULL
) {
675 // The +1 is for the NULL character. Can't forget the NULL character.
677 LogSize
= (AsciiStrLen (UnitTest
->Log
) + 1) * sizeof (CHAR8
);
678 ASSERT (LogSize
< MAX_UINT32
);
679 TotalSize
+= (UINT32
)LogSize
;
683 // Increment the test count.
690 // If there are no tests, we're done here.
692 if (TestCount
== 0) {
697 // Add room for the context, if there is one.
699 if (ContextToSave
!= NULL
) {
700 TotalSize
+= sizeof (UNIT_TEST_SAVE_CONTEXT
) + (UINT32
)ContextToSaveSize
;
704 // Now that we know the size, we need to allocate space for the serialized output.
706 Header
= AllocateZeroPool (TotalSize
);
707 if (Header
== NULL
) {
712 // Alright, let's start setting up some data.
714 Header
->Version
= UNIT_TEST_PERSISTENCE_LIB_VERSION
;
715 Header
->SaveStateSize
= TotalSize
;
716 CopyMem (&Header
->Fingerprint
[0], &Framework
->Fingerprint
[0], UNIT_TEST_FINGERPRINT_SIZE
);
717 CopyMem (&Header
->StartTime
, &Framework
->StartTime
, sizeof (EFI_TIME
));
718 Header
->TestCount
= TestCount
;
719 Header
->HasSavedContext
= FALSE
;
722 // Start adding all of the test cases.
723 // Set the floating pointer to the start of the current test save buffer.
725 FloatingPointer
= (UINT8
*)Header
+ sizeof (UNIT_TEST_SAVE_HEADER
);
727 // Iterate all suites.
729 SuiteListHead
= &Framework
->TestSuiteList
;
730 for (Suite
= GetFirstNode (SuiteListHead
); Suite
!= SuiteListHead
; Suite
= GetNextNode (SuiteListHead
, Suite
)) {
732 // Iterate all tests within the suite.
734 TestListHead
= &((UNIT_TEST_SUITE_LIST_ENTRY
*)Suite
)->UTS
.TestCaseList
;
735 for (Test
= GetFirstNode (TestListHead
); Test
!= TestListHead
; Test
= GetNextNode (TestListHead
, Test
)) {
736 TestSaveData
= (UNIT_TEST_SAVE_TEST
*)FloatingPointer
;
737 UnitTest
= &((UNIT_TEST_LIST_ENTRY
*)Test
)->UT
;
740 // Save the fingerprint.
742 CopyMem (&TestSaveData
->Fingerprint
[0], &UnitTest
->Fingerprint
[0], UNIT_TEST_FINGERPRINT_SIZE
);
747 TestSaveData
->Result
= UnitTest
->Result
;
748 TestSaveData
->FailureType
= UnitTest
->FailureType
;
749 AsciiStrnCpyS (&TestSaveData
->FailureMessage
[0], UNIT_TEST_TESTFAILUREMSG_LENGTH
, &UnitTest
->FailureMessage
[0], UNIT_TEST_TESTFAILUREMSG_LENGTH
);
752 // If there is a log, save the log.
754 FloatingPointer
+= sizeof (UNIT_TEST_SAVE_TEST
);
755 if (UnitTest
->Log
!= NULL
) {
757 // The +1 is for the NULL character. Can't forget the NULL character.
759 LogSize
= (AsciiStrLen (UnitTest
->Log
) + 1) * sizeof (CHAR8
);
760 CopyMem (FloatingPointer
, UnitTest
->Log
, LogSize
);
761 FloatingPointer
+= LogSize
;
765 // Update the size once the structure is complete.
766 // NOTE: Should this be a straight cast without validation?
768 TestSaveData
->Size
= (UINT32
)(FloatingPointer
- (UINT8
*)TestSaveData
);
773 // If there is a context to save, let's do that now.
775 if ((ContextToSave
!= NULL
) && (Framework
->CurrentTest
!= NULL
)) {
776 TestSaveContext
= (UNIT_TEST_SAVE_CONTEXT
*)FloatingPointer
;
777 TestSaveContext
->Size
= (UINT32
)ContextToSaveSize
+ sizeof (UNIT_TEST_SAVE_CONTEXT
);
778 CopyMem (&TestSaveContext
->Fingerprint
[0], &Framework
->CurrentTest
->Fingerprint
[0], UNIT_TEST_FINGERPRINT_SIZE
);
779 CopyMem (((UINT8
*)TestSaveContext
+ sizeof (UNIT_TEST_SAVE_CONTEXT
)), ContextToSave
, ContextToSaveSize
);
780 Header
->HasSavedContext
= TRUE
;
787 Leverages a framework-specific mechanism (see UnitTestPersistenceLib if you're
788 a framework author) to save the state of the executing framework along with
789 any allocated data so that the test may be resumed upon reentry. A test case
790 should pass any needed context (which, to prevent an infinite loop, should be
791 at least the current execution count) which will be saved by the framework and
792 passed to the test case upon resume.
794 This should be called while the current test framework is valid and active. It is
795 generally called from within a test case prior to quitting or rebooting.
797 @param[in] ContextToSave A buffer of test case-specific data to be saved
798 along with framework state. Will be passed as
799 "Context" to the test case upon resume. This
800 is an optional parameter that may be NULL.
801 @param[in] ContextToSaveSize Size of the ContextToSave buffer.
803 @retval EFI_SUCCESS The framework state and context were saved.
804 @retval EFI_NOT_FOUND An active framework handle was not found.
805 @retval EFI_INVALID_PARAMETER ContextToSave is not NULL and
806 ContextToSaveSize is 0.
807 @retval EFI_INVALID_PARAMETER ContextToSave is >= 4GB.
808 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
809 save the framework and context state.
810 @retval EFI_DEVICE_ERROR The framework and context state could not be
811 saved to a persistent storage device due to a
817 IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL
,
818 IN UINTN ContextToSaveSize
822 UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
;
823 UNIT_TEST_SAVE_HEADER
*Header
;
826 FrameworkHandle
= GetActiveFrameworkHandle ();
829 // Return a unique error code if the framework is not set.
831 if (FrameworkHandle
== NULL
) {
832 return EFI_NOT_FOUND
;
836 // First, let's not make assumptions about the parameters.
838 if (((ContextToSave
!= NULL
) && (ContextToSaveSize
== 0)) ||
839 (ContextToSaveSize
> MAX_UINT32
))
841 return EFI_INVALID_PARAMETER
;
845 // Now, let's package up all the data for saving.
847 Header
= SerializeState (FrameworkHandle
, ContextToSave
, ContextToSaveSize
);
848 if (Header
== NULL
) {
849 return EFI_OUT_OF_RESOURCES
;
853 // All that should be left to do is save it using the associated persistence lib.
855 Status
= SaveUnitTestCache (FrameworkHandle
, Header
);
856 if (EFI_ERROR (Status
)) {
857 DEBUG ((DEBUG_ERROR
, "%a - Could not save state! %r\n", __FUNCTION__
, Status
));
858 Status
= EFI_DEVICE_ERROR
;
862 // Free data that was used.