summaryrefslogtreecommitdiffstats
path: root/MdePkg/Include/Library/UnitTestLib.h
blob: 142e865cb219990eb5fdf179c2495d4b448328ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
/** @file
  Provides a unit test framework.  This allows tests to focus on testing logic
  and the framework to focus on runnings, reporting, statistics, etc.

  Copyright (c) Microsoft Corporation.<BR>
  Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
  SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#ifndef __UNIT_TEST_LIB_H__
#define __UNIT_TEST_LIB_H__

///
/// Unit Test Status
///
typedef UINT32  UNIT_TEST_STATUS;
#define UNIT_TEST_PASSED                      (0)
#define UNIT_TEST_ERROR_PREREQUISITE_NOT_MET  (1)
#define UNIT_TEST_ERROR_TEST_FAILED           (2)
#define UNIT_TEST_ERROR_CLEANUP_FAILED        (3)
#define UNIT_TEST_SKIPPED                     (0xFFFFFFFD)
#define UNIT_TEST_RUNNING                     (0xFFFFFFFE)
#define UNIT_TEST_PENDING                     (0xFFFFFFFF)

///
/// Declare PcdUnitTestLogLevel bits and UnitTestLog() ErrorLevel parameter.
///
#define UNIT_TEST_LOG_LEVEL_ERROR    BIT0
#define UNIT_TEST_LOG_LEVEL_WARN     BIT1
#define UNIT_TEST_LOG_LEVEL_INFO     BIT2
#define UNIT_TEST_LOG_LEVEL_VERBOSE  BIT3

///
/// Unit Test Framework Handle
///
struct UNIT_TEST_FRAMEWORK_OBJECT;
typedef struct UNIT_TEST_FRAMEWORK_OBJECT  *UNIT_TEST_FRAMEWORK_HANDLE;

///
/// Unit Test Suite Handle
///
struct UNIT_TEST_SUITE_OBJECT;
typedef struct UNIT_TEST_SUITE_OBJECT  *UNIT_TEST_SUITE_HANDLE;

///
/// Unit Test Handle
///
struct UNIT_TEST_OBJECT;
typedef struct UNIT_TEST_OBJECT  *UNIT_TEST_HANDLE;

///
/// Unit Test Context
///
typedef VOID*  UNIT_TEST_CONTEXT;

/**
  The prototype for a single UnitTest case function.

  Functions with this prototype are registered to be dispatched by the
  UnitTest framework, and results are recorded as test Pass or Fail.

  @param[in]  Context    [Optional] An optional parameter that enables:
                         1) test-case reuse with varied parameters and
                         2) test-case re-entry for Target tests that need a
                         reboot.  This parameter is a VOID* and it is the
                         responsibility of the test author to ensure that the
                         contents are well understood by all test cases that may
                         consume it.

  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test
                                        case was successful.
  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.

**/
typedef
UNIT_TEST_STATUS
(EFIAPI *UNIT_TEST_FUNCTION)(
  IN UNIT_TEST_CONTEXT  Context
  );

/**
  Unit-Test Prerequisite Function pointer type.

  Functions with this prototype are registered to be dispatched by the unit test
  framework prior to a given test case. If this prereq function returns
  UNIT_TEST_ERROR_PREREQUISITE_NOT_MET, the test case will be skipped.

  @param[in]  Context    [Optional] An optional parameter that enables:
                         1) test-case reuse with varied parameters and
                         2) test-case re-entry for Target tests that need a
                         reboot.  This parameter is a VOID* and it is the
                         responsibility of the test author to ensure that the
                         contents are well understood by all test cases that may
                         consume it.

  @retval  UNIT_TEST_PASSED                      Unit test case prerequisites
                                                 are met.
  @retval  UNIT_TEST_ERROR_PREREQUISITE_NOT_MET  Test case should be skipped.

**/
typedef
UNIT_TEST_STATUS
(EFIAPI *UNIT_TEST_PREREQUISITE)(
  IN UNIT_TEST_CONTEXT  Context
  );

