2 Unit tests of Base64 conversion APIs in BaseLib.
4 Copyright (C) Microsoft Corporation.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/BaseLib.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/MemoryAllocationLib.h>
14 #include <Library/UnitTestLib.h>
16 #define UNIT_TEST_APP_NAME "BaseLib Unit Test Application"
17 #define UNIT_TEST_APP_VERSION "1.0"
20 RFC 4648 https://tools.ietf.org/html/rfc4648 test vectors
25 BASE64("foo") = "Zm9v"
26 BASE64("foob") = "Zm9vYg=="
27 BASE64("fooba") = "Zm9vYmE="
28 BASE64("foobar") = "Zm9vYmFy"
30 The test vectors are using ascii strings for the binary data
36 EFI_STATUS ExpectedStatus
;
44 #define B64_TEST_2 "Zg=="
45 #define BIN_TEST_2 "f"
47 #define B64_TEST_3 "Zm8="
48 #define BIN_TEST_3 "fo"
50 #define B64_TEST_4 "Zm9v"
51 #define BIN_TEST_4 "foo"
53 #define B64_TEST_5 "Zm9vYg=="
54 #define BIN_TEST_5 "foob"
56 #define B64_TEST_6 "Zm9vYmE="
57 #define BIN_TEST_6 "fooba"
59 #define B64_TEST_7 "Zm9vYmFy"
60 #define BIN_TEST_7 "foobar"
62 // Adds all white space - also ends the last quantum with only spaces afterwards
63 #define B64_TEST_8_IN " \t\v Zm9\r\nvYmFy \f "
64 #define BIN_TEST_8 "foobar"
66 // Not a quantum multiple of 4
67 #define B64_ERROR_1 "Zm9vymFy="
69 // Invalid characters in the string
70 #define B64_ERROR_2 "Zm$vymFy"
72 // Too many '=' characters
73 #define B64_ERROR_3 "Z==="
76 #define B64_ERROR_4 "Zm=vYmFy"
78 #define MAX_TEST_STRING_SIZE (200)
80 // ------------------------------------------------ Input----------Output-----------Result-------Free--Expected Output Size
81 static BASIC_TEST_CONTEXT mBasicEncodeTest1
= { BIN_TEST_1
, B64_TEST_1
, EFI_SUCCESS
, NULL
, sizeof (B64_TEST_1
) };
82 static BASIC_TEST_CONTEXT mBasicEncodeTest2
= { BIN_TEST_2
, B64_TEST_2
, EFI_SUCCESS
, NULL
, sizeof (B64_TEST_2
) };
83 static BASIC_TEST_CONTEXT mBasicEncodeTest3
= { BIN_TEST_3
, B64_TEST_3
, EFI_SUCCESS
, NULL
, sizeof (B64_TEST_3
) };
84 static BASIC_TEST_CONTEXT mBasicEncodeTest4
= { BIN_TEST_4
, B64_TEST_4
, EFI_SUCCESS
, NULL
, sizeof (B64_TEST_4
) };
85 static BASIC_TEST_CONTEXT mBasicEncodeTest5
= { BIN_TEST_5
, B64_TEST_5
, EFI_SUCCESS
, NULL
, sizeof (B64_TEST_5
) };
86 static BASIC_TEST_CONTEXT mBasicEncodeTest6
= { BIN_TEST_6
, B64_TEST_6
, EFI_SUCCESS
, NULL
, sizeof (B64_TEST_6
) };
87 static BASIC_TEST_CONTEXT mBasicEncodeTest7
= { BIN_TEST_7
, B64_TEST_7
, EFI_SUCCESS
, NULL
, sizeof (B64_TEST_7
) };
88 static BASIC_TEST_CONTEXT mBasicEncodeError1
= { BIN_TEST_7
, B64_TEST_1
, EFI_BUFFER_TOO_SMALL
, NULL
, sizeof (B64_TEST_7
) };
90 static BASIC_TEST_CONTEXT mBasicDecodeTest1
= { B64_TEST_1
, BIN_TEST_1
, EFI_SUCCESS
, NULL
, sizeof (BIN_TEST_1
)-1 };
91 static BASIC_TEST_CONTEXT mBasicDecodeTest2
= { B64_TEST_2
, BIN_TEST_2
, EFI_SUCCESS
, NULL
, sizeof (BIN_TEST_2
)-1 };
92 static BASIC_TEST_CONTEXT mBasicDecodeTest3
= { B64_TEST_3
, BIN_TEST_3
, EFI_SUCCESS
, NULL
, sizeof (BIN_TEST_3
)-1 };
93 static BASIC_TEST_CONTEXT mBasicDecodeTest4
= { B64_TEST_4
, BIN_TEST_4
, EFI_SUCCESS
, NULL
, sizeof (BIN_TEST_4
)-1 };
94 static BASIC_TEST_CONTEXT mBasicDecodeTest5
= { B64_TEST_5
, BIN_TEST_5
, EFI_SUCCESS
, NULL
, sizeof (BIN_TEST_5
)-1 };
95 static BASIC_TEST_CONTEXT mBasicDecodeTest6
= { B64_TEST_6
, BIN_TEST_6
, EFI_SUCCESS
, NULL
, sizeof (BIN_TEST_6
)-1 };
96 static BASIC_TEST_CONTEXT mBasicDecodeTest7
= { B64_TEST_7
, BIN_TEST_7
, EFI_SUCCESS
, NULL
, sizeof (BIN_TEST_7
)-1 };
97 static BASIC_TEST_CONTEXT mBasicDecodeTest8
= { B64_TEST_8_IN
, BIN_TEST_8
, EFI_SUCCESS
, NULL
, sizeof (BIN_TEST_8
)-1 };
99 static BASIC_TEST_CONTEXT mBasicDecodeError1
= { B64_ERROR_1
, B64_ERROR_1
, EFI_INVALID_PARAMETER
, NULL
, 0 };
100 static BASIC_TEST_CONTEXT mBasicDecodeError2
= { B64_ERROR_2
, B64_ERROR_2
, EFI_INVALID_PARAMETER
, NULL
, 0 };
101 static BASIC_TEST_CONTEXT mBasicDecodeError3
= { B64_ERROR_3
, B64_ERROR_3
, EFI_INVALID_PARAMETER
, NULL
, 0 };
102 static BASIC_TEST_CONTEXT mBasicDecodeError4
= { B64_ERROR_4
, B64_ERROR_4
, EFI_INVALID_PARAMETER
, NULL
, 0 };
103 static BASIC_TEST_CONTEXT mBasicDecodeError5
= { B64_TEST_7
, BIN_TEST_1
, EFI_BUFFER_TOO_SMALL
, NULL
, sizeof (BIN_TEST_7
)-1 };
106 Simple clean up method to make sure tests clean up even if interrupted and fail
112 CleanUpB64TestContext (
113 IN UNIT_TEST_CONTEXT Context
116 BASIC_TEST_CONTEXT
*Btc
;
118 Btc
= (BASIC_TEST_CONTEXT
*)Context
;
120 // free string if set
121 if (Btc
->BufferToFree
!= NULL
) {
122 FreePool (Btc
->BufferToFree
);
123 Btc
->BufferToFree
= NULL
;
129 Unit test for Base64 encode APIs of BaseLib.
131 @param[in] Context [Optional] An optional parameter that enables:
132 1) test-case reuse with varied parameters and
133 2) test-case re-entry for Target tests that need a
134 reboot. This parameter is a VOID* and it is the
135 responsibility of the test author to ensure that the
136 contents are well understood by all test cases that may
139 @retval UNIT_TEST_PASSED The Unit test has completed and the test
141 @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
147 IN UNIT_TEST_CONTEXT Context
150 BASIC_TEST_CONTEXT
*Btc
;
157 CHAR8
*b64WorkString
;
162 Btc
= (BASIC_TEST_CONTEXT
*)Context
;
163 binString
= Btc
->TestInput
;
164 b64String
= Btc
->TestOutput
;
167 // Only testing the the translate functionality, so preallocate the proper
171 b64StringSize
= AsciiStrnSizeS (b64String
, MAX_TEST_STRING_SIZE
);
172 BinSize
= AsciiStrnLenS (binString
, MAX_TEST_STRING_SIZE
);
173 BinData
= (UINT8
*)binString
;
175 b64WorkString
= (CHAR8
*)AllocatePool (b64StringSize
);
176 UT_ASSERT_NOT_NULL (b64WorkString
);
178 Btc
->BufferToFree
= b64WorkString
;
179 ReturnSize
= b64StringSize
;
181 Status
= Base64Encode (BinData
, BinSize
, b64WorkString
, &ReturnSize
);
183 UT_ASSERT_STATUS_EQUAL (Status
, Btc
->ExpectedStatus
);
185 UT_ASSERT_EQUAL (ReturnSize
, Btc
->ExpectedSize
);
187 if (!EFI_ERROR (Btc
->ExpectedStatus
)) {
188 if (ReturnSize
!= 0) {
189 CompareStatus
= AsciiStrnCmp (b64String
, b64WorkString
, ReturnSize
);
190 if (CompareStatus
!= 0) {
191 UT_LOG_ERROR ("b64 string compare error - size=%d\n", ReturnSize
);
192 for (indx
= 0; indx
< ReturnSize
; indx
++) {
193 UT_LOG_ERROR (" %2.2x", 0xff & b64String
[indx
]);
196 UT_LOG_ERROR ("\n b64 work string:\n");
197 for (indx
= 0; indx
< ReturnSize
; indx
++) {
198 UT_LOG_ERROR (" %2.2x", 0xff & b64WorkString
[indx
]);
204 UT_ASSERT_EQUAL (CompareStatus
, 0);
208 Btc
->BufferToFree
= NULL
;
209 FreePool (b64WorkString
);
210 return UNIT_TEST_PASSED
;
214 Unit test for Base64 decode APIs of BaseLib.
216 @param[in] Context [Optional] An optional parameter that enables:
217 1) test-case reuse with varied parameters and
218 2) test-case re-entry for Target tests that need a
219 reboot. This parameter is a VOID* and it is the
220 responsibility of the test author to ensure that the
221 contents are well understood by all test cases that may
224 @retval UNIT_TEST_PASSED The Unit test has completed and the test
226 @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
232 IN UNIT_TEST_CONTEXT Context
235 BASIC_TEST_CONTEXT
*Btc
;
246 Btc
= (BASIC_TEST_CONTEXT
*)Context
;
247 b64String
= Btc
->TestInput
;
248 binString
= Btc
->TestOutput
;
251 // Only testing the the translate functionality
254 b64StringLen
= AsciiStrnLenS (b64String
, MAX_TEST_STRING_SIZE
);
255 BinSize
= AsciiStrnLenS (binString
, MAX_TEST_STRING_SIZE
);
257 BinData
= AllocatePool (BinSize
);
258 UT_ASSERT_NOT_NULL (BinData
);
260 Btc
->BufferToFree
= BinData
;
261 ReturnSize
= BinSize
;
263 Status
= Base64Decode (b64String
, b64StringLen
, BinData
, &ReturnSize
);
265 UT_ASSERT_STATUS_EQUAL (Status
, Btc
->ExpectedStatus
);
267 // If an error is not expected, check the results
268 if (EFI_ERROR (Btc
->ExpectedStatus
)) {
269 if (Btc
->ExpectedStatus
== EFI_BUFFER_TOO_SMALL
) {
270 UT_ASSERT_EQUAL (ReturnSize
, Btc
->ExpectedSize
);
273 UT_ASSERT_EQUAL (ReturnSize
, Btc
->ExpectedSize
);
274 if (ReturnSize
!= 0) {
275 CompareStatus
= CompareMem (binString
, BinData
, ReturnSize
);
276 if (CompareStatus
!= 0) {
277 UT_LOG_ERROR ("bin string compare error - size=%d\n", ReturnSize
);
278 for (indx
= 0; indx
< ReturnSize
; indx
++) {
279 UT_LOG_ERROR (" %2.2x", 0xff & binString
[indx
]);
282 UT_LOG_ERROR ("\nBinData:\n");
283 for (indx
= 0; indx
< ReturnSize
; indx
++) {
284 UT_LOG_ERROR (" %2.2x", 0xff & BinData
[indx
]);
290 UT_ASSERT_EQUAL (CompareStatus
, 0);
294 Btc
->BufferToFree
= NULL
;
296 return UNIT_TEST_PASSED
;
299 #define SOURCE_STRING L"Hello"
304 SafeStringContraintCheckTest (
305 IN UNIT_TEST_CONTEXT Context
308 RETURN_STATUS Status
;
309 CHAR16 Destination
[20];
313 // Zero buffer used to verify Destination is not modified
315 ZeroMem (AllZero
, sizeof (AllZero
));
318 // Positive test case copy source unicode string to destination
320 ZeroMem (Destination
, sizeof (Destination
));
321 Status
= StrCpyS (Destination
, sizeof (Destination
) / sizeof (CHAR16
), SOURCE_STRING
);
322 UT_ASSERT_NOT_EFI_ERROR (Status
);
323 UT_ASSERT_MEM_EQUAL (Destination
, SOURCE_STRING
, sizeof (SOURCE_STRING
));
326 // Positive test case with DestMax the same as Source size
328 ZeroMem (Destination
, sizeof (Destination
));
329 Status
= StrCpyS (Destination
, sizeof (SOURCE_STRING
) / sizeof (CHAR16
), SOURCE_STRING
);
330 UT_ASSERT_NOT_EFI_ERROR (Status
);
331 UT_ASSERT_MEM_EQUAL (Destination
, SOURCE_STRING
, sizeof (SOURCE_STRING
));
334 // Negative test case with Destination NULL
336 ZeroMem (Destination
, sizeof (Destination
));
337 Status
= StrCpyS (NULL
, sizeof (Destination
) / sizeof (CHAR16
), SOURCE_STRING
);
338 UT_ASSERT_STATUS_EQUAL (Status
, RETURN_INVALID_PARAMETER
);
339 UT_ASSERT_MEM_EQUAL (Destination
, AllZero
, sizeof (AllZero
));
342 // Negative test case with Source NULL
344 ZeroMem (Destination
, sizeof (Destination
));
345 Status
= StrCpyS (Destination
, sizeof (Destination
) / sizeof (CHAR16
), NULL
);
346 UT_ASSERT_STATUS_EQUAL (Status
, RETURN_INVALID_PARAMETER
);
347 UT_ASSERT_MEM_EQUAL (Destination
, AllZero
, sizeof (AllZero
));
350 // Negative test case with DestMax too big
352 ZeroMem (Destination
, sizeof (Destination
));
353 Status
= StrCpyS (Destination
, MAX_UINTN
, SOURCE_STRING
);
354 UT_ASSERT_STATUS_EQUAL (Status
, RETURN_INVALID_PARAMETER
);
355 UT_ASSERT_MEM_EQUAL (Destination
, AllZero
, sizeof (AllZero
));
358 // Negative test case with DestMax 0
360 ZeroMem (Destination
, sizeof (Destination
));
361 Status
= StrCpyS (Destination
, 0, SOURCE_STRING
);
362 UT_ASSERT_STATUS_EQUAL (Status
, RETURN_INVALID_PARAMETER
);
363 UT_ASSERT_MEM_EQUAL (Destination
, AllZero
, sizeof (AllZero
));
366 // Negative test case with DestMax smaller than Source size
368 ZeroMem (Destination
, sizeof (Destination
));
369 Status
= StrCpyS (Destination
, 1, SOURCE_STRING
);
370 UT_ASSERT_STATUS_EQUAL (Status
, RETURN_BUFFER_TOO_SMALL
);
371 UT_ASSERT_MEM_EQUAL (Destination
, AllZero
, sizeof (AllZero
));
374 // Negative test case with DestMax smaller than Source size by one character
376 ZeroMem (Destination
, sizeof (Destination
));
377 Status
= StrCpyS (Destination
, sizeof (SOURCE_STRING
) / sizeof (CHAR16
) - 1, SOURCE_STRING
);
378 UT_ASSERT_STATUS_EQUAL (Status
, RETURN_BUFFER_TOO_SMALL
);
379 UT_ASSERT_MEM_EQUAL (Destination
, AllZero
, sizeof (AllZero
));
382 // Negative test case with overlapping Destination and Source
384 ZeroMem (Destination
, sizeof (Destination
));
385 Status
= StrCpyS (Destination
, sizeof (Destination
) / sizeof (CHAR16
), Destination
);
386 UT_ASSERT_STATUS_EQUAL (Status
, RETURN_ACCESS_DENIED
);
387 UT_ASSERT_MEM_EQUAL (Destination
, AllZero
, sizeof (AllZero
));
389 return UNIT_TEST_PASSED
;
393 Initialze the unit test framework, suite, and unit tests for the
394 Base64 conversion APIs of BaseLib and run the unit tests.
396 @retval EFI_SUCCESS All test cases were dispatched.
397 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
398 initialize the unit tests.
408 UNIT_TEST_FRAMEWORK_HANDLE Fw
;
409 UNIT_TEST_SUITE_HANDLE b64EncodeTests
;
410 UNIT_TEST_SUITE_HANDLE b64DecodeTests
;
411 UNIT_TEST_SUITE_HANDLE SafeStringTests
;
415 DEBUG ((DEBUG_INFO
, "%a v%a\n", UNIT_TEST_APP_NAME
, UNIT_TEST_APP_VERSION
));
418 // Start setting up the test framework for running the tests.
420 Status
= InitUnitTestFramework (&Fw
, UNIT_TEST_APP_NAME
, gEfiCallerBaseName
, UNIT_TEST_APP_VERSION
);
421 if (EFI_ERROR (Status
)) {
422 DEBUG ((DEBUG_ERROR
, "Failed in InitUnitTestFramework. Status = %r\n", Status
));
427 // Populate the B64 Encode Unit Test Suite.
429 Status
= CreateUnitTestSuite (&b64EncodeTests
, Fw
, "b64 Encode binary to Ascii string", "BaseLib.b64Encode", NULL
, NULL
);
430 if (EFI_ERROR (Status
)) {
431 DEBUG ((DEBUG_ERROR
, "Failed in CreateUnitTestSuite for b64EncodeTests\n"));
432 Status
= EFI_OUT_OF_RESOURCES
;
436 // --------------Suite-----------Description--------------Class Name----------Function--------Pre---Post-------------------Context-----------
437 AddTestCase (b64EncodeTests
, "RFC 4686 Test Vector - Empty", "Test1", RfcEncodeTest
, NULL
, CleanUpB64TestContext
, &mBasicEncodeTest1
);
438 AddTestCase (b64EncodeTests
, "RFC 4686 Test Vector - f", "Test2", RfcEncodeTest
, NULL
, CleanUpB64TestContext
, &mBasicEncodeTest2
);
439 AddTestCase (b64EncodeTests
, "RFC 4686 Test Vector - fo", "Test3", RfcEncodeTest
, NULL
, CleanUpB64TestContext
, &mBasicEncodeTest3
);
440 AddTestCase (b64EncodeTests
, "RFC 4686 Test Vector - foo", "Test4", RfcEncodeTest
, NULL
, CleanUpB64TestContext
, &mBasicEncodeTest4
);
441 AddTestCase (b64EncodeTests
, "RFC 4686 Test Vector - foob", "Test5", RfcEncodeTest
, NULL
, CleanUpB64TestContext
, &mBasicEncodeTest5
);
442 AddTestCase (b64EncodeTests
, "RFC 4686 Test Vector - fooba", "Test6", RfcEncodeTest
, NULL
, CleanUpB64TestContext
, &mBasicEncodeTest6
);
443 AddTestCase (b64EncodeTests
, "RFC 4686 Test Vector - foobar", "Test7", RfcEncodeTest
, NULL
, CleanUpB64TestContext
, &mBasicEncodeTest7
);
444 AddTestCase (b64EncodeTests
, "Too small of output buffer", "Error1", RfcEncodeTest
, NULL
, CleanUpB64TestContext
, &mBasicEncodeError1
);
446 // Populate the B64 Decode Unit Test Suite.
448 Status
= CreateUnitTestSuite (&b64DecodeTests
, Fw
, "b64 Decode Ascii string to binary", "BaseLib.b64Decode", NULL
, NULL
);
449 if (EFI_ERROR (Status
)) {
450 DEBUG ((DEBUG_ERROR
, "Failed in CreateUnitTestSuite for b64Decode Tests\n"));
451 Status
= EFI_OUT_OF_RESOURCES
;
455 AddTestCase (b64DecodeTests
, "RFC 4686 Test Vector - Empty", "Test1", RfcDecodeTest
, NULL
, CleanUpB64TestContext
, &mBasicDecodeTest1
);
456 AddTestCase (b64DecodeTests
, "RFC 4686 Test Vector - f", "Test2", RfcDecodeTest
, NULL
, CleanUpB64TestContext
, &mBasicDecodeTest2
);
457 AddTestCase (b64DecodeTests
, "RFC 4686 Test Vector - fo", "Test3", RfcDecodeTest
, NULL
, CleanUpB64TestContext
, &mBasicDecodeTest3
);
458 AddTestCase (b64DecodeTests
, "RFC 4686 Test Vector - foo", "Test4", RfcDecodeTest
, NULL
, CleanUpB64TestContext
, &mBasicDecodeTest4
);
459 AddTestCase (b64DecodeTests
, "RFC 4686 Test Vector - foob", "Test5", RfcDecodeTest
, NULL
, CleanUpB64TestContext
, &mBasicDecodeTest5
);
460 AddTestCase (b64DecodeTests
, "RFC 4686 Test Vector - fooba", "Test6", RfcDecodeTest
, NULL
, CleanUpB64TestContext
, &mBasicDecodeTest6
);
461 AddTestCase (b64DecodeTests
, "RFC 4686 Test Vector - foobar", "Test7", RfcDecodeTest
, NULL
, CleanUpB64TestContext
, &mBasicDecodeTest7
);
462 AddTestCase (b64DecodeTests
, "Ignore Whitespace test", "Test8", RfcDecodeTest
, NULL
, CleanUpB64TestContext
, &mBasicDecodeTest8
);
464 AddTestCase (b64DecodeTests
, "Not a quantum multiple of 4", "Error1", RfcDecodeTest
, NULL
, CleanUpB64TestContext
, &mBasicDecodeError1
);
465 AddTestCase (b64DecodeTests
, "Invalid characters in the string", "Error2", RfcDecodeTest
, NULL
, CleanUpB64TestContext
, &mBasicDecodeError2
);
466 AddTestCase (b64DecodeTests
, "Too many padding characters", "Error3", RfcDecodeTest
, NULL
, CleanUpB64TestContext
, &mBasicDecodeError3
);
467 AddTestCase (b64DecodeTests
, "Incorrectly placed padding character", "Error4", RfcDecodeTest
, NULL
, CleanUpB64TestContext
, &mBasicDecodeError4
);
468 AddTestCase (b64DecodeTests
, "Too small of output buffer", "Error5", RfcDecodeTest
, NULL
, CleanUpB64TestContext
, &mBasicDecodeError5
);
471 // Populate the safe string Unit Test Suite.
473 Status
= CreateUnitTestSuite (&SafeStringTests
, Fw
, "Safe String", "BaseLib.SafeString", NULL
, NULL
);
474 if (EFI_ERROR (Status
)) {
475 DEBUG ((DEBUG_ERROR
, "Failed in CreateUnitTestSuite for SafeStringTests\n"));
476 Status
= EFI_OUT_OF_RESOURCES
;
480 // --------------Suite-----------Description--------------Class Name----------Function--------Pre---Post-------------------Context-----------
481 AddTestCase (SafeStringTests
, "SAFE_STRING_CONSTRAINT_CHECK", "SafeStringContraintCheckTest", SafeStringContraintCheckTest
, NULL
, NULL
, NULL
);
484 // Execute the tests.
486 Status
= RunAllTestSuites (Fw
);
490 FreeUnitTestFramework (Fw
);
497 Standard UEFI entry point for target based unit test execution from UEFI Shell.
501 BaseLibUnitTestAppEntry (
502 IN EFI_HANDLE ImageHandle
,
503 IN EFI_SYSTEM_TABLE
*SystemTable
506 return UnitTestingEntry ();
510 Standard POSIX C entry point for host based unit test execution.
518 return UnitTestingEntry ();