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
);
69 SetFrameworkFingerprint (
70 OUT UINT8
*Fingerprint
,
71 IN UNIT_TEST_FRAMEWORK
*Framework
74 UINT32 NewFingerprint
;
76 // For this one we'll just use the title and version as the unique fingerprint.
77 NewFingerprint
= CalculateCrc32( Framework
->Title
, (AsciiStrLen( Framework
->Title
) * sizeof( CHAR8
)) );
78 NewFingerprint
= (NewFingerprint
>> 8) ^ CalculateCrc32( Framework
->VersionString
, (AsciiStrLen( Framework
->VersionString
) * sizeof( CHAR8
)) );
80 CopyMem( Fingerprint
, &NewFingerprint
, UNIT_TEST_FINGERPRINT_SIZE
);
87 OUT UINT8
*Fingerprint
,
88 IN UNIT_TEST_FRAMEWORK
*Framework
,
89 IN UNIT_TEST_SUITE
*Suite
92 UINT32 NewFingerprint
;
94 // For this one, we'll use the fingerprint from the framework, and the title of the suite.
95 NewFingerprint
= CalculateCrc32( &Framework
->Fingerprint
[0], UNIT_TEST_FINGERPRINT_SIZE
);
96 NewFingerprint
= (NewFingerprint
>> 8) ^ CalculateCrc32( Suite
->Title
, (AsciiStrLen( Suite
->Title
) * sizeof( CHAR8
)) );
97 NewFingerprint
= (NewFingerprint
>> 8) ^ CalculateCrc32( Suite
->Name
, (AsciiStrLen(Suite
->Name
) * sizeof(CHAR8
)) );
99 CopyMem( Fingerprint
, &NewFingerprint
, UNIT_TEST_FINGERPRINT_SIZE
);
106 OUT UINT8
*Fingerprint
,
107 IN UNIT_TEST_SUITE
*Suite
,
111 UINT32 NewFingerprint
;
113 // For this one, we'll use the fingerprint from the suite, and the description and classname of the test.
114 NewFingerprint
= CalculateCrc32( &Suite
->Fingerprint
[0], UNIT_TEST_FINGERPRINT_SIZE
);
115 NewFingerprint
= (NewFingerprint
>> 8) ^ CalculateCrc32( Test
->Description
, (AsciiStrLen( Test
->Description
) * sizeof( CHAR8
)) );
116 NewFingerprint
= (NewFingerprint
>> 8) ^ CalculateCrc32( Test
->Name
, (AsciiStrLen(Test
->Name
) * sizeof(CHAR8
)) );
118 CopyMem( Fingerprint
, &NewFingerprint
, UNIT_TEST_FINGERPRINT_SIZE
);
124 CompareFingerprints (
125 IN UINT8
*FingerprintA
,
126 IN UINT8
*FingerprintB
129 return (CompareMem( FingerprintA
, FingerprintB
, UNIT_TEST_FINGERPRINT_SIZE
) == 0);
133 Cleanup a test framework.
135 After tests are run, this will teardown the entire framework and free all
136 allocated data within.
138 @param[in] FrameworkHandle A handle to the current running framework that
139 dispatched the test. Necessary for recording
140 certain test events with the framework.
142 @retval EFI_SUCCESS All resources associated with framework were
144 @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
148 FreeUnitTestFramework (
149 IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
152 // TODO: Finish this function.
158 FreeUnitTestSuiteEntry (
159 IN UNIT_TEST_SUITE_LIST_ENTRY
*SuiteEntry
162 // TODO: Finish this function.
168 FreeUnitTestTestEntry (
169 IN UNIT_TEST_LIST_ENTRY
*TestEntry
172 // TODO: Finish this function.
177 Method to Initialize the Unit Test framework. This function registers the
178 test name and also initializes the internal state of the test framework to
179 receive any new suites and tests.
181 @param[out] FrameworkHandle Unit test framework to be created.
182 @param[in] Title Null-terminated ASCII string that is the user
183 friendly name of the framework. String is
185 @param[in] ShortTitle Null-terminated ASCII short string that is the
186 short name of the framework with no spaces.
188 @param[in] VersionString Null-terminated ASCII version string for the
189 framework. String is copied.
191 @retval EFI_SUCCESS The unit test framework was initialized.
192 @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
193 @retval EFI_INVALID_PARAMETER Title is NULL.
194 @retval EFI_INVALID_PARAMETER ShortTitle is NULL.
195 @retval EFI_INVALID_PARAMETER VersionString is NULL.
196 @retval EFI_INVALID_PARAMETER ShortTitle is invalid.
197 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
198 initialize the unit test framework.
202 InitUnitTestFramework (
203 OUT UNIT_TEST_FRAMEWORK_HANDLE
*FrameworkHandle
,
205 IN CHAR8
*ShortTitle
,
206 IN CHAR8
*VersionString
210 UNIT_TEST_FRAMEWORK_HANDLE NewFrameworkHandle
;
211 UNIT_TEST_FRAMEWORK
*NewFramework
;
213 Status
= EFI_SUCCESS
;
217 // First, check all pointers and make sure nothing's broked.
219 if (FrameworkHandle
== NULL
|| Title
== NULL
||
220 ShortTitle
== NULL
|| VersionString
== NULL
) {
221 return EFI_INVALID_PARAMETER
;
225 // Next, determine whether all of the strings are good to use.
227 if (!IsFrameworkShortNameValid (ShortTitle
)) {
228 return EFI_INVALID_PARAMETER
;
232 // Next, set aside some space to start messing with the framework.
234 NewFramework
= AllocateZeroPool (sizeof (UNIT_TEST_FRAMEWORK
));
235 if (NewFramework
== NULL
) {
236 return EFI_OUT_OF_RESOURCES
;
240 // Next, set up all the test data.
242 NewFrameworkHandle
= (UNIT_TEST_FRAMEWORK_HANDLE
)NewFramework
;
243 NewFramework
->Title
= AllocateAndCopyString (Title
);
244 NewFramework
->ShortTitle
= AllocateAndCopyString (ShortTitle
);
245 NewFramework
->VersionString
= AllocateAndCopyString (VersionString
);
246 NewFramework
->Log
= NULL
;
247 NewFramework
->CurrentTest
= NULL
;
248 NewFramework
->SavedState
= NULL
;
249 if (NewFramework
->Title
== NULL
||
250 NewFramework
->ShortTitle
== NULL
||
251 NewFramework
->VersionString
== NULL
) {
252 Status
= EFI_OUT_OF_RESOURCES
;
255 InitializeListHead (&(NewFramework
->TestSuiteList
));
258 // Create the framework fingerprint.
260 SetFrameworkFingerprint (&NewFramework
->Fingerprint
[0], NewFramework
);
263 // If there is a persisted context, load it now.
265 if (DoesCacheExist (NewFrameworkHandle
)) {
266 Status
= LoadUnitTestCache (NewFrameworkHandle
, (UNIT_TEST_SAVE_HEADER
**)(&NewFramework
->SavedState
));
267 if (EFI_ERROR (Status
)) {
269 // Don't actually report it as an error, but emit a warning.
271 DEBUG (( DEBUG_ERROR
, "%a - Cache was detected, but failed to load.\n", __FUNCTION__
));
272 Status
= EFI_SUCCESS
;
278 // If we're good, then let's copy the framework.
280 if (!EFI_ERROR (Status
)) {
281 *FrameworkHandle
= NewFrameworkHandle
;
284 // Otherwise, we need to undo this horrible thing that we've done.
286 FreeUnitTestFramework (NewFrameworkHandle
);
293 Registers a Unit Test Suite in the Unit Test Framework.
294 At least one test suite must be registered, because all test cases must be
295 within a unit test suite.
297 @param[out] SuiteHandle Unit test suite to create
298 @param[in] FrameworkHandle Unit test framework to add unit test suite to
299 @param[in] Title Null-terminated ASCII string that is the user
300 friendly name of the test suite. String is
302 @param[in] Name Null-terminated ASCII string that is the short
303 name of the test suite with no spaces. String
305 @param[in] Setup Setup function, runs before suite. This is an
306 optional parameter that may be NULL.
307 @param[in] Teardown Teardown function, runs after suite. This is an
308 optional parameter that may be NULL.
310 @retval EFI_SUCCESS The unit test suite was created.
311 @retval EFI_INVALID_PARAMETER SuiteHandle is NULL.
312 @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
313 @retval EFI_INVALID_PARAMETER Title is NULL.
314 @retval EFI_INVALID_PARAMETER Name is NULL.
315 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
316 initialize the unit test suite.
320 CreateUnitTestSuite (
321 OUT UNIT_TEST_SUITE_HANDLE
*SuiteHandle
,
322 IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
,
325 IN UNIT_TEST_SUITE_SETUP Setup OPTIONAL
,
326 IN UNIT_TEST_SUITE_TEARDOWN Teardown OPTIONAL
330 UNIT_TEST_SUITE_LIST_ENTRY
*NewSuiteEntry
;
331 UNIT_TEST_FRAMEWORK
*Framework
;
333 Status
= EFI_SUCCESS
;
334 Framework
= (UNIT_TEST_FRAMEWORK
*)FrameworkHandle
;
337 // First, let's check to make sure that our parameters look good.
339 if ((SuiteHandle
== NULL
) || (Framework
== NULL
) || (Title
== NULL
) || (Name
== NULL
)) {
340 return EFI_INVALID_PARAMETER
;
344 // Create the new entry.
346 NewSuiteEntry
= AllocateZeroPool (sizeof (UNIT_TEST_SUITE_LIST_ENTRY
));
347 if (NewSuiteEntry
== NULL
) {
348 return EFI_OUT_OF_RESOURCES
;
352 // Copy the fields we think we need.
354 NewSuiteEntry
->UTS
.NumTests
= 0;
355 NewSuiteEntry
->UTS
.Title
= AllocateAndCopyString (Title
);
356 NewSuiteEntry
->UTS
.Name
= AllocateAndCopyString (Name
);
357 NewSuiteEntry
->UTS
.Setup
= Setup
;
358 NewSuiteEntry
->UTS
.Teardown
= Teardown
;
359 NewSuiteEntry
->UTS
.ParentFramework
= FrameworkHandle
;
360 InitializeListHead (&(NewSuiteEntry
->Entry
)); // List entry for sibling suites.
361 InitializeListHead (&(NewSuiteEntry
->UTS
.TestCaseList
)); // List entry for child tests.
362 if (NewSuiteEntry
->UTS
.Title
== NULL
) {
363 Status
= EFI_OUT_OF_RESOURCES
;
367 if (NewSuiteEntry
->UTS
.Name
== NULL
) {
368 Status
= EFI_OUT_OF_RESOURCES
;
373 // Create the suite fingerprint.
375 SetSuiteFingerprint( &NewSuiteEntry
->UTS
.Fingerprint
[0], Framework
, &NewSuiteEntry
->UTS
);
379 // If everything is going well, add the new suite to the tail list for the framework.
381 if (!EFI_ERROR( Status
)) {
382 InsertTailList (&(Framework
->TestSuiteList
), (LIST_ENTRY
*)NewSuiteEntry
);
383 *SuiteHandle
= (UNIT_TEST_SUITE_HANDLE
)(&NewSuiteEntry
->UTS
);
386 // Otherwise, make with the destruction.
388 FreeUnitTestSuiteEntry (NewSuiteEntry
);
395 Adds test case to Suite
397 @param[in] SuiteHandle Unit test suite to add test to.
398 @param[in] Description Null-terminated ASCII string that is the user
399 friendly description of a test. String is copied.
400 @param[in] Name Null-terminated ASCII string that is the short name
401 of the test with no spaces. String is copied.
402 @param[in] Function Unit test function.
403 @param[in] Prerequisite Prerequisite function, runs before test. This is
404 an optional parameter that may be NULL.
405 @param[in] CleanUp Clean up function, runs after test. This is an
406 optional parameter that may be NULL.
407 @param[in] Context Pointer to context. This is an optional parameter
410 @retval EFI_SUCCESS The unit test case was added to Suite.
411 @retval EFI_INVALID_PARAMETER SuiteHandle is NULL.
412 @retval EFI_INVALID_PARAMETER Description is NULL.
413 @retval EFI_INVALID_PARAMETER Name is NULL.
414 @retval EFI_INVALID_PARAMETER Function is NULL.
415 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
416 add the unit test case to Suite.
421 IN UNIT_TEST_SUITE_HANDLE SuiteHandle
,
422 IN CHAR8
*Description
,
424 IN UNIT_TEST_FUNCTION Function
,
425 IN UNIT_TEST_PREREQUISITE Prerequisite OPTIONAL
,
426 IN UNIT_TEST_CLEANUP CleanUp OPTIONAL
,
427 IN UNIT_TEST_CONTEXT Context OPTIONAL
431 UNIT_TEST_LIST_ENTRY
*NewTestEntry
;
432 UNIT_TEST_FRAMEWORK
*ParentFramework
;
433 UNIT_TEST_SUITE
*Suite
;
435 Status
= EFI_SUCCESS
;
436 Suite
= (UNIT_TEST_SUITE
*)SuiteHandle
;
439 // First, let's check to make sure that our parameters look good.
441 if ((Suite
== NULL
) || (Description
== NULL
) || (Name
== NULL
) || (Function
== NULL
)) {
442 return EFI_INVALID_PARAMETER
;
445 ParentFramework
= (UNIT_TEST_FRAMEWORK
*)Suite
->ParentFramework
;
447 // Create the new entry.
448 NewTestEntry
= AllocateZeroPool (sizeof( UNIT_TEST_LIST_ENTRY
));
449 if (NewTestEntry
== NULL
) {
450 return EFI_OUT_OF_RESOURCES
;
454 // Copy the fields we think we need.
455 NewTestEntry
->UT
.Description
= AllocateAndCopyString (Description
);
456 NewTestEntry
->UT
.Name
= AllocateAndCopyString (Name
);
457 NewTestEntry
->UT
.FailureType
= FAILURETYPE_NOFAILURE
;
458 NewTestEntry
->UT
.FailureMessage
[0] = '\0';
459 NewTestEntry
->UT
.Log
= NULL
;
460 NewTestEntry
->UT
.Prerequisite
= Prerequisite
;
461 NewTestEntry
->UT
.CleanUp
= CleanUp
;
462 NewTestEntry
->UT
.RunTest
= Function
;
463 NewTestEntry
->UT
.Context
= Context
;
464 NewTestEntry
->UT
.Result
= UNIT_TEST_PENDING
;
465 NewTestEntry
->UT
.ParentSuite
= SuiteHandle
;
466 InitializeListHead (&(NewTestEntry
->Entry
)); // List entry for sibling tests.
467 if (NewTestEntry
->UT
.Description
== NULL
) {
468 Status
= EFI_OUT_OF_RESOURCES
;
471 if (NewTestEntry
->UT
.Name
== NULL
) {
472 Status
= EFI_OUT_OF_RESOURCES
;
477 // Create the test fingerprint.
479 SetTestFingerprint (&NewTestEntry
->UT
.Fingerprint
[0], Suite
, &NewTestEntry
->UT
);
481 // TODO: Make sure that duplicate fingerprints cannot be created.
484 // If there is saved test data, update this record.
486 if (ParentFramework
->SavedState
!= NULL
) {
487 UpdateTestFromSave (&NewTestEntry
->UT
, ParentFramework
->SavedState
);
492 // If everything is going well, add the new suite to the tail list for the framework.
494 if (!EFI_ERROR (Status
)) {
495 InsertTailList (&(Suite
->TestCaseList
), (LIST_ENTRY
*)NewTestEntry
);
499 // Otherwise, make with the destruction.
501 FreeUnitTestTestEntry (NewTestEntry
);
510 IN OUT UNIT_TEST
*Test
,
511 IN UNIT_TEST_SAVE_HEADER
*SavedState
514 UNIT_TEST_SAVE_TEST
*CurrentTest
;
515 UNIT_TEST_SAVE_TEST
*MatchingTest
;
516 UINT8
*FloatingPointer
;
517 UNIT_TEST_SAVE_CONTEXT
*SavedContext
;
521 // First, evaluate the inputs.
523 if (Test
== NULL
|| SavedState
== NULL
) {
526 if (SavedState
->TestCount
== 0) {
531 // Next, determine whether a matching test can be found.
532 // Start at the beginning.
535 FloatingPointer
= (UINT8
*)SavedState
+ sizeof (*SavedState
);
536 for (Index
= 0; Index
< SavedState
->TestCount
; Index
++) {
537 CurrentTest
= (UNIT_TEST_SAVE_TEST
*)FloatingPointer
;
538 if (CompareFingerprints (&Test
->Fingerprint
[0], &CurrentTest
->Fingerprint
[0])) {
539 MatchingTest
= CurrentTest
;
541 // If there's a saved context, it's important that we iterate through the entire list.
543 if (!SavedState
->HasSavedContext
) {
549 // If we didn't find it, we have to increment to the next test.
551 FloatingPointer
= (UINT8
*)CurrentTest
+ CurrentTest
->Size
;
555 // If a matching test was found, copy the status.
559 // Override the test status with the saved status.
561 Test
->Result
= MatchingTest
->Result
;
563 Test
->FailureType
= MatchingTest
->FailureType
;
565 &Test
->FailureMessage
[0],
566 UNIT_TEST_TESTFAILUREMSG_LENGTH
,
567 &MatchingTest
->FailureMessage
[0],
568 UNIT_TEST_TESTFAILUREMSG_LENGTH
572 // If there is a log string associated, grab that.
573 // We can tell that there's a log string because the "size" will be larger than
574 // the structure size.
575 // IMPORTANT NOTE: There are security implications here.
576 // This data is user-supplied and we're about to play kinda
577 // fast and loose with data buffers.
579 if (MatchingTest
->Size
> sizeof (UNIT_TEST_SAVE_TEST
)) {
580 UnitTestLogInit (Test
, (UINT8
*)MatchingTest
->Log
, MatchingTest
->Size
- sizeof (UNIT_TEST_SAVE_TEST
));
585 // If the saved context exists and matches this test, grab it, too.
587 if (SavedState
->HasSavedContext
) {
589 // If there was a saved context, the "matching test" loop will have placed the FloatingPointer
590 // at the beginning of the context structure.
592 SavedContext
= (UNIT_TEST_SAVE_CONTEXT
*)FloatingPointer
;
593 if ((SavedContext
->Size
- sizeof (UNIT_TEST_SAVE_CONTEXT
)) > 0 &&
594 CompareFingerprints (&Test
->Fingerprint
[0], &SavedContext
->Fingerprint
[0])) {
596 // Override the test context with the saved context.
598 Test
->Context
= (VOID
*)SavedContext
->Data
;
604 UNIT_TEST_SAVE_HEADER
*
606 IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
,
607 IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL
,
608 IN UINTN ContextToSaveSize
611 UNIT_TEST_FRAMEWORK
*Framework
;
612 UNIT_TEST_SAVE_HEADER
*Header
;
613 LIST_ENTRY
*SuiteListHead
;
615 LIST_ENTRY
*TestListHead
;
620 UNIT_TEST_SAVE_TEST
*TestSaveData
;
621 UNIT_TEST_SAVE_CONTEXT
*TestSaveContext
;
623 UINT8
*FloatingPointer
;
625 Framework
= (UNIT_TEST_FRAMEWORK
*)FrameworkHandle
;
629 // First, let's not make assumptions about the parameters.
631 if (Framework
== NULL
||
632 (ContextToSave
!= NULL
&& ContextToSaveSize
== 0) ||
633 ContextToSaveSize
> MAX_UINT32
) {
638 // Next, we've gotta figure out the resources that will be required to serialize the
639 // the framework state so that we can persist it.
640 // To start with, we're gonna need a header.
642 TotalSize
= sizeof (UNIT_TEST_SAVE_HEADER
);
644 // Now we need to figure out how many tests there are.
648 // Iterate all suites.
650 SuiteListHead
= &Framework
->TestSuiteList
;
651 for (Suite
= GetFirstNode (SuiteListHead
); Suite
!= SuiteListHead
; Suite
= GetNextNode (SuiteListHead
, Suite
)) {
653 // Iterate all tests within the suite.
655 TestListHead
= &((UNIT_TEST_SUITE_LIST_ENTRY
*)Suite
)->UTS
.TestCaseList
;
656 for (Test
= GetFirstNode (TestListHead
); Test
!= TestListHead
; Test
= GetNextNode (TestListHead
, Test
)) {
657 UnitTest
= &((UNIT_TEST_LIST_ENTRY
*)Test
)->UT
;
659 // Account for the size of a test structure.
661 TotalSize
+= sizeof( UNIT_TEST_SAVE_TEST
);
663 // If there's a log, make sure to account for the log size.
665 if (UnitTest
->Log
!= NULL
) {
667 // The +1 is for the NULL character. Can't forget the NULL character.
669 LogSize
= (AsciiStrLen (UnitTest
->Log
) + 1) * sizeof (CHAR8
);
670 ASSERT (LogSize
< MAX_UINT32
);
671 TotalSize
+= (UINT32
)LogSize
;
674 // Increment the test count.
680 // If there are no tests, we're done here.
682 if (TestCount
== 0) {
686 // Add room for the context, if there is one.
688 if (ContextToSave
!= NULL
) {
689 TotalSize
+= sizeof (UNIT_TEST_SAVE_CONTEXT
) + (UINT32
)ContextToSaveSize
;
693 // Now that we know the size, we need to allocate space for the serialized output.
695 Header
= AllocateZeroPool (TotalSize
);
696 if (Header
== NULL
) {
701 // Alright, let's start setting up some data.
703 Header
->Version
= UNIT_TEST_PERSISTENCE_LIB_VERSION
;
704 Header
->SaveStateSize
= TotalSize
;
705 CopyMem (&Header
->Fingerprint
[0], &Framework
->Fingerprint
[0], UNIT_TEST_FINGERPRINT_SIZE
);
706 CopyMem (&Header
->StartTime
, &Framework
->StartTime
, sizeof (EFI_TIME
));
707 Header
->TestCount
= TestCount
;
708 Header
->HasSavedContext
= FALSE
;
711 // Start adding all of the test cases.
712 // Set the floating pointer to the start of the current test save buffer.
714 FloatingPointer
= (UINT8
*)Header
+ sizeof( UNIT_TEST_SAVE_HEADER
);
716 // Iterate all suites.
718 SuiteListHead
= &Framework
->TestSuiteList
;
719 for (Suite
= GetFirstNode (SuiteListHead
); Suite
!= SuiteListHead
; Suite
= GetNextNode (SuiteListHead
, Suite
)) {
721 // Iterate all tests within the suite.
723 TestListHead
= &((UNIT_TEST_SUITE_LIST_ENTRY
*)Suite
)->UTS
.TestCaseList
;
724 for (Test
= GetFirstNode (TestListHead
); Test
!= TestListHead
; Test
= GetNextNode (TestListHead
, Test
)) {
725 TestSaveData
= (UNIT_TEST_SAVE_TEST
*)FloatingPointer
;
726 UnitTest
= &((UNIT_TEST_LIST_ENTRY
*)Test
)->UT
;
729 // Save the fingerprint.
731 CopyMem (&TestSaveData
->Fingerprint
[0], &UnitTest
->Fingerprint
[0], UNIT_TEST_FINGERPRINT_SIZE
);
736 TestSaveData
->Result
= UnitTest
->Result
;
737 TestSaveData
->FailureType
= UnitTest
->FailureType
;
738 AsciiStrnCpyS (&TestSaveData
->FailureMessage
[0], UNIT_TEST_TESTFAILUREMSG_LENGTH
, &UnitTest
->FailureMessage
[0], UNIT_TEST_TESTFAILUREMSG_LENGTH
);
742 // If there is a log, save the log.
744 FloatingPointer
+= sizeof (UNIT_TEST_SAVE_TEST
);
745 if (UnitTest
->Log
!= NULL
) {
747 // The +1 is for the NULL character. Can't forget the NULL character.
749 LogSize
= (AsciiStrLen (UnitTest
->Log
) + 1) * sizeof (CHAR8
);
750 CopyMem (FloatingPointer
, UnitTest
->Log
, LogSize
);
751 FloatingPointer
+= LogSize
;
755 // Update the size once the structure is complete.
756 // NOTE: Should this be a straight cast without validation?
758 TestSaveData
->Size
= (UINT32
)(FloatingPointer
- (UINT8
*)TestSaveData
);
763 // If there is a context to save, let's do that now.
765 if (ContextToSave
!= NULL
&& Framework
->CurrentTest
!= NULL
) {
766 TestSaveContext
= (UNIT_TEST_SAVE_CONTEXT
*)FloatingPointer
;
767 TestSaveContext
->Size
= (UINT32
)ContextToSaveSize
+ sizeof (UNIT_TEST_SAVE_CONTEXT
);
768 CopyMem (&TestSaveContext
->Fingerprint
[0], &Framework
->CurrentTest
->Fingerprint
[0], UNIT_TEST_FINGERPRINT_SIZE
);
769 CopyMem (((UINT8
*)TestSaveContext
+ sizeof (UNIT_TEST_SAVE_CONTEXT
)), ContextToSave
, ContextToSaveSize
);
770 Header
->HasSavedContext
= TRUE
;
777 Leverages a framework-specific mechanism (see UnitTestPersistenceLib if you're
778 a framework author) to save the state of the executing framework along with
779 any allocated data so that the test may be resumed upon reentry. A test case
780 should pass any needed context (which, to prevent an infinite loop, should be
781 at least the current execution count) which will be saved by the framework and
782 passed to the test case upon resume.
784 This should be called while the current test framework is valid and active. It is
785 generally called from within a test case prior to quitting or rebooting.
787 @param[in] ContextToSave A buffer of test case-specific data to be saved
788 along with framework state. Will be passed as
789 "Context" to the test case upon resume. This
790 is an optional parameter that may be NULL.
791 @param[in] ContextToSaveSize Size of the ContextToSave buffer.
793 @retval EFI_SUCCESS The framework state and context were saved.
794 @retval EFI_NOT_FOUND An active framework handle was not found.
795 @retval EFI_INVALID_PARAMETER ContextToSave is not NULL and
796 ContextToSaveSize is 0.
797 @retval EFI_INVALID_PARAMETER ContextToSave is >= 4GB.
798 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
799 save the framework and context state.
800 @retval EFI_DEVICE_ERROR The framework and context state could not be
801 saved to a persistent storage device due to a
807 IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL
,
808 IN UINTN ContextToSaveSize
812 UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
;
813 UNIT_TEST_SAVE_HEADER
*Header
;
816 FrameworkHandle
= GetActiveFrameworkHandle ();
819 // Return a unique error code if the framework is not set.
821 if (FrameworkHandle
== NULL
) {
822 return EFI_NOT_FOUND
;
826 // First, let's not make assumptions about the parameters.
828 if ((ContextToSave
!= NULL
&& ContextToSaveSize
== 0) ||
829 ContextToSaveSize
> MAX_UINT32
) {
830 return EFI_INVALID_PARAMETER
;
834 // Now, let's package up all the data for saving.
836 Header
= SerializeState (FrameworkHandle
, ContextToSave
, ContextToSaveSize
);
837 if (Header
== NULL
) {
838 return EFI_OUT_OF_RESOURCES
;
842 // All that should be left to do is save it using the associated persistence lib.
844 Status
= SaveUnitTestCache (FrameworkHandle
, Header
);
845 if (EFI_ERROR (Status
)) {
846 DEBUG ((DEBUG_ERROR
, "%a - Could not save state! %r\n", __FUNCTION__
, Status
));
847 Status
= EFI_DEVICE_ERROR
;
851 // Free data that was used.