/**
  Unit-Test Cleanup (after) function pointer type.

  Functions with this prototype are registered to be dispatched by the
  unit test framework after a given test case. This will be called even if the
  test case returns an error, but not if the prerequisite fails and the test is
  skipped.  The purpose of this function is to clean up any global state or
  test data.

  @param[in]  Context    [Optional] An optional parameter that enables:
                         1) test-case reuse with varied parameters and
                         2) test-case re-entry for Target tests that need a
                         reboot.  This parameter is a VOID* and it is the
                         responsibility of the test author to ensure that the
                         contents are well understood by all test cases that may
                         consume it.

  @retval  UNIT_TEST_PASSED                Test case cleanup succeeded.
  @retval  UNIT_TEST_ERROR_CLEANUP_FAILED  Test case cleanup failed.

**/
typedef
VOID
(EFIAPI *UNIT_TEST_CLEANUP)(
  IN UNIT_TEST_CONTEXT  Context
  );

/**
  Unit-Test Test Suite Setup (before) function pointer type. Functions with this
  prototype are registered to be dispatched by the UnitTest framework prior to
  running any of the test cases in a test suite.  It will only be run once at
  the beginning of the suite (not prior to each case).

  The purpose of this function is to set up any global state or test data.
**/
typedef
VOID
(EFIAPI *UNIT_TEST_SUITE_SETUP)(
  VOID
  );

/**
  Unit-Test Test Suite Teardown (after) function pointer type.  Functions with
  this prototype are registered to be dispatched by the UnitTest framework after
  running all of the test cases in a test suite.  It will only be run once at
  the end of the suite.

  The purpose of this function is to clean up any global state or test data.
**/
typedef
VOID
(EFIAPI *UNIT_TEST_SUITE_TEARDOWN)(
  VOID
  );

/**
  Method to Initialize the Unit Test framework.  This function registers the
  test name and also initializes the internal state of the test framework to
  receive any new suites and tests.

  @param[out]  FrameworkHandle  Unit test framework to be created.
  @param[in]   Title            Null-terminated ASCII string that is the user
                                friendly name of the framework. String is
                                copied.
  @param[in]   ShortTitle       Null-terminated ASCII short string that is the
                                short name of the framework with no spaces.
                                String is copied.
  @param[in]   VersionString    Null-terminated ASCII version string for the
                                framework. String is copied.

  @retval  EFI_SUCCESS            The unit test framework was initialized.
  @retval  EFI_INVALID_PARAMETER  FrameworkHandle is NULL.
  @retval  EFI_INVALID_PARAMETER  Title is NULL.
  @retval  EFI_INVALID_PARAMETER  ShortTitle is NULL.
  @retval  EFI_INVALID_PARAMETER  VersionString is NULL.
  @retval  EFI_INVALID_PARAMETER  ShortTitle is invalid.
  @retval  EFI_OUT_OF_RESOURCES   There are not enough resources available to
                                  initialize the unit test framework.
**/
EFI_STATUS
EFIAPI
InitUnitTestFramework (
  OUT UNIT_TEST_FRAMEWORK_HANDLE  *FrameworkHandle,
  IN  CHAR8                       *Title,
  IN  CHAR8                       *ShortTitle,
  IN  CHAR8                       *VersionString
  );

/**
  Registers a Unit Test Suite in the Unit Test Framework.
  At least one test suite must be registered, because all test cases must be
  within a unit test suite.

  @param[out]  SuiteHandle      Unit test suite to create
  @param[in]   FrameworkHandle  Unit test framework to add unit test suite to
  @param[in]   Title            Null-terminated ASCII string that is the user
                                friendly name of the test suite.  String is
                                copied.
  @param[in]   Name             Null-terminated ASCII string that is the short
                                name of the test suite with no spaces.  String
                                is copied.
  @param[in]   Setup            Setup function, runs before suite.  This is an
                                optional parameter that may be NULL.
  @param[in]   Teardown         Teardown function, runs after suite.  This is an
                                optional parameter that may be NULL.

  @retval  EFI_SUCCESS            The unit test suite was created.
  @retval  EFI_INVALID_PARAMETER  SuiteHandle is NULL.
  @retval  EFI_INVALID_PARAMETER  FrameworkHandle is NULL.
  @retval  EFI_INVALID_PARAMETER  Title is NULL.
  @retval  EFI_INVALID_PARAMETER  Name is NULL.
  @retval  EFI_OUT_OF_RESOURCES   There are not enough resources available to
                                  initialize the unit test suite.
**/
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
  );

