TianoCore EDK2 master
Loading...
Searching...
No Matches
UnitTestLib.c
1
9#include <Uefi.h>
10#include <Library/UnitTestLib.h>
11#include <Library/BaseLib.h>
14#include <Library/DebugLib.h>
17
22VOID
23UpdateTestFromSave (
25 IN UNIT_TEST_SAVE_HEADER *SavedState
26 );
27
41BOOLEAN
42IsFrameworkShortNameValid (
43 IN CHAR8 *ShortTitleString
44 )
45{
46 // TODO: Finish this function.
47 return TRUE;
48}
49
51CHAR8 *
52AllocateAndCopyString (
53 IN CHAR8 *StringToCopy
54 )
55{
56 CHAR8 *NewString;
57 UINTN NewStringLength;
58
60 NewStringLength = AsciiStrnLenS (StringToCopy, UNIT_TEST_MAX_STRING_LENGTH) + 1;
61 NewString = AllocatePool (NewStringLength * sizeof (CHAR8));
62 if (NewString != NULL) {
63 AsciiStrCpyS (NewString, NewStringLength, StringToCopy);
64 }
65
66 return NewString;
67}
68
70VOID
71SetFrameworkFingerprint (
72 OUT UINT8 *Fingerprint,
73 IN UNIT_TEST_FRAMEWORK *Framework
74 )
75{
76 UINT32 NewFingerprint;
77
78 // For this one we'll just use the title and version as the unique fingerprint.
79 NewFingerprint = CalculateCrc32 (Framework->Title, (AsciiStrLen (Framework->Title) * sizeof (CHAR8)));
80 NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Framework->VersionString, (AsciiStrLen (Framework->VersionString) * sizeof (CHAR8)));
81
82 CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE);
83 return;
84}
85
87VOID
88SetSuiteFingerprint (
89 OUT UINT8 *Fingerprint,
90 IN UNIT_TEST_FRAMEWORK *Framework,
91 IN UNIT_TEST_SUITE *Suite
92 )
93{
94 UINT32 NewFingerprint;
95
96 // For this one, we'll use the fingerprint from the framework, and the title of the suite.
97 NewFingerprint = CalculateCrc32 (&Framework->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
98 NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Suite->Title, (AsciiStrLen (Suite->Title) * sizeof (CHAR8)));
99 NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Suite->Name, (AsciiStrLen (Suite->Name) * sizeof (CHAR8)));
100
101 CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE);
102 return;
103}
104
105STATIC
106VOID
107SetTestFingerprint (
108 OUT UINT8 *Fingerprint,
109 IN UNIT_TEST_SUITE *Suite,
111 )
112{
113 UINT32 NewFingerprint;
114
115 // For this one, we'll use the fingerprint from the suite, and the description and classname of the test.
116 NewFingerprint = CalculateCrc32 (&Suite->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
117 NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Test->Description, (AsciiStrLen (Test->Description) * sizeof (CHAR8)));
118 NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Test->Name, (AsciiStrLen (Test->Name) * sizeof (CHAR8)));
119
120 CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE);
121 return;
122}
123
124STATIC
125BOOLEAN
126CompareFingerprints (
127 IN UINT8 *FingerprintA,
128 IN UINT8 *FingerprintB
129 )
130{
131 return (CompareMem (FingerprintA, FingerprintB, UNIT_TEST_FINGERPRINT_SIZE) == 0);
132}
133
134STATIC
135VOID
136FreeUnitTestTestEntry (
137 IN UNIT_TEST_LIST_ENTRY *TestEntry
138 )
139{
140 if (TestEntry) {
141 if (TestEntry->UT.Description) {
142 FreePool (TestEntry->UT.Description);
143 }
144
145 if (TestEntry->UT.Name) {
146 FreePool (TestEntry->UT.Name);
147 }
148
149 FreePool (TestEntry);
150 }
151}
152
153STATIC
155FreeUnitTestSuiteEntry (
157 )
158{
159 UNIT_TEST_LIST_ENTRY *TestCase;
160 UNIT_TEST_LIST_ENTRY *NextTestCase;
161 LIST_ENTRY *TestCaseList;
162
163 if (SuiteEntry) {
164 TestCaseList = &(SuiteEntry->UTS.TestCaseList);
165 TestCase = (UNIT_TEST_LIST_ENTRY *)GetFirstNode (TestCaseList);
166 while (&TestCase->Entry != TestCaseList) {
167 NextTestCase = (UNIT_TEST_LIST_ENTRY *)GetNextNode (TestCaseList, &TestCase->Entry);
168 RemoveEntryList (&TestCase->Entry);
169 FreeUnitTestTestEntry (TestCase);
170 TestCase = NextTestCase;
171 }
172
173 if (SuiteEntry->UTS.Title) {
174 FreePool (SuiteEntry->UTS.Title);
175 }
176
177 if (SuiteEntry->UTS.Name) {
178 FreePool (SuiteEntry->UTS.Name);
179 }
180
181 FreePool (SuiteEntry);
182 }
183
184 return EFI_SUCCESS;
185}
186
202EFIAPI
204 IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
205 )
206{
207 UNIT_TEST_FRAMEWORK *Framework;
210
211 Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
212 if (Framework) {
213 Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetFirstNode (&Framework->TestSuiteList);
214 while ((LIST_ENTRY *)Suite != &Framework->TestSuiteList) {
215 NextSuite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetNextNode (&Framework->TestSuiteList, (LIST_ENTRY *)Suite);
216 RemoveEntryList ((LIST_ENTRY *)Suite);
217 FreeUnitTestSuiteEntry (Suite);
218 Suite = NextSuite;
219 }
220
221 if (Framework->Title) {
222 FreePool (Framework->Title);
223 }
224
225 if (Framework->ShortTitle) {
226 FreePool (Framework->ShortTitle);
227 }
228
229 if (Framework->VersionString) {
230 FreePool (Framework->VersionString);
231 }
232
233 FreePool (Framework);
234 }
235
236 return EFI_SUCCESS;
237}
238
264EFIAPI
266 OUT UNIT_TEST_FRAMEWORK_HANDLE *FrameworkHandle,
267 IN CHAR8 *Title,
268 IN CHAR8 *ShortTitle,
269 IN CHAR8 *VersionString
270 )
271{
272 EFI_STATUS Status;
273 UNIT_TEST_FRAMEWORK_HANDLE NewFrameworkHandle;
274 UNIT_TEST_FRAMEWORK *NewFramework;
275 UINTN SaveStateSize;
276
277 Status = EFI_SUCCESS;
278 NewFramework = NULL;
279
280 //
281 // First, check all pointers and make sure nothing's broked.
282 //
283 if ((FrameworkHandle == NULL) || (Title == NULL) ||
284 (ShortTitle == NULL) || (VersionString == NULL))
285 {
286 return EFI_INVALID_PARAMETER;
287 }
288
289 //
290 // Next, determine whether all of the strings are good to use.
291 //
292 if (!IsFrameworkShortNameValid (ShortTitle)) {
293 return EFI_INVALID_PARAMETER;
294 }
295
296 //
297 // Next, set aside some space to start messing with the framework.
298 //
299 NewFramework = AllocateZeroPool (sizeof (UNIT_TEST_FRAMEWORK));
300 if (NewFramework == NULL) {
301 return EFI_OUT_OF_RESOURCES;
302 }
303
304 //
305 // Next, set up all the test data.
306 //
307 NewFrameworkHandle = (UNIT_TEST_FRAMEWORK_HANDLE)NewFramework;
308 NewFramework->Title = AllocateAndCopyString (Title);
309 NewFramework->ShortTitle = AllocateAndCopyString (ShortTitle);
310 NewFramework->VersionString = AllocateAndCopyString (VersionString);
311 NewFramework->Log = NULL;
312 NewFramework->CurrentTest = NULL;
313 NewFramework->SavedState = NULL;
314 if ((NewFramework->Title == NULL) ||
315 (NewFramework->ShortTitle == NULL) ||
316 (NewFramework->VersionString == NULL))
317 {
318 Status = EFI_OUT_OF_RESOURCES;
319 goto Exit;
320 }
321
322 InitializeListHead (&(NewFramework->TestSuiteList));
323
324 //
325 // Create the framework fingerprint.
326 //
327 SetFrameworkFingerprint (&NewFramework->Fingerprint[0], NewFramework);
328
329 //
330 // If there is a persisted context, load it now.
331 //
332 if (DoesCacheExist (NewFrameworkHandle)) {
333 Status = LoadUnitTestCache (NewFrameworkHandle, (VOID **)(&NewFramework->SavedState), &SaveStateSize);
334 if (EFI_ERROR (Status)) {
335 //
336 // Don't actually report it as an error, but emit a warning.
337 //
338 DEBUG ((DEBUG_ERROR, "%a - Cache was detected, but failed to load.\n", __func__));
339 Status = EFI_SUCCESS;
340 }
341 }
342
343Exit:
344 //
345 // If we're good, then let's copy the framework.
346 //
347 if (!EFI_ERROR (Status)) {
348 *FrameworkHandle = NewFrameworkHandle;
349 } else {
350 //
351 // Otherwise, we need to undo this horrible thing that we've done.
352 //
353 FreeUnitTestFramework (NewFrameworkHandle);
354 }
355
356 return Status;
357}
358
386EFIAPI
388 OUT UNIT_TEST_SUITE_HANDLE *SuiteHandle,
389 IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,
390 IN CHAR8 *Title,
391 IN CHAR8 *Name,
392 IN UNIT_TEST_SUITE_SETUP Setup OPTIONAL,
393 IN UNIT_TEST_SUITE_TEARDOWN Teardown OPTIONAL
394 )
395{
396 EFI_STATUS Status;
397 UNIT_TEST_SUITE_LIST_ENTRY *NewSuiteEntry;
398 UNIT_TEST_FRAMEWORK *Framework;
399
400 Status = EFI_SUCCESS;
401 Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
402
403 //
404 // First, let's check to make sure that our parameters look good.
405 //
406 if ((SuiteHandle == NULL) || (Framework == NULL) || (Title == NULL) || (Name == NULL)) {
407 return EFI_INVALID_PARAMETER;
408 }
409
410 //
411 // Create the new entry.
412 //
413 NewSuiteEntry = AllocateZeroPool (sizeof (UNIT_TEST_SUITE_LIST_ENTRY));
414 if (NewSuiteEntry == NULL) {
415 return EFI_OUT_OF_RESOURCES;
416 }
417
418 //
419 // Copy the fields we think we need.
420 //
421 NewSuiteEntry->UTS.NumTests = 0;
422 NewSuiteEntry->UTS.Title = AllocateAndCopyString (Title);
423 NewSuiteEntry->UTS.Name = AllocateAndCopyString (Name);
424 NewSuiteEntry->UTS.Setup = Setup;
425 NewSuiteEntry->UTS.Teardown = Teardown;
426 NewSuiteEntry->UTS.ParentFramework = FrameworkHandle;
427 InitializeListHead (&(NewSuiteEntry->Entry)); // List entry for sibling suites.
428 InitializeListHead (&(NewSuiteEntry->UTS.TestCaseList)); // List entry for child tests.
429 if (NewSuiteEntry->UTS.Title == NULL) {
430 Status = EFI_OUT_OF_RESOURCES;
431 goto Exit;
432 }
433
434 if (NewSuiteEntry->UTS.Name == NULL) {
435 Status = EFI_OUT_OF_RESOURCES;
436 goto Exit;
437 }
438
439 //
440 // Create the suite fingerprint.
441 //
442 SetSuiteFingerprint (&NewSuiteEntry->UTS.Fingerprint[0], Framework, &NewSuiteEntry->UTS);
443
444Exit:
445 //
446 // If everything is going well, add the new suite to the tail list for the framework.
447 //
448 if (!EFI_ERROR (Status)) {
449 InsertTailList (&(Framework->TestSuiteList), (LIST_ENTRY *)NewSuiteEntry);
450 *SuiteHandle = (UNIT_TEST_SUITE_HANDLE)(&NewSuiteEntry->UTS);
451 } else {
452 //
453 // Otherwise, make with the destruction.
454 //
455 FreeUnitTestSuiteEntry (NewSuiteEntry);
456 }
457
458 return Status;
459}
460
486EFIAPI
488 IN UNIT_TEST_SUITE_HANDLE SuiteHandle,
489 IN CHAR8 *Description,
490 IN CHAR8 *Name,
491 IN UNIT_TEST_FUNCTION Function,
492 IN UNIT_TEST_PREREQUISITE Prerequisite OPTIONAL,
493 IN UNIT_TEST_CLEANUP CleanUp OPTIONAL,
494 IN UNIT_TEST_CONTEXT Context OPTIONAL
495 )
496{
497 EFI_STATUS Status;
498 UNIT_TEST_LIST_ENTRY *NewTestEntry;
499 UNIT_TEST_FRAMEWORK *ParentFramework;
500 UNIT_TEST_SUITE *Suite;
501
502 Status = EFI_SUCCESS;
503 Suite = (UNIT_TEST_SUITE *)SuiteHandle;
504
505 //
506 // First, let's check to make sure that our parameters look good.
507 //
508 if ((Suite == NULL) || (Description == NULL) || (Name == NULL) || (Function == NULL)) {
509 return EFI_INVALID_PARAMETER;
510 }
511
512 ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework;
513 //
514 // Create the new entry.
515 NewTestEntry = AllocateZeroPool (sizeof (UNIT_TEST_LIST_ENTRY));
516 if (NewTestEntry == NULL) {
517 return EFI_OUT_OF_RESOURCES;
518 }
519
520 //
521 // Copy the fields we think we need.
522 NewTestEntry->UT.Description = AllocateAndCopyString (Description);
523 NewTestEntry->UT.Name = AllocateAndCopyString (Name);
524 NewTestEntry->UT.FailureType = FAILURETYPE_NOFAILURE;
525 NewTestEntry->UT.FailureMessage[0] = '\0';
526 NewTestEntry->UT.Log = NULL;
527 NewTestEntry->UT.Prerequisite = Prerequisite;
528 NewTestEntry->UT.CleanUp = CleanUp;
529 NewTestEntry->UT.RunTest = Function;
530 NewTestEntry->UT.Context = Context;
531 NewTestEntry->UT.Result = UNIT_TEST_PENDING;
532 NewTestEntry->UT.ParentSuite = SuiteHandle;
533 InitializeListHead (&(NewTestEntry->Entry)); // List entry for sibling tests.
534 if (NewTestEntry->UT.Description == NULL) {
535 Status = EFI_OUT_OF_RESOURCES;
536 goto Exit;
537 }
538
539 if (NewTestEntry->UT.Name == NULL) {
540 Status = EFI_OUT_OF_RESOURCES;
541 goto Exit;
542 }
543
544 //
545 // Create the test fingerprint.
546 //
547 SetTestFingerprint (&NewTestEntry->UT.Fingerprint[0], Suite, &NewTestEntry->UT);
548
549 // TODO: Make sure that duplicate fingerprints cannot be created.
550
551 //
552 // If there is saved test data, update this record.
553 //
554 if (ParentFramework->SavedState != NULL) {
555 UpdateTestFromSave (&NewTestEntry->UT, ParentFramework->SavedState);
556 }
557
558Exit:
559 //
560 // If everything is going well, add the new suite to the tail list for the framework.
561 //
562 if (!EFI_ERROR (Status)) {
563 InsertTailList (&(Suite->TestCaseList), (LIST_ENTRY *)NewTestEntry);
564 Suite->NumTests++;
565 } else {
566 //
567 // Otherwise, make with the destruction.
568 //
569 FreeUnitTestTestEntry (NewTestEntry);
570 }
571
572 return Status;
573}
574
575STATIC
576VOID
577UpdateTestFromSave (
579 IN UNIT_TEST_SAVE_HEADER *SavedState
580 )
581{
582 UNIT_TEST_SAVE_TEST *CurrentTest;
583 UNIT_TEST_SAVE_TEST *MatchingTest;
584 UINT8 *FloatingPointer;
585 UNIT_TEST_SAVE_CONTEXT *SavedContext;
586 UINTN Index;
587
588 //
589 // First, evaluate the inputs.
590 //
591 if ((Test == NULL) || (SavedState == NULL)) {
592 return;
593 }
594
595 if (SavedState->TestCount == 0) {
596 return;
597 }
598
599 //
600 // Next, determine whether a matching test can be found.
601 // Start at the beginning.
602 //
603 MatchingTest = NULL;
604 FloatingPointer = (UINT8 *)SavedState + sizeof (*SavedState);
605 for (Index = 0; Index < SavedState->TestCount; Index++) {
606 CurrentTest = (UNIT_TEST_SAVE_TEST *)FloatingPointer;
607 if (CompareFingerprints (&Test->Fingerprint[0], &CurrentTest->Fingerprint[0])) {
608 MatchingTest = CurrentTest;
609 //
610 // If there's a saved context, it's important that we iterate through the entire list.
611 //
612 if (!SavedState->HasSavedContext) {
613 break;
614 }
615 }
616
617 //
618 // If we didn't find it, we have to increment to the next test.
619 //
620 FloatingPointer = (UINT8 *)CurrentTest + CurrentTest->Size;
621 }
622
623 //
624 // If a matching test was found, copy the status.
625 //
626 if (MatchingTest) {
627 //
628 // Override the test status with the saved status.
629 //
630 Test->Result = MatchingTest->Result;
631
632 Test->FailureType = MatchingTest->FailureType;
634 &Test->FailureMessage[0],
636 &MatchingTest->FailureMessage[0],
638 );
639
640 //
641 // If there is a log string associated, grab that.
642 // We can tell that there's a log string because the "size" will be larger than
643 // the structure size.
644 // IMPORTANT NOTE: There are security implications here.
645 // This data is user-supplied and we're about to play kinda
646 // fast and loose with data buffers.
647 //
648 if (MatchingTest->Size > sizeof (UNIT_TEST_SAVE_TEST)) {
649 UnitTestLogInit (Test, (UINT8 *)MatchingTest->Log, MatchingTest->Size - sizeof (UNIT_TEST_SAVE_TEST));
650 }
651 }
652
653 //
654 // If the saved context exists and matches this test, grab it, too.
655 //
656 if (SavedState->HasSavedContext) {
657 //
658 // If there was a saved context, the "matching test" loop will have placed the FloatingPointer
659 // at the beginning of the context structure.
660 //
661 SavedContext = (UNIT_TEST_SAVE_CONTEXT *)FloatingPointer;
662 if (((SavedContext->Size - sizeof (UNIT_TEST_SAVE_CONTEXT)) > 0) &&
663 CompareFingerprints (&Test->Fingerprint[0], &SavedContext->Fingerprint[0]))
664 {
665 //
666 // Override the test context with the saved context.
667 //
668 Test->Context = (VOID *)SavedContext->Data;
669 }
670 }
671}
672
673STATIC
675SerializeState (
676 IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,
677 IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL,
678 IN UINTN ContextToSaveSize
679 )
680{
681 UNIT_TEST_FRAMEWORK *Framework;
682 UNIT_TEST_SAVE_HEADER *Header;
683 LIST_ENTRY *SuiteListHead;
684 LIST_ENTRY *Suite;
685 LIST_ENTRY *TestListHead;
687 UINT32 TestCount;
688 UINT32 TotalSize;
689 UINTN LogSize;
690 UNIT_TEST_SAVE_TEST *TestSaveData;
691 UNIT_TEST_SAVE_CONTEXT *TestSaveContext;
692 UNIT_TEST *UnitTest;
693 UINT8 *FloatingPointer;
694
695 Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
696 Header = NULL;
697
698 //
699 // First, let's not make assumptions about the parameters.
700 //
701 if ((Framework == NULL) ||
702 ((ContextToSave != NULL) && (ContextToSaveSize == 0)) ||
703 (ContextToSaveSize > MAX_UINT32))
704 {
705 return NULL;
706 }
707
708 //
709 // Next, we've gotta figure out the resources that will be required to serialize the
710 // the framework state so that we can persist it.
711 // To start with, we're gonna need a header.
712 //
713 TotalSize = sizeof (UNIT_TEST_SAVE_HEADER);
714 //
715 // Now we need to figure out how many tests there are.
716 //
717 TestCount = 0;
718 //
719 // Iterate all suites.
720 //
721 SuiteListHead = &Framework->TestSuiteList;
722 for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) {
723 //
724 // Iterate all tests within the suite.
725 //
726 TestListHead = &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseList;
727 for (Test = GetFirstNode (TestListHead); Test != TestListHead; Test = GetNextNode (TestListHead, Test)) {
728 UnitTest = &((UNIT_TEST_LIST_ENTRY *)Test)->UT;
729 //
730 // Account for the size of a test structure.
731 //
732 TotalSize += sizeof (UNIT_TEST_SAVE_TEST);
733 //
734 // If there's a log, make sure to account for the log size.
735 //
736 if (UnitTest->Log != NULL) {
737 //
738 // The +1 is for the NULL character. Can't forget the NULL character.
739 //
740 LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8);
741 ASSERT (LogSize < MAX_UINT32);
742 TotalSize += (UINT32)LogSize;
743 }
744
745 //
746 // Increment the test count.
747 //
748 TestCount++;
749 }
750 }
751
752 //
753 // If there are no tests, we're done here.
754 //
755 if (TestCount == 0) {
756 return NULL;
757 }
758
759 //
760 // Add room for the context, if there is one.
761 //
762 if (ContextToSave != NULL) {
763 TotalSize += sizeof (UNIT_TEST_SAVE_CONTEXT) + (UINT32)ContextToSaveSize;
764 }
765
766 //
767 // Now that we know the size, we need to allocate space for the serialized output.
768 //
769 Header = AllocateZeroPool (TotalSize);
770 if (Header == NULL) {
771 return NULL;
772 }
773
774 //
775 // Alright, let's start setting up some data.
776 //
777 Header->Version = UNIT_TEST_PERSISTENCE_LIB_VERSION;
778 Header->SaveStateSize = TotalSize;
779 CopyMem (&Header->Fingerprint[0], &Framework->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
780 CopyMem (&Header->StartTime, &Framework->StartTime, sizeof (EFI_TIME));
781 Header->TestCount = TestCount;
782 Header->HasSavedContext = FALSE;
783
784 //
785 // Start adding all of the test cases.
786 // Set the floating pointer to the start of the current test save buffer.
787 //
788 FloatingPointer = (UINT8 *)Header + sizeof (UNIT_TEST_SAVE_HEADER);
789 //
790 // Iterate all suites.
791 //
792 SuiteListHead = &Framework->TestSuiteList;
793 for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) {
794 //
795 // Iterate all tests within the suite.
796 //
797 TestListHead = &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseList;
798 for (Test = GetFirstNode (TestListHead); Test != TestListHead; Test = GetNextNode (TestListHead, Test)) {
799 TestSaveData = (UNIT_TEST_SAVE_TEST *)FloatingPointer;
800 UnitTest = &((UNIT_TEST_LIST_ENTRY *)Test)->UT;
801
802 //
803 // Save the fingerprint.
804 //
805 CopyMem (&TestSaveData->Fingerprint[0], &UnitTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
806
807 //
808 // Save the result.
809 //
810 TestSaveData->Result = UnitTest->Result;
811 TestSaveData->FailureType = UnitTest->FailureType;
812 AsciiStrnCpyS (&TestSaveData->FailureMessage[0], UNIT_TEST_MAX_STRING_LENGTH, &UnitTest->FailureMessage[0], UNIT_TEST_MAX_STRING_LENGTH);
813
814 //
815 // If there is a log, save the log.
816 //
817 FloatingPointer += sizeof (UNIT_TEST_SAVE_TEST);
818 if (UnitTest->Log != NULL) {
819 //
820 // The +1 is for the NULL character. Can't forget the NULL character.
821 //
822 LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8);
823 CopyMem (FloatingPointer, UnitTest->Log, LogSize);
824 FloatingPointer += LogSize;
825 }
826
827 //
828 // Update the size once the structure is complete.
829 // NOTE: Should this be a straight cast without validation?
830 //
831 TestSaveData->Size = (UINT32)(FloatingPointer - (UINT8 *)TestSaveData);
832 }
833 }
834
835 //
836 // If there is a context to save, let's do that now.
837 //
838 if ((ContextToSave != NULL) && (Framework->CurrentTest != NULL)) {
839 TestSaveContext = (UNIT_TEST_SAVE_CONTEXT *)FloatingPointer;
840 TestSaveContext->Size = (UINT32)ContextToSaveSize + sizeof (UNIT_TEST_SAVE_CONTEXT);
841 CopyMem (&TestSaveContext->Fingerprint[0], &Framework->CurrentTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
842 CopyMem (((UINT8 *)TestSaveContext + sizeof (UNIT_TEST_SAVE_CONTEXT)), ContextToSave, ContextToSaveSize);
843 Header->HasSavedContext = TRUE;
844 }
845
846 return Header;
847}
848
878EFIAPI
880 IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL,
881 IN UINTN ContextToSaveSize
882 )
883{
884 EFI_STATUS Status;
885 UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle;
886 UNIT_TEST_SAVE_HEADER *Header;
887
888 Header = NULL;
889 FrameworkHandle = GetActiveFrameworkHandle ();
890 if (FrameworkHandle == NULL) {
891 DEBUG ((DEBUG_ERROR, "%a - Could not save state! FrameworkHandle not initialized\n", __func__));
892 return EFI_DEVICE_ERROR;
893 }
894
895 //
896 // Return a unique error code if the framework is not set.
897 //
898 if (FrameworkHandle == NULL) {
899 return EFI_NOT_FOUND;
900 }
901
902 //
903 // First, let's not make assumptions about the parameters.
904 //
905 if (((ContextToSave != NULL) && (ContextToSaveSize == 0)) ||
906 (ContextToSaveSize > MAX_UINT32))
907 {
908 return EFI_INVALID_PARAMETER;
909 }
910
911 //
912 // Now, let's package up all the data for saving.
913 //
914 Header = SerializeState (FrameworkHandle, ContextToSave, ContextToSaveSize);
915 if (Header == NULL) {
916 return EFI_OUT_OF_RESOURCES;
917 }
918
919 //
920 // All that should be left to do is save it using the associated persistence lib.
921 //
922 Status = SaveUnitTestCache (FrameworkHandle, Header, Header->SaveStateSize);
923 if (EFI_ERROR (Status)) {
924 DEBUG ((DEBUG_ERROR, "%a - Could not save state! %r\n", __func__, Status));
925 Status = EFI_DEVICE_ERROR;
926 }
927
928 //
929 // Free data that was used.
930 //
931 FreePool (Header);
932
933 return Status;
934}
UINT64 UINTN
UINTN EFIAPI AsciiStrnLenS(IN CONST CHAR8 *String, IN UINTN MaxSize)
Definition: SafeString.c:1696
RETURN_STATUS EFIAPI AsciiStrnCpyS(OUT CHAR8 *Destination, IN UINTN DestMax, IN CONST CHAR8 *Source, IN UINTN Length)
Definition: SafeString.c:1875
LIST_ENTRY *EFIAPI GetNextNode(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:333
UINT32 EFIAPI CalculateCrc32(IN VOID *Buffer, IN UINTN Length)
Definition: CheckSum.c:600
UINTN EFIAPI AsciiStrLen(IN CONST CHAR8 *String)
Definition: String.c:641
LIST_ENTRY *EFIAPI GetFirstNode(IN CONST LIST_ENTRY *List)
Definition: LinkedList.c:298
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
RETURN_STATUS EFIAPI AsciiStrCpyS(OUT CHAR8 *Destination, IN UINTN DestMax, IN CONST CHAR8 *Source)
Definition: SafeString.c:1797
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define VOID
Definition: Base.h:269
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:435
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
EFI_STRING_ID NewString(IN CHAR16 *String, IN EFI_HII_HANDLE HiiHandle)
Definition: Setup.c:1012
INTN EFIAPI Test(CONST VOID *b1, CONST VOID *b2)
VOID EFIAPI Exit(IN EFI_STATUS Status)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
#define UNIT_TEST_FINGERPRINT_SIZE
#define UNIT_TEST_MAX_STRING_LENGTH
EFI_STATUS EFIAPI SaveFrameworkState(IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL, IN UINTN ContextToSaveSize)
Definition: UnitTestLib.c:879
UNIT_TEST_STATUS(EFIAPI * UNIT_TEST_PREREQUISITE)(IN UNIT_TEST_CONTEXT Context)
Definition: UnitTestLib.h:103
VOID * UNIT_TEST_CONTEXT
Definition: UnitTestLib.h:54
VOID(EFIAPI * UNIT_TEST_SUITE_TEARDOWN)(VOID)
Definition: UnitTestLib.h:158
EFI_STATUS EFIAPI CreateUnitTestSuite(OUT UNIT_TEST_SUITE_HANDLE *SuiteHandle, IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, IN CHAR8 *Title, IN CHAR8 *Name, IN UNIT_TEST_SUITE_SETUP Setup OPTIONAL, IN UNIT_TEST_SUITE_TEARDOWN Teardown OPTIONAL)
Definition: UnitTestLib.c:387
EFI_STATUS EFIAPI FreeUnitTestFramework(IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle)
Definition: UnitTestLib.c:203
EFI_STATUS EFIAPI AddTestCase(IN UNIT_TEST_SUITE_HANDLE SuiteHandle, IN CHAR8 *Description, IN CHAR8 *Name, IN UNIT_TEST_FUNCTION Function, IN UNIT_TEST_PREREQUISITE Prerequisite OPTIONAL, IN UNIT_TEST_CLEANUP CleanUp OPTIONAL, IN UNIT_TEST_CONTEXT Context OPTIONAL)
Definition: UnitTestLib.c:487
VOID(EFIAPI * UNIT_TEST_SUITE_SETUP)(VOID)
Definition: UnitTestLib.h:144
EFI_STATUS EFIAPI InitUnitTestFramework(OUT UNIT_TEST_FRAMEWORK_HANDLE *FrameworkHandle, IN CHAR8 *Title, IN CHAR8 *ShortTitle, IN CHAR8 *VersionString)
Definition: UnitTestLib.c:265
UNIT_TEST_STATUS(EFIAPI * UNIT_TEST_FUNCTION)(IN UNIT_TEST_CONTEXT Context)
Definition: UnitTestLib.h:77
VOID(EFIAPI * UNIT_TEST_CLEANUP)(IN UNIT_TEST_CONTEXT Context)
Definition: UnitTestLib.h:130
EFI_STATUS EFIAPI SaveUnitTestCache(IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, IN VOID *SaveData, IN UINTN SaveStateSize)
EFI_STATUS EFIAPI LoadUnitTestCache(IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, OUT VOID **SaveData, OUT UINTN *SaveStateSize)
BOOLEAN EFIAPI DoesCacheExist(IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle)