Skip to content

Commit cc75db2

Browse files
KellesiVlada Kanivets
andauthored
Add tests for base64 (KF-25, #41)
* add tests for base64 * refactoring --------- Co-authored-by: Vlada Kanivets <vlada.kanivets@apriorit.com>
1 parent b992cfe commit cc75db2

File tree

3 files changed

+153
-1
lines changed

3 files changed

+153
-1
lines changed

include/kf/Base64.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ namespace kf
88

99
// original implementation is taken from https://github.com/adamvr/arduino-base64/blob/master/Base64.cpp
1010

11+
//////////////////////////////////////////////////////////////////////////////////
12+
// Base64 is utility for decoding Base64-encoded strings.
13+
// Only ASCII-compatible Base64 is supported.
14+
// Decoded buffer contains bytes as 'char', not 'WCHAR'.
15+
// If the string contains many '=' characters, the decoded length may be negative.
1116
class Base64
1217
{
1318
public:
@@ -20,7 +25,7 @@ namespace kf
2025

2126
int numEq = 0;
2227

23-
for (int i = input.charLength() - 1; static_cast<char>(input.charAt(i)) == '='; --i)
28+
for (int i = input.charLength() - 1; i >= 0 && static_cast<char>(input.charAt(i)) == '='; --i)
2429
{
2530
numEq++;
2631
}
@@ -36,6 +41,12 @@ namespace kf
3641
uint8_t a3[3];
3742
uint8_t a4[4];
3843

44+
int decodedLen = decodeLen(input);
45+
if (decodedLen < 0 || output.size() < decodedLen)
46+
{
47+
return -1;
48+
}
49+
3950
while (inputIdx < input.charLength())
4051
{
4152
auto ch = static_cast<char>(input.charAt(inputIdx++));

test/Base64Test.cpp

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#include "pch.h"
2+
#include <kf/Base64.h>
3+
#include <string_view>
4+
5+
SCENARIO("Base64::decodeLen")
6+
{
7+
WHEN("Encoded string is empty")
8+
{
9+
THEN("Decode length is 0")
10+
{
11+
REQUIRE(kf::Base64::decodeLen(L"") == 0);
12+
}
13+
}
14+
15+
WHEN("Encoded string is VA==")
16+
{
17+
THEN("Decode length is 1")
18+
{
19+
REQUIRE(kf::Base64::decodeLen(L"VA==") == 1); // "T"
20+
}
21+
}
22+
23+
WHEN("Encoded string is VGU=")
24+
{
25+
THEN("Decode length is 2")
26+
{
27+
REQUIRE(kf::Base64::decodeLen(L"VGU=") == 2); // "Te"
28+
}
29+
}
30+
31+
WHEN("Encoded string is VGVz")
32+
{
33+
THEN("Decode length is 3")
34+
{
35+
REQUIRE(kf::Base64::decodeLen(L"VGVz") == 3); // "Tes"
36+
}
37+
}
38+
39+
WHEN("Encoded string is VGVzdA==")
40+
{
41+
THEN("Decode length is 4")
42+
{
43+
REQUIRE(kf::Base64::decodeLen(L"VGVzdA==") == 4); // "Test"
44+
}
45+
}
46+
47+
WHEN("Encoded string is ==")
48+
{
49+
THEN("Decode length is -1")
50+
{
51+
REQUIRE(kf::Base64::decodeLen(L"==") == -1);
52+
}
53+
}
54+
}
55+
56+
57+
SCENARIO("Base64::decode")
58+
{
59+
GIVEN("Encoded string 'VA=='")
60+
{
61+
kf::USimpleString input(L"VA=="); // "T"
62+
constexpr std::wstring_view kExpectedOutput = L"T";
63+
constexpr size_t kExpectedLength = kExpectedOutput.size();
64+
std::array<wchar_t, kExpectedLength> output;
65+
66+
THEN("Decoded symbol is 'T' and decoded length is 1")
67+
{
68+
int written = kf::Base64::decode(input, std::as_writable_bytes(std::span{ output }));
69+
REQUIRE(written == kExpectedLength);
70+
71+
REQUIRE(std::wstring_view(output.data(), written) == kExpectedOutput);
72+
}
73+
}
74+
75+
GIVEN("Encoded string 'VGU='")
76+
{
77+
kf::USimpleString input(L"VGU="); // "Te"
78+
constexpr std::string_view kExpectedOutput = "Te";
79+
constexpr size_t kExpectedLength = kExpectedOutput.size();
80+
std::array<char, kExpectedLength> output;
81+
82+
THEN("Decoded symbols are 'Te' and decoded length is 2")
83+
{
84+
int written = kf::Base64::decode(input, std::as_writable_bytes(std::span{ output }));
85+
REQUIRE(written == kExpectedLength);
86+
REQUIRE(std::string_view(output.data(), written) == kExpectedOutput);
87+
}
88+
}
89+
90+
GIVEN("Encoded string 'VGhpcyBpcyBhIGxvbmcgdGVzdCBzdHJpbmcgZm9yIHVuaXQgdGVzdGluZw=='")
91+
{
92+
kf::USimpleString input(L"VGhpcyBpcyBhIGxvbmcgdGVzdCBzdHJpbmcgZm9yIHVuaXQgdGVzdGluZw==");
93+
constexpr std::string_view kExpectedOutput = "This is a long test string for unit testing";
94+
constexpr size_t kExpectedLength = kExpectedOutput.size();
95+
std::array<char, kExpectedLength> output;
96+
97+
THEN("Decoded symbols are 'This is a long test string for unit testing' and decoded length is correct")
98+
{
99+
int written = kf::Base64::decode(input, std::as_writable_bytes(std::span{ output }));
100+
REQUIRE(written == kExpectedLength);
101+
REQUIRE(std::string_view(output.data(), written) == kExpectedOutput);
102+
}
103+
}
104+
105+
GIVEN("Empty string")
106+
{
107+
kf::USimpleString input;
108+
std::array<char, 2> output;
109+
110+
THEN("Decoded length is 0")
111+
{
112+
int written = kf::Base64::decode(input, std::as_writable_bytes(std::span{ output }));
113+
REQUIRE(written == 0);
114+
}
115+
}
116+
117+
GIVEN("Output buffer isn't big enough")
118+
{
119+
kf::USimpleString input(L"VGVzdA==");
120+
std::array<char, 2> output;
121+
122+
THEN("Decode returns -1")
123+
{
124+
int written = kf::Base64::decode(input, std::as_writable_bytes(std::span{ output }));
125+
REQUIRE(written == -1);
126+
}
127+
}
128+
129+
GIVEN("Encoded string with negative decode length")
130+
{
131+
kf::USimpleString input(L"==");
132+
std::array<char, 2> output;
133+
134+
THEN("Decode returns -1")
135+
{
136+
int written = kf::Base64::decode(input, std::as_writable_bytes(std::span{ output }));
137+
REQUIRE(written == -1);
138+
}
139+
}
140+
}

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ wdk_add_driver(kf-test WINVER NTDDI_WIN10 STL
4444
HexTest.cpp
4545
MapTest.cpp
4646
Vector.cpp
47+
Base64Test.cpp
4748
)
4849

4950
target_link_libraries(kf-test kf::kf kmtest::kmtest)

0 commit comments

Comments
 (0)