/**
  Adds test case to Suite

  @param[in]  SuiteHandle   Unit test suite to add test to.
  @param[in]  Description   Null-terminated ASCII string that is the user
                            friendly description of a test.  String is copied.
  @param[in]  Name          Null-terminated ASCII string that is the short name
                            of the test with no spaces.  String is copied.
  @param[in]  Function      Unit test function.
  @param[in]  Prerequisite  Prerequisite function, runs before test.  This is
                            an optional parameter that may be NULL.
  @param[in]  CleanUp       Clean up function, runs after test.  This is an
                            optional parameter that may be NULL.
  @param[in]  Context       Pointer to context.    This is an optional parameter
                            that may be NULL.

  @retval  EFI_SUCCESS            The unit test case was added to Suite.
  @retval  EFI_INVALID_PARAMETER  SuiteHandle is NULL.
  @retval  EFI_INVALID_PARAMETER  Description is NULL.
  @retval  EFI_INVALID_PARAMETER  Name is NULL.
  @retval  EFI_INVALID_PARAMETER  Function is NULL.
  @retval  EFI_OUT_OF_RESOURCES   There are not enough resources available to
                                  add the unit test case to Suite.
**/
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
  );

/**
  Execute all unit test cases in all unit test suites added to a Framework.

  Once a unit test framework is initialized and all unit test suites and unit
  test cases are registered, this function will cause the unit test framework to
  dispatch all unit test cases in sequence and record the results for reporting.

  @param[in]  FrameworkHandle  A handle to the current running framework that
                               dispatched the test.  Necessary for recording
                               certain test events with the framework.

  @retval  EFI_SUCCESS            All test cases were dispatched.
  @retval  EFI_INVALID_PARAMETER  FrameworkHandle is NULL.
**/
EFI_STATUS
EFIAPI
RunAllTestSuites (
  IN UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle
  );

/**
  Cleanup a test framework.

  After tests are run, this will teardown the entire framework and free all
  allocated data within.

  @param[in]  FrameworkHandle  A handle to the current running framework that
                               dispatched the test.  Necessary for recording
                               certain test events with the framework.

  @retval  EFI_SUCCESS            All resources associated with framework were
                                  freed.
  @retval  EFI_INVALID_PARAMETER  FrameworkHandle is NULL.
**/
EFI_STATUS
EFIAPI
FreeUnitTestFramework (
  IN UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle
  );

/**
  Leverages a framework-specific mechanism (see UnitTestPersistenceLib if you're
  a framework author) to save the state of the executing framework along with
  any allocated data so that the test may be resumed upon reentry. A test case
  should pass any needed context (which, to prevent an infinite loop, should be
  at least the current execution count) which will be saved by the framework and
  passed to the test case upon resume.

  This should be called while the current test framework is valid and active. It is
  generally called from within a test case prior to quitting or rebooting.

  @param[in]  ContextToSave      A buffer of test case-specific data to be saved
                                 along with framework state.  Will be passed as
                                 "Context" to the test case upon resume.  This
                                 is an optional parameter that may be NULL.
  @param[in]  ContextToSaveSize  Size of the ContextToSave buffer.

  @retval  EFI_SUCCESS            The framework state and context were saved.
  @retval  EFI_NOT_FOUND          An active framework handle was not found.
  @retval  EFI_INVALID_PARAMETER  ContextToSave is not NULL and
                                  ContextToSaveSize is 0.
  @retval  EFI_INVALID_PARAMETER  ContextToSave is >= 4GB.
  @retval  EFI_OUT_OF_RESOURCES   There are not enough resources available to
                                  save the framework and context state.
  @retval  EFI_DEVICE_ERROR       The framework and context state could not be
                                  saved to a persistent storage device due to a
                                  device error.
**/
EFI_STATUS
EFIAPI
SaveFrameworkState (
  IN UNIT_TEST_CONTEXT           ContextToSave     OPTIONAL,
  IN UINTN                       ContextToSaveSize
  );

