Wyatt Hepler | b8b01e3 | 2020-01-08 18:33:40 -0800 | [diff] [blame] | 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 "gtest/gtest.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, "\x63\xa9", "Y6k="}, |
| 156 | {2, "\xa1\x49", "oUk="}, |
| 157 | {2, "\x14\x58", "FFg="}, |
| 158 | {2, "\x5d\xa2", "XaI="}, |
| 159 | {2, "\x7c\x80", "fIA="}, |
| 160 | {2, "\xc1\xbb", "wbs="}, |
| 161 | {2, "\x08\x00", "CAA="}, |
| 162 | {2, "\xd8\x88", "2Ig="}, |
| 163 | {2, "\x74\x6d", "dG0="}, |
| 164 | {2, "\x22\x86", "IoY="}, |
| 165 | {3, "\x69\x89\x03", "aYkD"}, |
| 166 | {3, "\x6c\xcb\xc5", "bMvF"}, |
| 167 | {3, "\x72\x36\x8b", "cjaL"}, |
| 168 | {3, "\xd3\xdc\xe0", "09zg"}, |
| 169 | {3, "\x5d\x1f\x8a", "XR+K"}, |
| 170 | {3, "\x0d\xc0\x5b", "DcBb"}, |
| 171 | {3, "\xe3\x11\x1e", "4xEe"}, |
| 172 | {3, "\xbc\x3c\xb9", "vDy5"}, |
| 173 | {3, "\xc0\xa2\x1c", "wKIc"}, |
| 174 | {3, "\xa9\x67\xfb", "qWf7"}, |
| 175 | {4, "\x80\xf5\xc8\xd4", "gPXI1A=="}, |
| 176 | {4, "\xa3\x54\x4a\xfa", "o1RK+g=="}, |
| 177 | {4, "\x69\xdb\x14\x4c", "adsUTA=="}, |
| 178 | {4, "\x95\x20\x23\x1a", "lSAjGg=="}, |
| 179 | {4, "\xb9\x2c\x00\x11", "uSwAEQ=="}, |
| 180 | {4, "\xef\xeb\x23\x44", "7+sjRA=="}, |
| 181 | {4, "\xcf\xa9\xe6\x85", "z6nmhQ=="}, |
| 182 | {4, "\xc5\xe0\x36\xde", "xeA23g=="}, |
| 183 | {4, "\x77\xe1\x63\x51", "d+FjUQ=="}, |
| 184 | {4, "\x7d\xa6\x8c\x5e", "faaMXg=="}, |
| 185 | {5, "\x6e\xb8\x91\x3f\xac", "briRP6w="}, |
| 186 | {5, "\xd1\x16\x7f\x1d\xef", "0RZ/He8="}, |
| 187 | {5, "\x42\x95\xfb\x24\xee", "QpX7JO4="}, |
| 188 | {5, "\x19\xfd\xe5\x96\xc1", "Gf3llsE="}, |
| 189 | {5, "\x42\x5a\xb3\xfe\x13", "Qlqz/hM="}, |
| 190 | {5, "\x2b\xf7\x1a\xcc\x13", "K/cazBM="}, |
| 191 | {5, "\xba\x8f\x0d\xf7\xc1", "uo8N98E="}, |
| 192 | {5, "\x28\xa6\x77\x2d\xfc", "KKZ3Lfw="}, |
| 193 | {5, "\x68\xaa\x19\x59\xd0", "aKoZWdA="}, |
| 194 | {5, "\x46\x73\xd3\x54\x7e", "RnPTVH4="}, |
| 195 | {6, "\x1f\x88\x91\xbb\xd7\x10", "H4iRu9cQ"}, |
| 196 | {6, "\x37\x23\x3b\x5a\x26\xe4", "NyM7Wibk"}, |
| 197 | {6, "\xd2\xa0\xf4\x13\x91\xe6", "0qD0E5Hm"}, |
| 198 | {6, "\x55\xe8\xe9\x06\x5d\xc3", "VejpBl3D"}, |
| 199 | {6, "\xeb\xf5\xd8\x62\x3c\x5e", "6/XYYjxe"}, |
| 200 | {6, "\xee\xad\x7e\xc4\x66\x83", "7q1+xGaD"}, |
| 201 | {6, "\xbb\x07\x2c\x26\x3f\xb7", "uwcsJj+3"}, |
| 202 | {6, "\xed\xf3\x34\x94\xab\x41", "7fM0lKtB"}, |
| 203 | {6, "\x3f\xe8\x18\x4c\xe8\xf4", "P+gYTOj0"}, |
| 204 | {6, "\x0a\xdd\x39\xbc\x1f\x65", "Ct05vB9l"}, |
| 205 | {7, "\xac\xcf\xb2\xd5\xee\xa2\x8e", "rM+y1e6ijg=="}, |
| 206 | {7, "\x78\x63\xeb\x3f\x07\xde\x04", "eGPrPwfeBA=="}, |
| 207 | {7, "\x7a\xd7\x3b\x5c\x09\xc2\x93", "etc7XAnCkw=="}, |
| 208 | {7, "\xd4\xe4\xda\xe3\xf3\x4d\xe9", "1OTa4/NN6Q=="}, |
| 209 | {7, "\xa6\xc6\x7c\x47\xd5\xbe\xd3", "psZ8R9W+0w=="}, |
| 210 | {7, "\x34\xad\x5d\x02\x47\xa1\x39", "NK1dAkehOQ=="}, |
| 211 | {7, "\x33\x98\xd7\x02\x46\x4e\xad", "M5jXAkZOrQ=="}, |
| 212 | {7, "\x08\x4d\x48\x48\xb1\x3d\x05", "CE1ISLE9BQ=="}, |
| 213 | {7, "\xc4\x5e\x4a\x6d\x4a\x04\xb6", "xF5KbUoEtg=="}, |
| 214 | {7, "\x12\xe9\xf4\xaa\x2e\x4c\x31", "Eun0qi5MMQ=="}, |
| 215 | {8, "\xff\x15\x25\x7e\x7b\xc9\x7b\x60", "/xUlfnvJe2A="}, |
| 216 | {8, "\xc7\xbb\x0b\x62\x5c\x62\x41\xc2", "x7sLYlxiQcI="}, |
| 217 | {8, "\x48\x49\x6d\x7c\xca\xb7\xae\xed", "SEltfMq3ru0="}, |
| 218 | {8, "\xfd\xec\x13\xd6\x93\x9f\xba\xe0", "/ewT1pOfuuA="}, |
| 219 | {8, "\x7e\xff\xd2\xdd\x0e\xe2\x6c\x60", "fv/S3Q7ibGA="}, |
| 220 | {8, "\xe5\xba\x41\x65\xa0\x46\x17\x27", "5bpBZaBGFyc="}, |
| 221 | {8, "\xce\xec\xd5\x68\x3a\xb7\xb4\x16", "zuzVaDq3tBY="}, |
| 222 | {8, "\xbe\x33\x9a\xc9\xfd\xcc\x29\xe8", "vjOayf3MKeg="}, |
| 223 | {8, "\x55\x8c\x60\xcc\xc4\x7d\x99\x1f", "VYxgzMR9mR8="}, |
| 224 | {8, "\xee\x21\x88\x2a\x0f\x7e\x76\xd7", "7iGIKg9+dtc="}, |
| 225 | {9, "\xd5\xab\xd9\xa6\xae\xaa\x33\x9f\x66", "1avZpq6qM59m"}, |
| 226 | {9, "\x6f\xe8\x06\xcf\xfd\x79\x3a\x4e\xdb", "b+gGz/15Ok7b"}, |
| 227 | {9, "\x61\x00\x0a\x51\xad\x5b\xf1\xf9\x37", "YQAKUa1b8fk3"}, |
| 228 | {9, "\x4f\x40\x0b\x79\x10\xa4\x12\x25\x3e", "T0ALeRCkEiU+"}, |
| 229 | {9, "\xb1\x37\xb3\x41\x5b\xd7\xe8\xa4\xda", "sTezQVvX6KTa"}, |
| 230 | {9, "\x82\xa5\x22\xd3\x48\xd8\xf7\x62\x7a", "gqUi00jY92J6"}, |
| 231 | {9, "\xfd\x05\x33\x92\x2c\xd3\x85\x29\xa2", "/QUzkizThSmi"}, |
| 232 | {9, "\x32\x93\x53\x06\x9c\xbb\x96\xbb\xf3", "MpNTBpy7lrvz"}, |
| 233 | {9, "\xba\x40\x1d\x06\x92\xce\xc2\x8a\x28", "ukAdBpLOwooo"}, |
| 234 | {9, "\xcc\x89\xf5\xeb\x49\x91\xa6\xa6\x88", "zIn160mRpqaI"}, |
| 235 | {10, "\x6b\xfd\x95\xc5\x4a\xc7\xc2\x39\x45\xdc", "a/2VxUrHwjlF3A=="}, |
| 236 | {10, "\x34\x50\xab\x78\xaf\x92\x47\x56\x8a\xb6", "NFCreK+SR1aKtg=="}, |
| 237 | {10, "\x07\x14\x0a\xe8\x49\xca\x3a\x36\x80\xb0", "BxQK6EnKOjaAsA=="}, |
| 238 | {10, "\xde\x79\x3d\xa7\xab\x22\xa9\xaa\xfc\x05", "3nk9p6siqar8BQ=="}, |
| 239 | {10, "\x73\x62\x02\x77\x41\x91\xe6\x8b\x3f\x89", "c2ICd0GR5os/iQ=="}, |
| 240 | {10, "\xf2\x09\xa9\x8b\x7c\x30\x26\x54\xf0\xd3", "8gmpi3wwJlTw0w=="}, |
| 241 | {10, "\x32\xc8\xcc\xfc\x47\xa3\xac\x20\x37\x39", "MsjM/EejrCA3OQ=="}, |
| 242 | {10, "\x32\x1b\x2b\x36\x07\x76\x90\xfa\xe0\x04", "MhsrNgd2kPrgBA=="}, |
| 243 | {10, "\x55\x6b\x11\xe4\xc2\x22\xb0\x40\x14\x53", "VWsR5MIisEAUUw=="}, |
| 244 | {10, "\xd3\x1e\xc4\xe5\x06\x60\x37\x51\x10\x48", "0x7E5QZgN1EQSA=="}, |
| 245 | {11, "\x4c\xde\xee\xb8\x68\x0d\x9c\x66\x3e\xea\x46", "TN7uuGgNnGY+6kY="}, |
| 246 | {11, "\x36\x79\x11\x5c\xce\xd0\xdf\x3c\xd2\xc9\x45", "NnkRXM7Q3zzSyUU="}, |
| 247 | {11, "\xa0\x78\xc3\xc0\x79\xaf\xa1\xc3\xef\xd5\xf3", "oHjDwHmvocPv1fM="}, |
| 248 | {11, "\xdd\x6b\x78\x18\x95\x80\x99\x7a\x02\x41\xe8", "3Wt4GJWAmXoCQeg="}, |
| 249 | {11, "\x18\xfa\x19\xe0\xce\x3b\x0a\xa1\xec\x2b\x30", "GPoZ4M47CqHsKzA="}, |
| 250 | {11, "\x74\xf2\x96\x90\x95\xbe\x14\x64\xbf\x10\xd9", "dPKWkJW+FGS/ENk="}, |
| 251 | {11, "\x7f\xe8\x18\xab\xeb\x28\x86\xf1\x7c\x75\x47", "f+gYq+sohvF8dUc="}, |
| 252 | {11, "\xa4\xc9\x62\x73\x0e\x89\xe1\x51\x8b\xf0\x96", "pMlicw6J4VGL8JY="}, |
| 253 | {11, "\x98\xae\x09\x8c\x61\x40\xbf\x77\xde\xd9\x0d", "mK4JjGFAv3fe2Q0="}, |
| 254 | {11, "\x86\x39\x06\xa1\xc6\xfc\xcf\x30\x21\xba\xdf", "hjkGocb8zzAhut8="}, |
| 255 | }; |
| 256 | |
| 257 | void ExpectEncodeDecodeSizesMatch(const EncodedData& data) { |
| 258 | const size_t actual_encoded_size = std::strlen(data.encoded_data); |
| 259 | const size_t actual_raw_size = data.binary_size; |
| 260 | |
| 261 | // Encoded size. |
| 262 | ASSERT_EQ(EncodedSize(data.binary_size), actual_encoded_size); |
| 263 | ASSERT_EQ(PW_BASE64_ENCODED_SIZE(data.binary_size), actual_encoded_size); |
| 264 | |
| 265 | // Max decoded size. Do upper & lower bounds. |
| 266 | ASSERT_GE(MaxDecodedSize(actual_encoded_size), actual_raw_size); |
| 267 | ASSERT_GE(PW_BASE64_MAX_DECODED_SIZE(actual_encoded_size), actual_raw_size); |
| 268 | ASSERT_LE(MaxDecodedSize(actual_encoded_size), actual_raw_size + 2); |
| 269 | ASSERT_LE(PW_BASE64_MAX_DECODED_SIZE(actual_encoded_size), |
| 270 | actual_raw_size + 2); |
| 271 | } |
| 272 | |
| 273 | // Tests both the C++ constexpr variant and the C macro variant. |
| 274 | TEST(Base64, EncodedAndDecodedSize) { |
| 275 | for (const EncodedData& data : kSingleCharTestData) { |
| 276 | ExpectEncodeDecodeSizesMatch(data); |
| 277 | } |
| 278 | for (const EncodedData& data : kRandomTestData) { |
| 279 | ExpectEncodeDecodeSizesMatch(data); |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | TEST(Base64, Encode_SingleChar) { |
| 284 | char output[32]; |
| 285 | for (const EncodedData& data : kSingleCharTestData) { |
| 286 | const size_t size = EncodedSize(data.binary_size); |
| 287 | ASSERT_EQ(std::strlen(data.encoded_data), size); |
| 288 | Encode(as_bytes(span(data.binary_data, data.binary_size)), output); |
| 289 | output[size] = '\0'; |
| 290 | EXPECT_STREQ(data.encoded_data, output); |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | TEST(Base64, Encode_RandomData) { |
| 295 | char output[128]; |
| 296 | for (const EncodedData& data : kRandomTestData) { |
| 297 | const size_t size = EncodedSize(data.binary_size); |
| 298 | ASSERT_EQ(std::strlen(data.encoded_data), size); |
| 299 | Encode(as_bytes(span(data.binary_data, data.binary_size)), output); |
| 300 | output[size] = '\0'; |
| 301 | EXPECT_STREQ(data.encoded_data, output); |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | TEST(Base64, Encode_BoundaryCheck) { |
| 306 | constexpr std::byte data[] = {std::byte{'h'}, std::byte{'i'}}; |
| 307 | char output[5] = {}; |
| 308 | |
| 309 | EXPECT_EQ(0u, Encode(data, span(output, 3))); |
| 310 | EXPECT_STREQ("", output); |
| 311 | EXPECT_EQ(4u, Encode(data, span(output, 4))); |
| 312 | EXPECT_STREQ("aGk=", output); |
| 313 | } |
| 314 | |
| 315 | TEST(Base64, Decode_SingleChar) { |
| 316 | char output[32]; |
| 317 | for (const EncodedData& data : kSingleCharTestData) { |
| 318 | size_t binary_size = Decode(data.encoded_data, output); |
| 319 | ASSERT_EQ(binary_size, data.binary_size); |
| 320 | EXPECT_EQ(0, std::memcmp(data.binary_data, output, data.binary_size)); |
| 321 | } |
| 322 | } |
| 323 | |
| 324 | TEST(Base64, Decode_RandomData) { |
| 325 | char output[128]; |
| 326 | for (const EncodedData& data : kRandomTestData) { |
| 327 | size_t binary_size = Decode(data.encoded_data, output); |
| 328 | ASSERT_EQ(binary_size, data.binary_size); |
| 329 | EXPECT_EQ(0, std::memcmp(data.binary_data, output, data.binary_size)); |
| 330 | } |
| 331 | } |
| 332 | |
| 333 | TEST(Base64, Decode_BoundaryCheck) { |
| 334 | constexpr const char encoded_data[] = "aGk="; |
| 335 | std::byte output[4] = {}; |
| 336 | |
| 337 | EXPECT_EQ(0u, Decode(encoded_data, span(output, 2))); |
| 338 | EXPECT_STREQ("", reinterpret_cast<const char*>(output)); |
| 339 | EXPECT_EQ(2u, Decode(encoded_data, span(output, 3))); |
| 340 | EXPECT_STREQ("hi", reinterpret_cast<const char*>(output)); |
| 341 | } |
| 342 | |
| 343 | TEST(Base64, Decode_InPlace) { |
| 344 | constexpr const char expected[] = "This is a secret message"; |
| 345 | char buf[] = "VGhpcyBpcyBhIHNlY3JldCBtZXNzYWdl"; |
| 346 | EXPECT_EQ(sizeof(expected) - 1, Decode(buf, buf)); |
| 347 | EXPECT_EQ(0, std::memcmp(expected, buf, sizeof(expected) - 1)); |
| 348 | } |
| 349 | |
| 350 | TEST(Base64, Decode_UrlSafeDecode) { |
| 351 | char output[9] = {}; |
| 352 | |
| 353 | EXPECT_TRUE(IsValid("+f//WW8h")); |
| 354 | EXPECT_TRUE(IsValid("-f__WW8h")); |
| 355 | |
| 356 | EXPECT_EQ(6u, Decode("-f__WW8h", output)); |
| 357 | EXPECT_STREQ("\xf9\xff\xffYo!", output); |
| 358 | } |
| 359 | |
| 360 | TEST(Base64, Empty) { |
| 361 | char buffer[] = "DO NOT TOUCH"; |
| 362 | EXPECT_EQ(0u, EncodedSize(0)); |
| 363 | Encode(as_bytes(span("Something cool!!!", 0)), buffer); |
| 364 | EXPECT_STREQ("DO NOT TOUCH", buffer); |
| 365 | |
| 366 | EXPECT_EQ(0u, MaxDecodedSize(0)); |
| 367 | EXPECT_EQ(0u, Decode(std::string_view("nothing please", 0), buffer)); |
| 368 | EXPECT_STREQ("DO NOT TOUCH", buffer); |
| 369 | } |
| 370 | |
| 371 | TEST(Base64, ExampleFromRfc3548Section7) { |
| 372 | constexpr uint8_t input[] = {0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e}; |
| 373 | char output[EncodedSize(sizeof(input)) + 1] = {}; |
| 374 | |
| 375 | Encode(as_bytes(span(input)), output); |
| 376 | EXPECT_STREQ("FPucA9l+", output); |
| 377 | Encode(as_bytes(span(input, 5)), output); |
| 378 | EXPECT_STREQ("FPucA9k=", output); |
| 379 | Encode(as_bytes(span(input, 4)), output); |
| 380 | EXPECT_STREQ("FPucAw==", output); |
| 381 | |
| 382 | EXPECT_EQ(6u, Decode("FPucA9l+", output)); |
| 383 | EXPECT_EQ(0, std::memcmp(input, output, 6)); |
| 384 | EXPECT_EQ(5u, Decode("FPucA9k=", output)); |
| 385 | EXPECT_EQ(0, std::memcmp(input, output, 5)); |
| 386 | EXPECT_EQ(4u, Decode("FPucAw==", output)); |
| 387 | EXPECT_EQ(0, std::memcmp(input, output, 4)); |
| 388 | } |
| 389 | |
| 390 | TEST(Base64, ExampleFromRfc4648Section9) { |
| 391 | char output[EncodedSize(sizeof("foobar")) + 1] = {}; |
| 392 | const std::byte* foobar = reinterpret_cast<const std::byte*>("foobar"); |
| 393 | |
| 394 | Encode(span(foobar, 0), output); |
| 395 | EXPECT_STREQ("", output); |
| 396 | Encode(span(foobar, 1), output); |
| 397 | EXPECT_STREQ("Zg==", output); |
| 398 | Encode(span(foobar, 2), output); |
| 399 | EXPECT_STREQ("Zm8=", output); |
| 400 | Encode(span(foobar, 3), output); |
| 401 | EXPECT_STREQ("Zm9v", output); |
| 402 | Encode(span(foobar, 4), output); |
| 403 | EXPECT_STREQ("Zm9vYg==", output); |
| 404 | Encode(span(foobar, 5), output); |
| 405 | EXPECT_STREQ("Zm9vYmE=", output); |
| 406 | Encode(span(foobar, 6), output); |
| 407 | EXPECT_STREQ("Zm9vYmFy", output); |
| 408 | |
| 409 | std::memset(output, '\0', sizeof(output)); |
| 410 | EXPECT_EQ(0u, Decode("", output)); |
| 411 | EXPECT_STREQ("", output); |
| 412 | EXPECT_EQ(1u, Decode("Zg==", output)); |
| 413 | EXPECT_STREQ("f", output); |
| 414 | EXPECT_EQ(2u, Decode("Zm8=", output)); |
| 415 | EXPECT_STREQ("fo", output); |
| 416 | EXPECT_EQ(3u, Decode("Zm9v", output)); |
| 417 | EXPECT_STREQ("foo", output); |
| 418 | EXPECT_EQ(4u, Decode("Zm9vYg==", output)); |
| 419 | EXPECT_STREQ("foob", output); |
| 420 | EXPECT_EQ(5u, Decode("Zm9vYmE=", output)); |
| 421 | EXPECT_STREQ("fooba", output); |
| 422 | EXPECT_EQ(6u, Decode("Zm9vYmFy", output)); |
| 423 | EXPECT_STREQ("foobar", output); |
| 424 | } |
| 425 | |
| 426 | // Functions that call the Base64 API from C. These are defined in |
| 427 | // base64_test.c; no point in having a separate header. |
| 428 | extern "C" { |
| 429 | |
| 430 | void pw_Base64CallEncode(const void* binary_data, |
| 431 | const size_t binary_size_bytes, |
| 432 | char* output); |
| 433 | |
| 434 | size_t pw_Base64CallDecode(const char* base64, |
| 435 | size_t base64_size_bytes, |
| 436 | void* output); |
| 437 | |
| 438 | bool pw_Base64CallIsValid(const char* base64_data, size_t base64_size); |
| 439 | |
| 440 | } // extern "C" |
| 441 | |
| 442 | constexpr const char kBase64[] = "aaaabbbbcc#%"; |
| 443 | |
| 444 | // Ensure that the C API works correctly from a C-only context. |
| 445 | TEST(Base64, IsValid_Ok) { |
| 446 | EXPECT_TRUE(IsValid(std::string_view(kBase64, 4))); |
| 447 | EXPECT_TRUE(IsValid(std::string_view(kBase64, 8))); |
| 448 | } |
| 449 | |
| 450 | TEST(Base64, IsValid_IncorrectSize) { |
| 451 | EXPECT_FALSE(IsValid(std::string_view(kBase64, 5))); |
| 452 | EXPECT_FALSE(IsValid(std::string_view(kBase64, 6))); |
| 453 | EXPECT_FALSE(IsValid(std::string_view(kBase64, 7))); |
| 454 | EXPECT_FALSE(IsValid(std::string_view(kBase64, 10))); |
| 455 | } |
| 456 | |
| 457 | TEST(Base64, IsValid_InvalidCharacters) { |
| 458 | EXPECT_FALSE(IsValid(std::string_view(kBase64, 11))); |
| 459 | EXPECT_FALSE(IsValid(std::string_view(kBase64, 12))); |
| 460 | } |
| 461 | |
| 462 | TEST(Base64CLinkage, IsValid_Ok) { |
| 463 | EXPECT_TRUE(pw_Base64CallIsValid(kBase64, 4)); |
| 464 | EXPECT_TRUE(pw_Base64CallIsValid(kBase64, 8)); |
| 465 | } |
| 466 | |
| 467 | TEST(Base64CLinkage, IsValid_IncorrectSize) { |
| 468 | EXPECT_FALSE(pw_Base64CallIsValid(kBase64, 5)); |
| 469 | EXPECT_FALSE(pw_Base64CallIsValid(kBase64, 6)); |
| 470 | EXPECT_FALSE(pw_Base64CallIsValid(kBase64, 7)); |
| 471 | EXPECT_FALSE(pw_Base64CallIsValid(kBase64, 10)); |
| 472 | } |
| 473 | |
| 474 | TEST(Base64CLinkage, IsValid_InvalidCharacters) { |
| 475 | EXPECT_FALSE(pw_Base64CallIsValid(kBase64, 11)); |
| 476 | EXPECT_FALSE(pw_Base64CallIsValid(kBase64, 12)); |
| 477 | } |
| 478 | |
| 479 | TEST(Base64CLinkage, Encode) { |
| 480 | char output[EncodedSize(sizeof("foobar")) + 1] = {}; |
| 481 | |
| 482 | pw_Base64CallEncode("", 0, output); |
| 483 | EXPECT_STREQ("", output); |
| 484 | pw_Base64CallEncode("f", 1, output); |
| 485 | EXPECT_STREQ("Zg==", output); |
| 486 | pw_Base64CallEncode("fo", 2, output); |
| 487 | } |
| 488 | |
| 489 | TEST(Base64CLinkage, Decode) { |
| 490 | char output[EncodedSize(sizeof("foobar")) + 1] = {}; |
| 491 | |
| 492 | EXPECT_EQ(0u, pw_Base64CallDecode("", 0, output)); |
| 493 | EXPECT_STREQ("", output); |
| 494 | EXPECT_EQ(1u, pw_Base64CallDecode("Zg==", 4, output)); |
| 495 | EXPECT_STREQ("f", output); |
| 496 | EXPECT_EQ(2u, pw_Base64CallDecode("Zm8=", 4, output)); |
| 497 | EXPECT_STREQ("fo", output); |
| 498 | } |
| 499 | |
| 500 | } // namespace |
| 501 | } // namespace pw::base64 |