xref: /aosp_15_r20/external/pigweed/pw_base64/base64_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_base64/base64.h"
16 
17 #include <cstring>
18 
19 #include "pw_unit_test/framework.h"
20 
21 namespace pw::base64 {
22 namespace {
23 
24 struct EncodedData {
25   const size_t binary_size;
26   const char* const binary_data;
27   const char* const encoded_data;
28 };
29 
30 /* The following test data was generated by this Python 3 script.
31 
32 #!/usr/bin/env python3
33 
34 import base64
35 import random
36 
37 
38 def b64_encode(raw_data):
39     encoded = base64.b64encode(raw_data).decode()
40     hex_string = ''.join(r'\x{:02x}'.format(b) for b in raw_data)
41 
42     print('    {{{size}, "{raw}", "{encoded}"}},'.format(
43         size=len(raw_data), raw=hex_string, encoded=encoded))
44 
45 
46 print('constexpr EncodedData kSingleCharTestData[] = {')
47 
48 for i in range(256):
49     b64_encode(bytes([i]))
50 
51 print('};')
52 print()
53 
54 print('constexpr EncodedData kRandomTestData[] = {')
55 
56 for length in range(2, 12):
57     for _ in range(10):
58         b64_encode(bytes(random.randrange(256) for _ in range(length)))
59 
60 print('};')
61 print()
62 
63 */
64 
65 constexpr EncodedData kSingleCharTestData[] = {
66     {1, "\x00", "AA=="}, {1, "\x01", "AQ=="}, {1, "\x02", "Ag=="},
67     {1, "\x03", "Aw=="}, {1, "\x04", "BA=="}, {1, "\x05", "BQ=="},
68     {1, "\x06", "Bg=="}, {1, "\x07", "Bw=="}, {1, "\x08", "CA=="},
69     {1, "\x09", "CQ=="}, {1, "\x0a", "Cg=="}, {1, "\x0b", "Cw=="},
70     {1, "\x0c", "DA=="}, {1, "\x0d", "DQ=="}, {1, "\x0e", "Dg=="},
71     {1, "\x0f", "Dw=="}, {1, "\x10", "EA=="}, {1, "\x11", "EQ=="},
72     {1, "\x12", "Eg=="}, {1, "\x13", "Ew=="}, {1, "\x14", "FA=="},
73     {1, "\x15", "FQ=="}, {1, "\x16", "Fg=="}, {1, "\x17", "Fw=="},
74     {1, "\x18", "GA=="}, {1, "\x19", "GQ=="}, {1, "\x1a", "Gg=="},
75     {1, "\x1b", "Gw=="}, {1, "\x1c", "HA=="}, {1, "\x1d", "HQ=="},
76     {1, "\x1e", "Hg=="}, {1, "\x1f", "Hw=="}, {1, "\x20", "IA=="},
77     {1, "\x21", "IQ=="}, {1, "\x22", "Ig=="}, {1, "\x23", "Iw=="},
78     {1, "\x24", "JA=="}, {1, "\x25", "JQ=="}, {1, "\x26", "Jg=="},
79     {1, "\x27", "Jw=="}, {1, "\x28", "KA=="}, {1, "\x29", "KQ=="},
80     {1, "\x2a", "Kg=="}, {1, "\x2b", "Kw=="}, {1, "\x2c", "LA=="},
81     {1, "\x2d", "LQ=="}, {1, "\x2e", "Lg=="}, {1, "\x2f", "Lw=="},
82     {1, "\x30", "MA=="}, {1, "\x31", "MQ=="}, {1, "\x32", "Mg=="},
83     {1, "\x33", "Mw=="}, {1, "\x34", "NA=="}, {1, "\x35", "NQ=="},
84     {1, "\x36", "Ng=="}, {1, "\x37", "Nw=="}, {1, "\x38", "OA=="},
85     {1, "\x39", "OQ=="}, {1, "\x3a", "Og=="}, {1, "\x3b", "Ow=="},
86     {1, "\x3c", "PA=="}, {1, "\x3d", "PQ=="}, {1, "\x3e", "Pg=="},
87     {1, "\x3f", "Pw=="}, {1, "\x40", "QA=="}, {1, "\x41", "QQ=="},
88     {1, "\x42", "Qg=="}, {1, "\x43", "Qw=="}, {1, "\x44", "RA=="},
89     {1, "\x45", "RQ=="}, {1, "\x46", "Rg=="}, {1, "\x47", "Rw=="},
90     {1, "\x48", "SA=="}, {1, "\x49", "SQ=="}, {1, "\x4a", "Sg=="},
91     {1, "\x4b", "Sw=="}, {1, "\x4c", "TA=="}, {1, "\x4d", "TQ=="},
92     {1, "\x4e", "Tg=="}, {1, "\x4f", "Tw=="}, {1, "\x50", "UA=="},
93     {1, "\x51", "UQ=="}, {1, "\x52", "Ug=="}, {1, "\x53", "Uw=="},
94     {1, "\x54", "VA=="}, {1, "\x55", "VQ=="}, {1, "\x56", "Vg=="},
95     {1, "\x57", "Vw=="}, {1, "\x58", "WA=="}, {1, "\x59", "WQ=="},
96     {1, "\x5a", "Wg=="}, {1, "\x5b", "Ww=="}, {1, "\x5c", "XA=="},
97     {1, "\x5d", "XQ=="}, {1, "\x5e", "Xg=="}, {1, "\x5f", "Xw=="},
98     {1, "\x60", "YA=="}, {1, "\x61", "YQ=="}, {1, "\x62", "Yg=="},
99     {1, "\x63", "Yw=="}, {1, "\x64", "ZA=="}, {1, "\x65", "ZQ=="},
100     {1, "\x66", "Zg=="}, {1, "\x67", "Zw=="}, {1, "\x68", "aA=="},
101     {1, "\x69", "aQ=="}, {1, "\x6a", "ag=="}, {1, "\x6b", "aw=="},
102     {1, "\x6c", "bA=="}, {1, "\x6d", "bQ=="}, {1, "\x6e", "bg=="},
103     {1, "\x6f", "bw=="}, {1, "\x70", "cA=="}, {1, "\x71", "cQ=="},
104     {1, "\x72", "cg=="}, {1, "\x73", "cw=="}, {1, "\x74", "dA=="},
105     {1, "\x75", "dQ=="}, {1, "\x76", "dg=="}, {1, "\x77", "dw=="},
106     {1, "\x78", "eA=="}, {1, "\x79", "eQ=="}, {1, "\x7a", "eg=="},
107     {1, "\x7b", "ew=="}, {1, "\x7c", "fA=="}, {1, "\x7d", "fQ=="},
108     {1, "\x7e", "fg=="}, {1, "\x7f", "fw=="}, {1, "\x80", "gA=="},
109     {1, "\x81", "gQ=="}, {1, "\x82", "gg=="}, {1, "\x83", "gw=="},
110     {1, "\x84", "hA=="}, {1, "\x85", "hQ=="}, {1, "\x86", "hg=="},
111     {1, "\x87", "hw=="}, {1, "\x88", "iA=="}, {1, "\x89", "iQ=="},
112     {1, "\x8a", "ig=="}, {1, "\x8b", "iw=="}, {1, "\x8c", "jA=="},
113     {1, "\x8d", "jQ=="}, {1, "\x8e", "jg=="}, {1, "\x8f", "jw=="},
114     {1, "\x90", "kA=="}, {1, "\x91", "kQ=="}, {1, "\x92", "kg=="},
115     {1, "\x93", "kw=="}, {1, "\x94", "lA=="}, {1, "\x95", "lQ=="},
116     {1, "\x96", "lg=="}, {1, "\x97", "lw=="}, {1, "\x98", "mA=="},
117     {1, "\x99", "mQ=="}, {1, "\x9a", "mg=="}, {1, "\x9b", "mw=="},
118     {1, "\x9c", "nA=="}, {1, "\x9d", "nQ=="}, {1, "\x9e", "ng=="},
119     {1, "\x9f", "nw=="}, {1, "\xa0", "oA=="}, {1, "\xa1", "oQ=="},
120     {1, "\xa2", "og=="}, {1, "\xa3", "ow=="}, {1, "\xa4", "pA=="},
121     {1, "\xa5", "pQ=="}, {1, "\xa6", "pg=="}, {1, "\xa7", "pw=="},
122     {1, "\xa8", "qA=="}, {1, "\xa9", "qQ=="}, {1, "\xaa", "qg=="},
123     {1, "\xab", "qw=="}, {1, "\xac", "rA=="}, {1, "\xad", "rQ=="},
124     {1, "\xae", "rg=="}, {1, "\xaf", "rw=="}, {1, "\xb0", "sA=="},
125     {1, "\xb1", "sQ=="}, {1, "\xb2", "sg=="}, {1, "\xb3", "sw=="},
126     {1, "\xb4", "tA=="}, {1, "\xb5", "tQ=="}, {1, "\xb6", "tg=="},
127     {1, "\xb7", "tw=="}, {1, "\xb8", "uA=="}, {1, "\xb9", "uQ=="},
128     {1, "\xba", "ug=="}, {1, "\xbb", "uw=="}, {1, "\xbc", "vA=="},
129     {1, "\xbd", "vQ=="}, {1, "\xbe", "vg=="}, {1, "\xbf", "vw=="},
130     {1, "\xc0", "wA=="}, {1, "\xc1", "wQ=="}, {1, "\xc2", "wg=="},
131     {1, "\xc3", "ww=="}, {1, "\xc4", "xA=="}, {1, "\xc5", "xQ=="},
132     {1, "\xc6", "xg=="}, {1, "\xc7", "xw=="}, {1, "\xc8", "yA=="},
133     {1, "\xc9", "yQ=="}, {1, "\xca", "yg=="}, {1, "\xcb", "yw=="},
134     {1, "\xcc", "zA=="}, {1, "\xcd", "zQ=="}, {1, "\xce", "zg=="},
135     {1, "\xcf", "zw=="}, {1, "\xd0", "0A=="}, {1, "\xd1", "0Q=="},
136     {1, "\xd2", "0g=="}, {1, "\xd3", "0w=="}, {1, "\xd4", "1A=="},
137     {1, "\xd5", "1Q=="}, {1, "\xd6", "1g=="}, {1, "\xd7", "1w=="},
138     {1, "\xd8", "2A=="}, {1, "\xd9", "2Q=="}, {1, "\xda", "2g=="},
139     {1, "\xdb", "2w=="}, {1, "\xdc", "3A=="}, {1, "\xdd", "3Q=="},
140     {1, "\xde", "3g=="}, {1, "\xdf", "3w=="}, {1, "\xe0", "4A=="},
141     {1, "\xe1", "4Q=="}, {1, "\xe2", "4g=="}, {1, "\xe3", "4w=="},
142     {1, "\xe4", "5A=="}, {1, "\xe5", "5Q=="}, {1, "\xe6", "5g=="},
143     {1, "\xe7", "5w=="}, {1, "\xe8", "6A=="}, {1, "\xe9", "6Q=="},
144     {1, "\xea", "6g=="}, {1, "\xeb", "6w=="}, {1, "\xec", "7A=="},
145     {1, "\xed", "7Q=="}, {1, "\xee", "7g=="}, {1, "\xef", "7w=="},
146     {1, "\xf0", "8A=="}, {1, "\xf1", "8Q=="}, {1, "\xf2", "8g=="},
147     {1, "\xf3", "8w=="}, {1, "\xf4", "9A=="}, {1, "\xf5", "9Q=="},
148     {1, "\xf6", "9g=="}, {1, "\xf7", "9w=="}, {1, "\xf8", "+A=="},
149     {1, "\xf9", "+Q=="}, {1, "\xfa", "+g=="}, {1, "\xfb", "+w=="},
150     {1, "\xfc", "/A=="}, {1, "\xfd", "/Q=="}, {1, "\xfe", "/g=="},
151     {1, "\xff", "/w=="},
152 };
153 
154 constexpr EncodedData kRandomTestData[] = {
155     {2, "\x74\x6d", "dG0="},
156     {2, "\x22\x86", "IoY="},
157     {3, "\xc0\xa2\x1c", "wKIc"},
158     {3, "\xa9\x67\xfb", "qWf7"},
159     {4, "\x77\xe1\x63\x51", "d+FjUQ=="},
160     {4, "\x7d\xa6\x8c\x5e", "faaMXg=="},
161     {5, "\x68\xaa\x19\x59\xd0", "aKoZWdA="},
162     {5, "\x46\x73\xd3\x54\x7e", "RnPTVH4="},
163     {6, "\x3f\xe8\x18\x4c\xe8\xf4", "P+gYTOj0"},
164     {6, "\x0a\xdd\x39\xbc\x1f\x65", "Ct05vB9l"},
165     {7, "\xc4\x5e\x4a\x6d\x4a\x04\xb6", "xF5KbUoEtg=="},
166     {7, "\x12\xe9\xf4\xaa\x2e\x4c\x31", "Eun0qi5MMQ=="},
167     {8, "\x55\x8c\x60\xcc\xc4\x7d\x99\x1f", "VYxgzMR9mR8="},
168     {8, "\xee\x21\x88\x2a\x0f\x7e\x76\xd7", "7iGIKg9+dtc="},
169     {9, "\xba\x40\x1d\x06\x92\xce\xc2\x8a\x28", "ukAdBpLOwooo"},
170     {9, "\xcc\x89\xf5\xeb\x49\x91\xa6\xa6\x88", "zIn160mRpqaI"},
171     {10, "\x55\x6b\x11\xe4\xc2\x22\xb0\x40\x14\x53", "VWsR5MIisEAUUw=="},
172     {10, "\xd3\x1e\xc4\xe5\x06\x60\x37\x51\x10\x48", "0x7E5QZgN1EQSA=="},
173     {11, "\x98\xae\x09\x8c\x61\x40\xbf\x77\xde\xd9\x0d", "mK4JjGFAv3fe2Q0="},
174     {11, "\x86\x39\x06\xa1\xc6\xfc\xcf\x30\x21\xba\xdf", "hjkGocb8zzAhut8="},
175 };
176 
ExpectEncodeDecodeSizesMatch(const EncodedData & data)177 void ExpectEncodeDecodeSizesMatch(const EncodedData& data) {
178   const size_t actual_encoded_size = std::strlen(data.encoded_data);
179   const size_t actual_raw_size = data.binary_size;
180 
181   // Encoded size.
182   ASSERT_EQ(EncodedSize(data.binary_size), actual_encoded_size);
183   ASSERT_EQ(PW_BASE64_ENCODED_SIZE(data.binary_size), actual_encoded_size);
184 
185   // Max decoded size. Do upper & lower bounds.
186   ASSERT_GE(MaxDecodedSize(actual_encoded_size), actual_raw_size);
187   ASSERT_GE(PW_BASE64_MAX_DECODED_SIZE(actual_encoded_size), actual_raw_size);
188   ASSERT_LE(MaxDecodedSize(actual_encoded_size), actual_raw_size + 2);
189   ASSERT_LE(PW_BASE64_MAX_DECODED_SIZE(actual_encoded_size),
190             actual_raw_size + 2);
191 }
192 
193 // Tests both the C++ constexpr variant and the C macro variant.
TEST(Base64,EncodedAndDecodedSize)194 TEST(Base64, EncodedAndDecodedSize) {
195   for (const EncodedData& data : kSingleCharTestData) {
196     ExpectEncodeDecodeSizesMatch(data);
197   }
198   for (const EncodedData& data : kRandomTestData) {
199     ExpectEncodeDecodeSizesMatch(data);
200   }
201 }
202 
TEST(Base64,Encode_SingleChar)203 TEST(Base64, Encode_SingleChar) {
204   char output[32];
205   for (const EncodedData& data : kSingleCharTestData) {
206     const size_t size = EncodedSize(data.binary_size);
207     ASSERT_EQ(std::strlen(data.encoded_data), size);
208     Encode(as_bytes(span(data.binary_data, data.binary_size)), output);
209     output[size] = '\0';
210     EXPECT_STREQ(data.encoded_data, output);
211   }
212 }
213 
TEST(Base64,Encode_RandomData)214 TEST(Base64, Encode_RandomData) {
215   char output[128];
216   for (const EncodedData& data : kRandomTestData) {
217     const size_t size = EncodedSize(data.binary_size);
218     ASSERT_EQ(std::strlen(data.encoded_data), size);
219     Encode(as_bytes(span(data.binary_data, data.binary_size)), output);
220     output[size] = '\0';
221     EXPECT_STREQ(data.encoded_data, output);
222   }
223 }
224 
TEST(Base64,Encode_BoundaryCheck)225 TEST(Base64, Encode_BoundaryCheck) {
226   constexpr std::byte data[] = {std::byte{'h'}, std::byte{'i'}};
227   char output[5] = {};
228 
229   EXPECT_EQ(0u, Encode(data, span(output, 3)));
230   EXPECT_STREQ("", output);
231   EXPECT_EQ(4u, Encode(data, span(output, 4)));
232   EXPECT_STREQ("aGk=", output);
233 }
234 
TEST(Base64,Encode_RandomData_ToInlineString)235 TEST(Base64, Encode_RandomData_ToInlineString) {
236   for (const EncodedData& data : kRandomTestData) {
237     auto b64 = Encode<11>(as_bytes(span(data.binary_data, data.binary_size)));
238     EXPECT_EQ(data.encoded_data, b64);
239   }
240 }
241 
TEST(Base64,Encode_RandomData_ToInlineStringAppend)242 TEST(Base64, Encode_RandomData_ToInlineStringAppend) {
243   for (const EncodedData& data : kRandomTestData) {
244     InlineString<32> output("Wow:");
245 
246     InlineString<32> expected(output);
247     expected.append(data.encoded_data);
248 
249     Encode(as_bytes(span(data.binary_data, data.binary_size)), output);
250     EXPECT_EQ(expected, output);
251   }
252 }
253 
TEST(Base64,Decode_SingleChar)254 TEST(Base64, Decode_SingleChar) {
255   char output[32];
256   for (const EncodedData& data : kSingleCharTestData) {
257     size_t binary_size = Decode(data.encoded_data, output);
258     ASSERT_EQ(binary_size, data.binary_size);
259     EXPECT_EQ(0, std::memcmp(data.binary_data, output, data.binary_size));
260   }
261 }
262 
TEST(Base64,Decode_RandomData)263 TEST(Base64, Decode_RandomData) {
264   char output[128];
265   for (const EncodedData& data : kRandomTestData) {
266     size_t binary_size = Decode(data.encoded_data, output);
267     ASSERT_EQ(binary_size, data.binary_size);
268     EXPECT_EQ(0, std::memcmp(data.binary_data, output, data.binary_size));
269   }
270 }
271 
TEST(Base64,Decode_BoundaryCheck)272 TEST(Base64, Decode_BoundaryCheck) {
273   constexpr const char encoded_data[] = "aGk=";
274   std::byte output[4] = {};
275 
276   EXPECT_EQ(0u, Decode(encoded_data, span(output, 2)));
277   EXPECT_STREQ("", reinterpret_cast<const char*>(output));
278   EXPECT_EQ(2u, Decode(encoded_data, span(output, 3)));
279   EXPECT_STREQ("hi", reinterpret_cast<const char*>(output));
280 }
281 
TEST(Base64,Decode_InPlace)282 TEST(Base64, Decode_InPlace) {
283   constexpr const char expected[] = "This is a secret message";
284   char buf[] = "VGhpcyBpcyBhIHNlY3JldCBtZXNzYWdl";
285   EXPECT_EQ(sizeof(expected) - 1, Decode(buf, buf));
286   EXPECT_EQ(0, std::memcmp(expected, buf, sizeof(expected) - 1));
287 }
288 
TEST(Base64,DecodeString_InPlace)289 TEST(Base64, DecodeString_InPlace) {
290   constexpr const char expected[] = "This is a secret message";
291   InlineBasicString buf = "VGhpcyBpcyBhIHNlY3JldCBtZXNzYWdl";
292   DecodeInPlace(buf);
293   EXPECT_EQ(sizeof(expected) - 1, buf.size());
294   EXPECT_EQ(expected, buf);
295 
296   buf.clear();
297   DecodeInPlace(buf);
298   EXPECT_TRUE(buf.empty());
299 }
300 
TEST(Base64,Decode_UrlSafeDecode)301 TEST(Base64, Decode_UrlSafeDecode) {
302   char output[9] = {};
303 
304   EXPECT_TRUE(IsValid("+f//WW8h"));
305   EXPECT_TRUE(IsValid("-f__WW8h"));
306 
307   EXPECT_EQ(6u, Decode("-f__WW8h", output));
308   EXPECT_STREQ("\xf9\xff\xffYo!", output);
309 }
310 
TEST(Base64,Empty)311 TEST(Base64, Empty) {
312   char buffer[] = "DO NOT TOUCH";
313   EXPECT_EQ(0u, EncodedSize(0));
314   Encode(as_bytes(span("Something cool!!!", 0)), buffer);
315   EXPECT_STREQ("DO NOT TOUCH", buffer);
316 
317   EXPECT_EQ(0u, MaxDecodedSize(0));
318   // NOLINTNEXTLINE(bugprone-string-constructor)
319   EXPECT_EQ(0u, Decode(std::string_view("nothing please", 0), buffer));
320   EXPECT_STREQ("DO NOT TOUCH", buffer);
321 }
322 
TEST(Base64,ExampleFromRfc3548Section7)323 TEST(Base64, ExampleFromRfc3548Section7) {
324   constexpr uint8_t input[] = {0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e};
325   char output[EncodedSize(sizeof(input)) + 1] = {};
326 
327   Encode(as_bytes(span(input)), output);
328   EXPECT_STREQ("FPucA9l+", output);
329   Encode(as_bytes(span(input, 5)), output);
330   EXPECT_STREQ("FPucA9k=", output);
331   Encode(as_bytes(span(input, 4)), output);
332   EXPECT_STREQ("FPucAw==", output);
333 
334   EXPECT_EQ(6u, Decode("FPucA9l+", output));
335   EXPECT_EQ(0, std::memcmp(input, output, 6));
336   EXPECT_EQ(5u, Decode("FPucA9k=", output));
337   EXPECT_EQ(0, std::memcmp(input, output, 5));
338   EXPECT_EQ(4u, Decode("FPucAw==", output));
339   EXPECT_EQ(0, std::memcmp(input, output, 4));
340 }
341 
TEST(Base64,ExampleFromRfc4648Section9)342 TEST(Base64, ExampleFromRfc4648Section9) {
343   char output[EncodedSize(sizeof("foobar")) + 1] = {};
344   const std::byte* foobar = reinterpret_cast<const std::byte*>("foobar");
345 
346   Encode(span(foobar, 0), output);
347   EXPECT_STREQ("", output);
348   Encode(span(foobar, 1), output);
349   EXPECT_STREQ("Zg==", output);
350   Encode(span(foobar, 2), output);
351   EXPECT_STREQ("Zm8=", output);
352   Encode(span(foobar, 3), output);
353   EXPECT_STREQ("Zm9v", output);
354   Encode(span(foobar, 4), output);
355   EXPECT_STREQ("Zm9vYg==", output);
356   Encode(span(foobar, 5), output);
357   EXPECT_STREQ("Zm9vYmE=", output);
358   Encode(span(foobar, 6), output);
359   EXPECT_STREQ("Zm9vYmFy", output);
360 
361   std::memset(output, '\0', sizeof(output));
362   EXPECT_EQ(0u, Decode("", output));
363   EXPECT_STREQ("", output);
364   EXPECT_EQ(1u, Decode("Zg==", output));
365   EXPECT_STREQ("f", output);
366   EXPECT_EQ(2u, Decode("Zm8=", output));
367   EXPECT_STREQ("fo", output);
368   EXPECT_EQ(3u, Decode("Zm9v", output));
369   EXPECT_STREQ("foo", output);
370   EXPECT_EQ(4u, Decode("Zm9vYg==", output));
371   EXPECT_STREQ("foob", output);
372   EXPECT_EQ(5u, Decode("Zm9vYmE=", output));
373   EXPECT_STREQ("fooba", output);
374   EXPECT_EQ(6u, Decode("Zm9vYmFy", output));
375   EXPECT_STREQ("foobar", output);
376 }
377 
378 // Functions that call the Base64 API from C. These are defined in
379 // base64_test.c; no point in having a separate header.
380 extern "C" {
381 
382 void pw_Base64CallEncode(const void* binary_data,
383                          const size_t binary_size_bytes,
384                          char* output);
385 
386 size_t pw_Base64CallDecode(const char* base64,
387                            size_t base64_size_bytes,
388                            void* output);
389 
390 bool pw_Base64CallIsValid(const char* base64_data, size_t base64_size);
391 
392 }  // extern "C"
393 
394 constexpr const char kBase64[] = "aaaabbbbcc#%";
395 
396 // Ensure that the C API works correctly from a C-only context.
TEST(Base64,IsValid_Ok)397 TEST(Base64, IsValid_Ok) {
398   EXPECT_TRUE(IsValid(std::string_view(kBase64, 4)));
399   EXPECT_TRUE(IsValid(std::string_view(kBase64, 8)));
400 }
401 
TEST(Base64,IsValid_IncorrectSize)402 TEST(Base64, IsValid_IncorrectSize) {
403   EXPECT_FALSE(IsValid(std::string_view(kBase64, 5)));
404   EXPECT_FALSE(IsValid(std::string_view(kBase64, 6)));
405   EXPECT_FALSE(IsValid(std::string_view(kBase64, 7)));
406   EXPECT_FALSE(IsValid(std::string_view(kBase64, 10)));
407 }
408 
TEST(Base64,IsValid_InvalidCharacters)409 TEST(Base64, IsValid_InvalidCharacters) {
410   EXPECT_FALSE(IsValid(std::string_view(kBase64, 11)));
411   EXPECT_FALSE(IsValid(std::string_view(kBase64, 12)));
412 }
413 
TEST(Base64CLinkage,IsValid_Ok)414 TEST(Base64CLinkage, IsValid_Ok) {
415   EXPECT_TRUE(pw_Base64CallIsValid(kBase64, 4));
416   EXPECT_TRUE(pw_Base64CallIsValid(kBase64, 8));
417 }
418 
TEST(Base64CLinkage,IsValid_IncorrectSize)419 TEST(Base64CLinkage, IsValid_IncorrectSize) {
420   EXPECT_FALSE(pw_Base64CallIsValid(kBase64, 5));
421   EXPECT_FALSE(pw_Base64CallIsValid(kBase64, 6));
422   EXPECT_FALSE(pw_Base64CallIsValid(kBase64, 7));
423   EXPECT_FALSE(pw_Base64CallIsValid(kBase64, 10));
424 }
425 
TEST(Base64CLinkage,IsValid_InvalidCharacters)426 TEST(Base64CLinkage, IsValid_InvalidCharacters) {
427   EXPECT_FALSE(pw_Base64CallIsValid(kBase64, 11));
428   EXPECT_FALSE(pw_Base64CallIsValid(kBase64, 12));
429 }
430 
TEST(Base64CLinkage,Encode)431 TEST(Base64CLinkage, Encode) {
432   char output[EncodedSize(sizeof("foobar")) + 1] = {};
433 
434   pw_Base64CallEncode("", 0, output);
435   EXPECT_STREQ("", output);
436   pw_Base64CallEncode("f", 1, output);
437   EXPECT_STREQ("Zg==", output);
438   pw_Base64CallEncode("fo", 2, output);
439 }
440 
TEST(Base64CLinkage,Decode)441 TEST(Base64CLinkage, Decode) {
442   char output[EncodedSize(sizeof("foobar")) + 1] = {};
443 
444   EXPECT_EQ(0u, pw_Base64CallDecode("", 0, output));
445   EXPECT_STREQ("", output);
446   EXPECT_EQ(1u, pw_Base64CallDecode("Zg==", 4, output));
447   EXPECT_STREQ("f", output);
448   EXPECT_EQ(2u, pw_Base64CallDecode("Zm8=", 4, output));
449   EXPECT_STREQ("fo", output);
450 }
451 
452 }  // namespace
453 }  // namespace pw::base64
454