/**
  This macro uses the framework assertion logic to check an expression for
  "TRUE". If the expression evaluates to TRUE, execution continues.
  Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED.

  @param[in]  Expression  Expression to be evaluated for TRUE.
**/
#define UT_ASSERT_TRUE(Expression)                                                                 \
  if(!UnitTestAssertTrue ((Expression), __FUNCTION__, DEBUG_LINE_NUMBER, __FILE__, #Expression)) { \
    return UNIT_TEST_ERROR_TEST_FAILED;                                                            \
  }

/**
  This macro uses the framework assertion logic to check an expression for
  "FALSE". If the expression evaluates to FALSE, execution continues.
  Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED.

  @param[in]  Expression  Expression to be evaluated for FALSE.
**/
#define UT_ASSERT_FALSE(Expression)                                                                 \
  if(!UnitTestAssertFalse ((Expression), __FUNCTION__, DEBUG_LINE_NUMBER, __FILE__, #Expression)) { \
    return UNIT_TEST_ERROR_TEST_FAILED;                                                             \
  }

/**
  This macro uses the framework assertion logic to check whether two simple
  values are equal.  If the values are equal, execution continues.
  Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED.

  @param[in]  ValueA  Value to be compared for equality (64-bit comparison).
  @param[in]  ValueB  Value to be compared for equality (64-bit comparison).
**/
#define UT_ASSERT_EQUAL(ValueA, ValueB)                                                                           \
  if(!UnitTestAssertEqual ((UINT64)(ValueA), (UINT64)(ValueB), __FUNCTION__, DEBUG_LINE_NUMBER, __FILE__, #ValueA, #ValueB)) { \
    return UNIT_TEST_ERROR_TEST_FAILED;                                                                           \
  }

/**
  This macro uses the framework assertion logic to check whether two memory
  buffers are equal.  If the buffers are equal, execution continues.
  Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED.

  @param[in]  BufferA  Pointer to a buffer for comparison.
  @param[in]  BufferB  Pointer to a buffer for comparison.
  @param[in]  Length   Number of bytes to compare in BufferA and BufferB.
**/
#define UT_ASSERT_MEM_EQUAL(BufferA, BufferB, Length)                                                                                                              \
  if(!UnitTestAssertMemEqual ((VOID *)(UINTN)(BufferA), (VOID *)(UINTN)(BufferB), (UINTN)Length, __FUNCTION__, DEBUG_LINE_NUMBER, __FILE__, #BufferA, #BufferB)) { \
    return UNIT_TEST_ERROR_TEST_FAILED;                                                                                                                            \
  }

/**
  This macro uses the framework assertion logic to check whether two simple
  values are non-equal.  If the values are non-equal, execution continues.
  Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED.

  @param[in]  ValueA  Value to be compared for inequality (64-bit comparison).
  @param[in]  ValueB  Value to be compared for inequality (64-bit comparison).
**/
#define UT_ASSERT_NOT_EQUAL(ValueA, ValueB)                                                                                       \
  if(!UnitTestAssertNotEqual ((UINT64)(ValueA), (UINT64)(ValueB), __FUNCTION__, DEBUG_LINE_NUMBER, __FILE__, #ValueA, #ValueB)) { \
    return UNIT_TEST_ERROR_TEST_FAILED;                                                                                           \
  }

/**
  This macro uses the framework assertion logic to check whether an EFI_STATUS
  value is !EFI_ERROR().  If the status is !EFI_ERROR(), execution continues.
  Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED.

  @param[in]  Status  EFI_STATUS value to check.
**/
#define UT_ASSERT_NOT_EFI_ERROR(Status)                                                           \
  if(!UnitTestAssertNotEfiError ((Status), __FUNCTION__, DEBUG_LINE_NUMBER, __FILE__, #Status)) { \
    return UNIT_TEST_ERROR_TEST_FAILED;                                                           \
  }

/**
  This macro uses the framework assertion logic to check whether two EFI_STATUS
  values are equal.  If the values are equal, execution continues.
  Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED.

  @param[in]  Status    EFI_STATUS values to compare for equality.
  @param[in]  Expected  EFI_STATUS values to compare for equality.
**/
#define UT_ASSERT_STATUS_EQUAL(Status, Expected)                                                              \
  if(!UnitTestAssertStatusEqual ((Status), (Expected), __FUNCTION__, DEBUG_LINE_NUMBER, __FILE__, #Status)) { \
    return UNIT_TEST_ERROR_TEST_FAILED;                                                                       \
  }

/**
  This macro uses the framework assertion logic to check whether a pointer is
  not NULL.  If the pointer is not NULL, execution continues. Otherwise, the
  test case immediately returns UNIT_TEST_ERROR_TEST_FAILED.

  @param[in]  Pointer  Pointer to be checked against NULL.
**/
#define UT_ASSERT_NOT_NULL(Pointer)                                                             \
  if(!UnitTestAssertNotNull ((Pointer), __FUNCTION__, DEBUG_LINE_NUMBER, __FILE__, #Pointer)) { \
    return UNIT_TEST_ERROR_TEST_FAILED;                                                         \
  }

/**
  This macro uses the framework assertion logic to check whether a function call
  triggers an ASSERT() condition.  The BaseLib SetJump()/LongJump() services
  are used to establish a safe return point when an ASSERT() is triggered.
  If an ASSERT() is triggered, unit test execution continues and Status is set
  to UNIT_TEST_PASSED.  Otherwise, a unit test case failure is raised and
  Status is set to UNIT_TEST_ERROR_TEST_FAILED.

  If ASSERT() macros are disabled, then the test case is skipped and a warning
  message is added to the unit test log.  Status is set to UNIT_TEST_SKIPPED.

  @param[in]  FunctionCall  Function call that is expected to trigger ASSERT().
  @param[out] Status        Pointer to a UNIT_TEST_STATUS return value.  This
                            is an optional parameter that may be NULL.
**/
#if defined (EDKII_UNIT_TEST_FRAMEWORK_ENABLED)
  #include <Library/BaseLib.h>

  ///
  /// Pointer to jump buffer used with SetJump()/LongJump() to test if a
  /// function under test generates an expected ASSERT() condition.
  ///
  extern BASE_LIBRARY_JUMP_BUFFER  *gUnitTestExpectAssertFailureJumpBuffer;

  #define UT_EXPECT_ASSERT_FAILURE(FunctionCall, Status)               \
    do {                                                               \
      UNIT_TEST_STATUS          UnitTestJumpStatus;                    \
      BASE_LIBRARY_JUMP_BUFFER  UnitTestJumpBuffer;                    \
      UnitTestJumpStatus = UNIT_TEST_SKIPPED;                          \
      if (DebugAssertEnabled ()) {                                     \
        gUnitTestExpectAssertFailureJumpBuffer = &UnitTestJumpBuffer;  \
        if (SetJump (gUnitTestExpectAssertFailureJumpBuffer) == 0) {   \
          FunctionCall;                                                \
          UnitTestJumpStatus = UNIT_TEST_ERROR_TEST_FAILED;            \
        } else {                                                       \
          UnitTestJumpStatus = UNIT_TEST_PASSED;                       \
        }                                                              \
        gUnitTestExpectAssertFailureJumpBuffer = NULL;                 \
      }                                                                \
      if (!UnitTestExpectAssertFailure (                               \
             UnitTestJumpStatus,                                       \
             __FUNCTION__, DEBUG_LINE_NUMBER, __FILE__,                \
             #FunctionCall, Status)) {                                 \
        return UNIT_TEST_ERROR_TEST_FAILED;                            \
      }                                                                \
    } while (FALSE)
#else
  #define UT_EXPECT_ASSERT_FAILURE(FunctionCall, Status)  FunctionCall;
#endif

/**
  If Expression is TRUE, then TRUE is returned.
  If Expression is FALSE, then an assert is triggered and the location of the
  assert provided by FunctionName, LineNumber, FileName, and Description are
  recorded and FALSE is returned.

  @param[in]  Expression    The BOOLEAN result of the expression evaluation.
  @param[in]  FunctionName  Null-terminated ASCII string of the function
                            executing the assert macro.
  @param[in]  LineNumber    The source file line number of the assert macro.
  @param[in]  FileName      Null-terminated ASCII string of the filename
                            executing the assert macro.
  @param[in]  Description   Null-terminated ASCII string of the expression being
                            evaluated.

  @retval  TRUE   Expression is TRUE.
  @retval  FALSE  Expression is FALSE.
**/
BOOLEAN
EFIAPI
UnitTestAssertTrue (
  IN BOOLEAN      Expression,
  IN CONST CHAR8  *FunctionName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *FileName,
  IN CONST CHAR8  *Description
  );

/**
  If Expression is FALSE, then TRUE is returned.
  If Expression is TRUE, then an assert is triggered and the location of the
  assert provided by FunctionName, LineNumber, FileName, and Description are
  recorded and FALSE is returned.

  @param[in]  Expression    The BOOLEAN result of the expression evaluation.
  @param[in]  FunctionName  Null-terminated ASCII string of the function
                            executing the assert macro.
  @param[in]  LineNumber    The source file line number of the assert macro.
  @param[in]  FileName      Null-terminated ASCII string of the filename
                            executing the assert macro.
  @param[in]  Description   Null-terminated ASCII string of the expression being
                            evaluated.

  @retval  TRUE   Expression is FALSE.
  @retval  FALSE  Expression is TRUE.
**/
BOOLEAN
EFIAPI
UnitTestAssertFalse (
  IN BOOLEAN      Expression,
  IN CONST CHAR8  *FunctionName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *FileName,
  IN CONST CHAR8  *Description
  );

/**
  If Status is not an EFI_ERROR(), then TRUE is returned.
  If Status is an EFI_ERROR(), then an assert is triggered and the location of
  the assert provided by FunctionName, LineNumber, FileName, and Description are
  recorded and FALSE is returned.

  @param[in]  Status        The EFI_STATUS value to evaluate.
  @param[in]  FunctionName  Null-terminated ASCII string of the function
                            executing the assert macro.
  @param[in]  LineNumber    The source file line number of the assert macro.
  @param[in]  FileName      Null-terminated ASCII string of the filename
                            executing the assert macro.
  @param[in]  Description   Null-terminated ASCII string of the status
                            expression being evaluated.

  @retval  TRUE   Status is not an EFI_ERROR().
  @retval  FALSE  Status is an EFI_ERROR().
**/
BOOLEAN
EFIAPI
UnitTestAssertNotEfiError (
  IN EFI_STATUS   Status,
  IN CONST CHAR8  *FunctionName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *FileName,
  IN CONST CHAR8  *Description
  );

/**
  If ValueA is equal ValueB, then TRUE is returned.
  If ValueA is not equal to ValueB, then an assert is triggered and the location
  of the assert provided by FunctionName, LineNumber, FileName, DescriptionA,
  and DescriptionB are recorded and FALSE is returned.

  @param[in]  ValueA        64-bit value.
  @param[in]  ValueB        64-bit value.
  @param[in]  FunctionName  Null-terminated ASCII string of the function
                            executing the assert macro.
  @param[in]  LineNumber    The source file line number of the assert macro.
  @param[in]  FileName      Null-terminated ASCII string of the filename
                            executing the assert macro.
  @param[in]  DescriptionA  Null-terminated ASCII string that is a description
                            of ValueA.
  @param[in]  DescriptionB  Null-terminated ASCII string that is a description
                            of ValueB.

  @retval  TRUE   ValueA is equal to ValueB.
  @retval  FALSE  ValueA is not equal to ValueB.
**/
BOOLEAN
EFIAPI
UnitTestAssertEqual (
  IN UINT64       ValueA,
  IN UINT64       ValueB,
  IN CONST CHAR8  *FunctionName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *FileName,
  IN CONST CHAR8  *DescriptionA,
  IN CONST CHAR8  *DescriptionB
  );

/**
  If the contents of BufferA are identical to the contents of BufferB, then TRUE
  is returned.  If the contents of BufferA are not identical to the contents of
  BufferB, then an assert is triggered and the location of the assert provided
  by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are
  recorded and FALSE is returned.

  @param[in]  BufferA       Pointer to a buffer for comparison.
  @param[in]  BufferB       Pointer to a buffer for comparison.
  @param[in]  Length        Number of bytes to compare in BufferA and BufferB.
  @param[in]  FunctionName  Null-terminated ASCII string of the function
                            executing the assert macro.
  @param[in]  LineNumber    The source file line number of the assert macro.
  @param[in]  FileName      Null-terminated ASCII string of the filename
                            executing the assert macro.
  @param[in]  DescriptionA  Null-terminated ASCII string that is a description
                            of BufferA.
  @param[in]  DescriptionB  Null-terminated ASCII string that is a description
                            of BufferB.

  @retval  TRUE   The contents of BufferA are identical to the contents of
                  BufferB.
  @retval  FALSE  The contents of BufferA are not identical to the contents of
                  BufferB.
**/
BOOLEAN
EFIAPI
UnitTestAssertMemEqual (
  IN VOID         *BufferA,
  IN VOID         *BufferB,
  IN UINTN        Length,
  IN CONST CHAR8  *FunctionName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *FileName,
  IN CONST CHAR8  *DescriptionA,
  IN CONST CHAR8  *DescriptionB
  );

/**
  If ValueA is not equal ValueB, then TRUE is returned.
  If ValueA is equal to ValueB, then an assert is triggered and the location
  of the assert provided by FunctionName, LineNumber, FileName, DescriptionA
  and DescriptionB are recorded and FALSE is returned.

  @param[in]  ValueA        64-bit value.
  @param[in]  ValueB        64-bit value.
  @param[in]  FunctionName  Null-terminated ASCII string of the function
                            executing the assert macro.
  @param[in]  LineNumber    The source file line number of the assert macro.
  @param[in]  FileName      Null-terminated ASCII string of the filename
                            executing the assert macro.
  @param[in]  DescriptionA  Null-terminated ASCII string that is a description
                            of ValueA.
  @param[in]  DescriptionB  Null-terminated ASCII string that is a description
                            of ValueB.

  @retval  TRUE   ValueA is not equal to ValueB.
  @retval  FALSE  ValueA is equal to ValueB.
**/
BOOLEAN
EFIAPI
UnitTestAssertNotEqual (
  IN UINT64       ValueA,
  IN UINT64       ValueB,
  IN CONST CHAR8  *FunctionName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *FileName,
  IN CONST CHAR8  *DescriptionA,
  IN CONST CHAR8  *DescriptionB
  );

/**
  If Status is equal to Expected, then TRUE is returned.
  If Status is not equal to Expected, then an assert is triggered and the
  location of the assert provided by FunctionName, LineNumber, FileName, and
  Description are recorded and FALSE is returned.

  @param[in]  Status        EFI_STATUS value returned from an API under test.
  @param[in]  Expected      The expected EFI_STATUS return value from an API
                            under test.
  @param[in]  FunctionName  Null-terminated ASCII string of the function
                            executing the assert macro.
  @param[in]  LineNumber    The source file line number of the assert macro.
  @param[in]  FileName      Null-terminated ASCII string of the filename
                            executing the assert macro.
  @param[in]  Description   Null-terminated ASCII string that is a description
                            of Status.

  @retval  TRUE   Status is equal to Expected.
  @retval  FALSE  Status is not equal to Expected.
**/
BOOLEAN
EFIAPI
UnitTestAssertStatusEqual (
  IN EFI_STATUS   Status,
  IN EFI_STATUS   Expected,
  IN CONST CHAR8  *FunctionName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *FileName,
  IN CONST CHAR8  *Description
  );

/**
  If Pointer is not equal to NULL, then TRUE is returned.
  If Pointer is equal to NULL, then an assert is triggered and the location of
  the assert provided by FunctionName, LineNumber, FileName, and PointerName
  are recorded and FALSE is returned.

  @param[in]  Pointer       Pointer value to be checked against NULL.
  @param[in]  Expected      The expected EFI_STATUS return value from a function
                            under test.
  @param[in]  FunctionName  Null-terminated ASCII string of the function
                            executing the assert macro.
  @param[in]  LineNumber    The source file line number of the assert macro.
  @param[in]  FileName      Null-terminated ASCII string of the filename
                            executing the assert macro.
  @param[in]  PointerName   Null-terminated ASCII string that is a description
                            of Pointer.

  @retval  TRUE   Pointer is not equal to NULL.
  @retval  FALSE  Pointer is equal to NULL.
**/
BOOLEAN
EFIAPI
UnitTestAssertNotNull (
  IN VOID         *Pointer,
  IN CONST CHAR8  *FunctionName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *FileName,
  IN CONST CHAR8  *PointerName
  );

/**
  If UnitTestStatus is UNIT_TEST_PASSED, then log an info message and return
  TRUE because an ASSERT() was expected when FunctionCall was executed and an
  ASSERT() was triggered. If UnitTestStatus is UNIT_TEST_SKIPPED, then log a
  warning message and return TRUE because ASSERT() macros are disabled.  If
  UnitTestStatus is UNIT_TEST_ERROR_TEST_FAILED, then log an error message and
  return FALSE because an ASSERT() was expected when FunctionCall was executed,
  but no ASSERT() conditions were triggered.  The log messages contain
  FunctionName, LineNumber, and FileName strings to provide the location of the
  UT_EXPECT_ASSERT_FAILURE() macro.

  @param[in]  UnitTestStatus  The status from UT_EXPECT_ASSERT_FAILURE() that
                              is either pass, skipped, or failed.
  @param[in]  FunctionName    Null-terminated ASCII string of the function
                              executing the UT_EXPECT_ASSERT_FAILURE() macro.
  @param[in]  LineNumber      The source file line number of the the function
                              executing the UT_EXPECT_ASSERT_FAILURE() macro.
  @param[in]  FileName        Null-terminated ASCII string of the filename
                              executing the UT_EXPECT_ASSERT_FAILURE() macro.
  @param[in]  FunctionCall    Null-terminated ASCII string of the function call
                              executed by the UT_EXPECT_ASSERT_FAILURE() macro.
  @param[out] ResultStatus    Used to return the UnitTestStatus value to the
                              caller of UT_EXPECT_ASSERT_FAILURE().  This is
                              optional parameter that may be NULL.

  @retval  TRUE   UnitTestStatus is UNIT_TEST_PASSED.
  @retval  TRUE   UnitTestStatus is UNIT_TEST_SKIPPED.
  @retval  FALSE  UnitTestStatus is UNIT_TEST_ERROR_TEST_FAILED.
**/
BOOLEAN
EFIAPI
UnitTestExpectAssertFailure (
  IN  UNIT_TEST_STATUS  UnitTestStatus,
  IN  CONST CHAR8       *FunctionName,
  IN  UINTN             LineNumber,
  IN  CONST CHAR8       *FileName,
  IN  CONST CHAR8       *FunctionCall,
  OUT UNIT_TEST_STATUS  *ResultStatus  OPTIONAL
  );

/**
  Test logging macro that records an ERROR message in the test framework log.
  Record is associated with the currently executing test case.

  @param[in]  Format  Formatting string following the format defined in
                      MdePkg/Include/Library/PrintLib.h.
  @param[in]  ...     Print args.
**/
#define UT_LOG_ERROR(Format, ...)  \
  UnitTestLog (UNIT_TEST_LOG_LEVEL_ERROR, Format, ##__VA_ARGS__)

/**
  Test logging macro that records a WARNING message in the test framework log.
  Record is associated with the currently executing test case.

  @param[in]  Format  Formatting string following the format defined in
                      MdePkg/Include/Library/PrintLib.h.
  @param[in]  ...     Print args.
**/
#define UT_LOG_WARNING(Format, ...)  \
  UnitTestLog (UNIT_TEST_LOG_LEVEL_WARN, Format, ##__VA_ARGS__)

/**
  Test logging macro that records an INFO message in the test framework log.
  Record is associated with the currently executing test case.

  @param[in]  Format  Formatting string following the format defined in
                      MdePkg/Include/Library/PrintLib.h.
  @param[in]  ...     Print args.
**/
#define UT_LOG_INFO(Format, ...)  \
  UnitTestLog (UNIT_TEST_LOG_LEVEL_INFO, Format, ##__VA_ARGS__)

/**
  Test logging macro that records a VERBOSE message in the test framework log.
  Record is associated with the currently executing test case.

  @param[in]  Format  Formatting string following the format defined in
                      MdePkg/Include/Library/PrintLib.h.
  @param[in]  ...     Print args.
**/
#define UT_LOG_VERBOSE(Format, ...)  \
  UnitTestLog (UNIT_TEST_LOG_LEVEL_VERBOSE, Format, ##__VA_ARGS__)

/**
  Test logging function that records a messages in the test framework log.
  Record is associated with the currently executing test case.

  @param[in]  ErrorLevel  The error level of the unit test log message.
  @param[in]  Format      Formatting string following the format defined in the
                          MdePkg/Include/Library/PrintLib.h.
  @param[in]  ...         Print args.
**/
VOID
EFIAPI
UnitTestLog (
  IN  UINTN        ErrorLevel,
  IN  CONST CHAR8  *Format,
  ...
  );

#endif