]> git.proxmox.com Git - mirror_edk2.git/blob - UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c
UnitTestFrameworkPkg: Apply uncrustify changes
[mirror_edk2.git] / UnitTestFrameworkPkg / Library / UnitTestLib / UnitTestLib.c
1 /**
2 Implement UnitTestLib
3
4 Copyright (c) Microsoft Corporation.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 **/
7
8 #include <Uefi.h>
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>
16
17 ///
18 /// Forward declaration of prototype
19 ///
20 STATIC
21 VOID
22 UpdateTestFromSave (
23 IN OUT UNIT_TEST *Test,
24 IN UNIT_TEST_SAVE_HEADER *SavedState
25 );
26
27 /**
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.
30
31 Example: If the name cannot be serialized to a filesystem file name.
32
33 @param[in] ShortTitleString A pointer to the short title string to be evaluated.
34
35 @retval TRUE The string is acceptable.
36 @retval FALSE The string should not be used.
37
38 **/
39 STATIC
40 BOOLEAN
41 IsFrameworkShortNameValid (
42 IN CHAR8 *ShortTitleString
43 )
44 {
45 // TODO: Finish this function.
46 return TRUE;
47 }
48
49 STATIC
50 CHAR8 *
51 AllocateAndCopyString (
52 IN CHAR8 *StringToCopy
53 )
54 {
55 CHAR8 *NewString;
56 UINTN NewStringLength;
57
58 NewString = NULL;
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);
63 }
64
65 return NewString;
66 }
67
68 STATIC
69 VOID
70 SetFrameworkFingerprint (
71 OUT UINT8 *Fingerprint,
72 IN UNIT_TEST_FRAMEWORK *Framework
73 )
74 {
75 UINT32 NewFingerprint;
76
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)));
80
81 CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE);
82 return;
83 }
84
85 STATIC
86 VOID
87 SetSuiteFingerprint (
88 OUT UINT8 *Fingerprint,
89 IN UNIT_TEST_FRAMEWORK *Framework,
90 IN UNIT_TEST_SUITE *Suite
91 )
92 {
93 UINT32 NewFingerprint;
94
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)));
99
100 CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE);
101 return;
102 }
103
104 STATIC
105 VOID
106 SetTestFingerprint (
107 OUT UINT8 *Fingerprint,
108 IN UNIT_TEST_SUITE *Suite,
109 IN UNIT_TEST *Test
110 )
111 {
112 UINT32 NewFingerprint;
113
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)));
118
119 CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE);
120 return;
121 }
122
123 STATIC
124 BOOLEAN
125 CompareFingerprints (
126 IN UINT8 *FingerprintA,
127 IN UINT8 *FingerprintB
128 )
129 {
130 return (CompareMem (FingerprintA, FingerprintB, UNIT_TEST_FINGERPRINT_SIZE) == 0);
131 }
132
133 /**
134 Cleanup a test framework.
135
136 After tests are run, this will teardown the entire framework and free all
137 allocated data within.
138
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.
142
143 @retval EFI_SUCCESS All resources associated with framework were
144 freed.
145 @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
146 **/
147 EFI_STATUS
148 EFIAPI
149 FreeUnitTestFramework (
150 IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
151 )
152 {
153 // TODO: Finish this function.
154 return EFI_SUCCESS;
155 }
156
157 STATIC
158 EFI_STATUS
159 FreeUnitTestSuiteEntry (
160 IN UNIT_TEST_SUITE_LIST_ENTRY *SuiteEntry
161 )
162 {
163 // TODO: Finish this function.
164 return EFI_SUCCESS;
165 }
166
167 STATIC
168 EFI_STATUS
169 FreeUnitTestTestEntry (
170 IN UNIT_TEST_LIST_ENTRY *TestEntry
171 )
172 {
173 // TODO: Finish this function.
174 return EFI_SUCCESS;
175 }
176
177 /**
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.
181
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
185 copied.
186 @param[in] ShortTitle Null-terminated ASCII short string that is the
187 short name of the framework with no spaces.
188 String is copied.
189 @param[in] VersionString Null-terminated ASCII version string for the
190 framework. String is copied.
191
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.
200 **/
201 EFI_STATUS
202 EFIAPI
203 InitUnitTestFramework (
204 OUT UNIT_TEST_FRAMEWORK_HANDLE *FrameworkHandle,
205 IN CHAR8 *Title,
206 IN CHAR8 *ShortTitle,
207 IN CHAR8 *VersionString
208 )
209 {
210 EFI_STATUS Status;
211 UNIT_TEST_FRAMEWORK_HANDLE NewFrameworkHandle;
212 UNIT_TEST_FRAMEWORK *NewFramework;
213
214 Status = EFI_SUCCESS;
215 NewFramework = NULL;
216
217 //
218 // First, check all pointers and make sure nothing's broked.
219 //
220 if ((FrameworkHandle == NULL) || (Title == NULL) ||
221 (ShortTitle == NULL) || (VersionString == NULL))
222 {
223 return EFI_INVALID_PARAMETER;
224 }
225
226 //
227 // Next, determine whether all of the strings are good to use.
228 //
229 if (!IsFrameworkShortNameValid (ShortTitle)) {
230 return EFI_INVALID_PARAMETER;
231 }
232
233 //
234 // Next, set aside some space to start messing with the framework.
235 //
236 NewFramework = AllocateZeroPool (sizeof (UNIT_TEST_FRAMEWORK));
237 if (NewFramework == NULL) {
238 return EFI_OUT_OF_RESOURCES;
239 }
240
241 //
242 // Next, set up all the test data.
243 //
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))
254 {
255 Status = EFI_OUT_OF_RESOURCES;
256 goto Exit;
257 }
258
259 InitializeListHead (&(NewFramework->TestSuiteList));
260
261 //
262 // Create the framework fingerprint.
263 //
264 SetFrameworkFingerprint (&NewFramework->Fingerprint[0], NewFramework);
265
266 //
267 // If there is a persisted context, load it now.
268 //
269 if (DoesCacheExist (NewFrameworkHandle)) {
270 Status = LoadUnitTestCache (NewFrameworkHandle, (UNIT_TEST_SAVE_HEADER **)(&NewFramework->SavedState));
271 if (EFI_ERROR (Status)) {
272 //
273 // Don't actually report it as an error, but emit a warning.
274 //
275 DEBUG ((DEBUG_ERROR, "%a - Cache was detected, but failed to load.\n", __FUNCTION__));
276 Status = EFI_SUCCESS;
277 }
278 }
279
280 Exit:
281 //
282 // If we're good, then let's copy the framework.
283 //
284 if (!EFI_ERROR (Status)) {
285 *FrameworkHandle = NewFrameworkHandle;
286 } else {
287 //
288 // Otherwise, we need to undo this horrible thing that we've done.
289 //
290 FreeUnitTestFramework (NewFrameworkHandle);
291 }
292
293 return Status;
294 }
295
296 /**
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.
300
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
305 copied.
306 @param[in] Name Null-terminated ASCII string that is the short
307 name of the test suite with no spaces. String
308 is copied.
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.
313
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.
321 **/
322 EFI_STATUS
323 EFIAPI
324 CreateUnitTestSuite (
325 OUT UNIT_TEST_SUITE_HANDLE *SuiteHandle,
326 IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,
327 IN CHAR8 *Title,
328 IN CHAR8 *Name,
329 IN UNIT_TEST_SUITE_SETUP Setup OPTIONAL,
330 IN UNIT_TEST_SUITE_TEARDOWN Teardown OPTIONAL
331 )
332 {
333 EFI_STATUS Status;
334 UNIT_TEST_SUITE_LIST_ENTRY *NewSuiteEntry;
335 UNIT_TEST_FRAMEWORK *Framework;
336
337 Status = EFI_SUCCESS;
338 Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
339
340 //
341 // First, let's check to make sure that our parameters look good.
342 //
343 if ((SuiteHandle == NULL) || (Framework == NULL) || (Title == NULL) || (Name == NULL)) {
344 return EFI_INVALID_PARAMETER;
345 }
346
347 //
348 // Create the new entry.
349 //
350 NewSuiteEntry = AllocateZeroPool (sizeof (UNIT_TEST_SUITE_LIST_ENTRY));
351 if (NewSuiteEntry == NULL) {
352 return EFI_OUT_OF_RESOURCES;
353 }
354
355 //
356 // Copy the fields we think we need.
357 //
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;
368 goto Exit;
369 }
370
371 if (NewSuiteEntry->UTS.Name == NULL) {
372 Status = EFI_OUT_OF_RESOURCES;
373 goto Exit;
374 }
375
376 //
377 // Create the suite fingerprint.
378 //
379 SetSuiteFingerprint (&NewSuiteEntry->UTS.Fingerprint[0], Framework, &NewSuiteEntry->UTS);
380
381 Exit:
382 //
383 // If everything is going well, add the new suite to the tail list for the framework.
384 //
385 if (!EFI_ERROR (Status)) {
386 InsertTailList (&(Framework->TestSuiteList), (LIST_ENTRY *)NewSuiteEntry);
387 *SuiteHandle = (UNIT_TEST_SUITE_HANDLE)(&NewSuiteEntry->UTS);
388 } else {
389 //
390 // Otherwise, make with the destruction.
391 //
392 FreeUnitTestSuiteEntry (NewSuiteEntry);
393 }
394
395 return Status;
396 }
397
398 /**
399 Adds test case to Suite
400
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
412 that may be NULL.
413
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.
421 **/
422 EFI_STATUS
423 EFIAPI
424 AddTestCase (
425 IN UNIT_TEST_SUITE_HANDLE SuiteHandle,
426 IN CHAR8 *Description,
427 IN CHAR8 *Name,
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
432 )
433 {
434 EFI_STATUS Status;
435 UNIT_TEST_LIST_ENTRY *NewTestEntry;
436 UNIT_TEST_FRAMEWORK *ParentFramework;
437 UNIT_TEST_SUITE *Suite;
438
439 Status = EFI_SUCCESS;
440 Suite = (UNIT_TEST_SUITE *)SuiteHandle;
441
442 //
443 // First, let's check to make sure that our parameters look good.
444 //
445 if ((Suite == NULL) || (Description == NULL) || (Name == NULL) || (Function == NULL)) {
446 return EFI_INVALID_PARAMETER;
447 }
448
449 ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework;
450 //
451 // Create the new entry.
452 NewTestEntry = AllocateZeroPool (sizeof (UNIT_TEST_LIST_ENTRY));
453 if (NewTestEntry == NULL) {
454 return EFI_OUT_OF_RESOURCES;
455 }
456
457 //
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;
473 goto Exit;
474 }
475
476 if (NewTestEntry->UT.Name == NULL) {
477 Status = EFI_OUT_OF_RESOURCES;
478 goto Exit;
479 }
480
481 //
482 // Create the test fingerprint.
483 //
484 SetTestFingerprint (&NewTestEntry->UT.Fingerprint[0], Suite, &NewTestEntry->UT);
485
486 // TODO: Make sure that duplicate fingerprints cannot be created.
487
488 //
489 // If there is saved test data, update this record.
490 //
491 if (ParentFramework->SavedState != NULL) {
492 UpdateTestFromSave (&NewTestEntry->UT, ParentFramework->SavedState);
493 }
494
495 Exit:
496 //
497 // If everything is going well, add the new suite to the tail list for the framework.
498 //
499 if (!EFI_ERROR (Status)) {
500 InsertTailList (&(Suite->TestCaseList), (LIST_ENTRY *)NewTestEntry);
501 Suite->NumTests++;
502 } else {
503 //
504 // Otherwise, make with the destruction.
505 //
506 FreeUnitTestTestEntry (NewTestEntry);
507 }
508
509 return Status;
510 }
511
512 STATIC
513 VOID
514 UpdateTestFromSave (
515 IN OUT UNIT_TEST *Test,
516 IN UNIT_TEST_SAVE_HEADER *SavedState
517 )
518 {
519 UNIT_TEST_SAVE_TEST *CurrentTest;
520 UNIT_TEST_SAVE_TEST *MatchingTest;
521 UINT8 *FloatingPointer;
522 UNIT_TEST_SAVE_CONTEXT *SavedContext;
523 UINTN Index;
524
525 //
526 // First, evaluate the inputs.
527 //
528 if ((Test == NULL) || (SavedState == NULL)) {
529 return;
530 }
531
532 if (SavedState->TestCount == 0) {
533 return;
534 }
535
536 //
537 // Next, determine whether a matching test can be found.
538 // Start at the beginning.
539 //
540 MatchingTest = NULL;
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;
546 //
547 // If there's a saved context, it's important that we iterate through the entire list.
548 //
549 if (!SavedState->HasSavedContext) {
550 break;
551 }
552 }
553
554 //
555 // If we didn't find it, we have to increment to the next test.
556 //
557 FloatingPointer = (UINT8 *)CurrentTest + CurrentTest->Size;
558 }
559
560 //
561 // If a matching test was found, copy the status.
562 //
563 if (MatchingTest) {
564 //
565 // Override the test status with the saved status.
566 //
567 Test->Result = MatchingTest->Result;
568
569 Test->FailureType = MatchingTest->FailureType;
570 AsciiStrnCpyS (
571 &Test->FailureMessage[0],
572 UNIT_TEST_TESTFAILUREMSG_LENGTH,
573 &MatchingTest->FailureMessage[0],
574 UNIT_TEST_TESTFAILUREMSG_LENGTH
575 );
576
577 //
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.
584 //
585 if (MatchingTest->Size > sizeof (UNIT_TEST_SAVE_TEST)) {
586 UnitTestLogInit (Test, (UINT8 *)MatchingTest->Log, MatchingTest->Size - sizeof (UNIT_TEST_SAVE_TEST));
587 }
588 }
589
590 //
591 // If the saved context exists and matches this test, grab it, too.
592 //
593 if (SavedState->HasSavedContext) {
594 //
595 // If there was a saved context, the "matching test" loop will have placed the FloatingPointer
596 // at the beginning of the context structure.
597 //
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]))
601 {
602 //
603 // Override the test context with the saved context.
604 //
605 Test->Context = (VOID *)SavedContext->Data;
606 }
607 }
608 }
609
610 STATIC
611 UNIT_TEST_SAVE_HEADER *
612 SerializeState (
613 IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,
614 IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL,
615 IN UINTN ContextToSaveSize
616 )
617 {
618 UNIT_TEST_FRAMEWORK *Framework;
619 UNIT_TEST_SAVE_HEADER *Header;
620 LIST_ENTRY *SuiteListHead;
621 LIST_ENTRY *Suite;
622 LIST_ENTRY *TestListHead;
623 LIST_ENTRY *Test;
624 UINT32 TestCount;
625 UINT32 TotalSize;
626 UINTN LogSize;
627 UNIT_TEST_SAVE_TEST *TestSaveData;
628 UNIT_TEST_SAVE_CONTEXT *TestSaveContext;
629 UNIT_TEST *UnitTest;
630 UINT8 *FloatingPointer;
631
632 Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
633 Header = NULL;
634
635 //
636 // First, let's not make assumptions about the parameters.
637 //
638 if ((Framework == NULL) ||
639 ((ContextToSave != NULL) && (ContextToSaveSize == 0)) ||
640 (ContextToSaveSize > MAX_UINT32))
641 {
642 return NULL;
643 }
644
645 //
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.
649 //
650 TotalSize = sizeof (UNIT_TEST_SAVE_HEADER);
651 //
652 // Now we need to figure out how many tests there are.
653 //
654 TestCount = 0;
655 //
656 // Iterate all suites.
657 //
658 SuiteListHead = &Framework->TestSuiteList;
659 for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) {
660 //
661 // Iterate all tests within the suite.
662 //
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;
666 //
667 // Account for the size of a test structure.
668 //
669 TotalSize += sizeof (UNIT_TEST_SAVE_TEST);
670 //
671 // If there's a log, make sure to account for the log size.
672 //
673 if (UnitTest->Log != NULL) {
674 //
675 // The +1 is for the NULL character. Can't forget the NULL character.
676 //
677 LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8);
678 ASSERT (LogSize < MAX_UINT32);
679 TotalSize += (UINT32)LogSize;
680 }
681
682 //
683 // Increment the test count.
684 //
685 TestCount++;
686 }
687 }
688
689 //
690 // If there are no tests, we're done here.
691 //
692 if (TestCount == 0) {
693 return NULL;
694 }
695
696 //
697 // Add room for the context, if there is one.
698 //
699 if (ContextToSave != NULL) {
700 TotalSize += sizeof (UNIT_TEST_SAVE_CONTEXT) + (UINT32)ContextToSaveSize;
701 }
702
703 //
704 // Now that we know the size, we need to allocate space for the serialized output.
705 //
706 Header = AllocateZeroPool (TotalSize);
707 if (Header == NULL) {
708 return NULL;
709 }
710
711 //
712 // Alright, let's start setting up some data.
713 //
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;
720
721 //
722 // Start adding all of the test cases.
723 // Set the floating pointer to the start of the current test save buffer.
724 //
725 FloatingPointer = (UINT8 *)Header + sizeof (UNIT_TEST_SAVE_HEADER);
726 //
727 // Iterate all suites.
728 //
729 SuiteListHead = &Framework->TestSuiteList;
730 for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) {
731 //
732 // Iterate all tests within the suite.
733 //
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;
738
739 //
740 // Save the fingerprint.
741 //
742 CopyMem (&TestSaveData->Fingerprint[0], &UnitTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
743
744 //
745 // Save the result.
746 //
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);
750
751 //
752 // If there is a log, save the log.
753 //
754 FloatingPointer += sizeof (UNIT_TEST_SAVE_TEST);
755 if (UnitTest->Log != NULL) {
756 //
757 // The +1 is for the NULL character. Can't forget the NULL character.
758 //
759 LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8);
760 CopyMem (FloatingPointer, UnitTest->Log, LogSize);
761 FloatingPointer += LogSize;
762 }
763
764 //
765 // Update the size once the structure is complete.
766 // NOTE: Should this be a straight cast without validation?
767 //
768 TestSaveData->Size = (UINT32)(FloatingPointer - (UINT8 *)TestSaveData);
769 }
770 }
771
772 //
773 // If there is a context to save, let's do that now.
774 //
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;
781 }
782
783 return Header;
784 }
785
786 /**
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.
793
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.
796
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.
802
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
812 device error.
813 **/
814 EFI_STATUS
815 EFIAPI
816 SaveFrameworkState (
817 IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL,
818 IN UINTN ContextToSaveSize
819 )
820 {
821 EFI_STATUS Status;
822 UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle;
823 UNIT_TEST_SAVE_HEADER *Header;
824
825 Header = NULL;
826 FrameworkHandle = GetActiveFrameworkHandle ();
827
828 //
829 // Return a unique error code if the framework is not set.
830 //
831 if (FrameworkHandle == NULL) {
832 return EFI_NOT_FOUND;
833 }
834
835 //
836 // First, let's not make assumptions about the parameters.
837 //
838 if (((ContextToSave != NULL) && (ContextToSaveSize == 0)) ||
839 (ContextToSaveSize > MAX_UINT32))
840 {
841 return EFI_INVALID_PARAMETER;
842 }
843
844 //
845 // Now, let's package up all the data for saving.
846 //
847 Header = SerializeState (FrameworkHandle, ContextToSave, ContextToSaveSize);
848 if (Header == NULL) {
849 return EFI_OUT_OF_RESOURCES;
850 }
851
852 //
853 // All that should be left to do is save it using the associated persistence lib.
854 //
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;
859 }
860
861 //
862 // Free data that was used.
863 //
864 FreePool (Header);
865
866 return Status;
867 }