File Index
Files and directories
Sign in
FILE

base64_kunit.c

File preview with syntax highlighting.

linux-6.19.14/lib/tests/base64_kunit.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * base64_kunit_test.c - KUnit tests for base64 encoding and decoding functions
  4 *
  5 * Copyright (c) 2025, Guan-Chun Wu <409411716@gms.tku.edu.tw>
  6 */
  7
  8#include <kunit/test.h>
  9#include <linux/base64.h>
 10
 11/* ---------- Benchmark helpers ---------- */
 12static u64 bench_encode_ns(const u8 *data, int len, char *dst, int reps,
 13			   enum base64_variant variant)
 14{
 15	u64 t0, t1;
 16
 17	t0 = ktime_get_ns();
 18	for (int i = 0; i < reps; i++)
 19		base64_encode(data, len, dst, true, variant);
 20	t1 = ktime_get_ns();
 21
 22	return div64_u64(t1 - t0, (u64)reps);
 23}
 24
 25static u64 bench_decode_ns(const char *data, int len, u8 *dst, int reps,
 26			   enum base64_variant variant)
 27{
 28	u64 t0, t1;
 29
 30	t0 = ktime_get_ns();
 31	for (int i = 0; i < reps; i++)
 32		base64_decode(data, len, dst, true, variant);
 33	t1 = ktime_get_ns();
 34
 35	return div64_u64(t1 - t0, (u64)reps);
 36}
 37
 38static void run_perf_and_check(struct kunit *test, const char *label, int size,
 39			       enum base64_variant variant)
 40{
 41	const int reps = 1000;
 42	size_t outlen = DIV_ROUND_UP(size, 3) * 4;
 43	u8 *in = kmalloc(size, GFP_KERNEL);
 44	char *enc = kmalloc(outlen, GFP_KERNEL);
 45	u8 *decoded = kmalloc(size, GFP_KERNEL);
 46
 47	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, in);
 48	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, enc);
 49	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, decoded);
 50
 51	get_random_bytes(in, size);
 52	int enc_len = base64_encode(in, size, enc, true, variant);
 53	int dec_len = base64_decode(enc, enc_len, decoded, true, variant);
 54
 55	/* correctness sanity check */
 56	KUNIT_EXPECT_EQ(test, dec_len, size);
 57	KUNIT_EXPECT_MEMEQ(test, decoded, in, size);
 58
 59	/* benchmark encode */
 60
 61	u64 t1 = bench_encode_ns(in, size, enc, reps, variant);
 62
 63	kunit_info(test, "[%s] encode run : %lluns", label, t1);
 64
 65	u64 t2 = bench_decode_ns(enc, enc_len, decoded, reps, variant);
 66
 67	kunit_info(test, "[%s] decode run : %lluns", label, t2);
 68
 69	kfree(in);
 70	kfree(enc);
 71	kfree(decoded);
 72}
 73
 74static void base64_performance_tests(struct kunit *test)
 75{
 76	/* run on STD variant only */
 77	run_perf_and_check(test, "64B", 64, BASE64_STD);
 78	run_perf_and_check(test, "1KB", 1024, BASE64_STD);
 79}
 80
 81/* ---------- Helpers for encode ---------- */
 82static void expect_encode_ok(struct kunit *test, const u8 *src, int srclen,
 83			     const char *expected, bool padding,
 84			     enum base64_variant variant)
 85{
 86	char buf[128];
 87	int encoded_len = base64_encode(src, srclen, buf, padding, variant);
 88
 89	buf[encoded_len] = '\0';
 90
 91	KUNIT_EXPECT_EQ(test, encoded_len, strlen(expected));
 92	KUNIT_EXPECT_STREQ(test, buf, expected);
 93}
 94
 95/* ---------- Helpers for decode ---------- */
 96static void expect_decode_ok(struct kunit *test, const char *src,
 97			     const u8 *expected, int expected_len, bool padding,
 98			     enum base64_variant variant)
 99{
100	u8 buf[128];
101	int decoded_len = base64_decode(src, strlen(src), buf, padding, variant);
102
103	KUNIT_EXPECT_EQ(test, decoded_len, expected_len);
104	KUNIT_EXPECT_MEMEQ(test, buf, expected, expected_len);
105}
106
107static void expect_decode_err(struct kunit *test, const char *src,
108			      int srclen, bool padding,
109			      enum base64_variant variant)
110{
111	u8 buf[64];
112	int decoded_len = base64_decode(src, srclen, buf, padding, variant);
113
114	KUNIT_EXPECT_EQ(test, decoded_len, -1);
115}
116
117/* ---------- Encode Tests ---------- */
118static void base64_std_encode_tests(struct kunit *test)
119{
120	/* With padding */
121	expect_encode_ok(test, (const u8 *)"", 0, "", true, BASE64_STD);
122	expect_encode_ok(test, (const u8 *)"f", 1, "Zg==", true, BASE64_STD);
123	expect_encode_ok(test, (const u8 *)"fo", 2, "Zm8=", true, BASE64_STD);
124	expect_encode_ok(test, (const u8 *)"foo", 3, "Zm9v", true, BASE64_STD);
125	expect_encode_ok(test, (const u8 *)"foob", 4, "Zm9vYg==", true, BASE64_STD);
126	expect_encode_ok(test, (const u8 *)"fooba", 5, "Zm9vYmE=", true, BASE64_STD);
127	expect_encode_ok(test, (const u8 *)"foobar", 6, "Zm9vYmFy", true, BASE64_STD);
128
129	/* Extra cases with padding */
130	expect_encode_ok(test, (const u8 *)"Hello, world!", 13, "SGVsbG8sIHdvcmxkIQ==",
131			 true, BASE64_STD);
132	expect_encode_ok(test, (const u8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26,
133			 "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", true, BASE64_STD);
134	expect_encode_ok(test, (const u8 *)"abcdefghijklmnopqrstuvwxyz", 26,
135			 "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=", true, BASE64_STD);
136	expect_encode_ok(test, (const u8 *)"0123456789+/", 12, "MDEyMzQ1Njc4OSsv",
137			 true, BASE64_STD);
138
139	/* Without padding */
140	expect_encode_ok(test, (const u8 *)"", 0, "", false, BASE64_STD);
141	expect_encode_ok(test, (const u8 *)"f", 1, "Zg", false, BASE64_STD);
142	expect_encode_ok(test, (const u8 *)"fo", 2, "Zm8", false, BASE64_STD);
143	expect_encode_ok(test, (const u8 *)"foo", 3, "Zm9v", false, BASE64_STD);
144	expect_encode_ok(test, (const u8 *)"foob", 4, "Zm9vYg", false, BASE64_STD);
145	expect_encode_ok(test, (const u8 *)"fooba", 5, "Zm9vYmE", false, BASE64_STD);
146	expect_encode_ok(test, (const u8 *)"foobar", 6, "Zm9vYmFy", false, BASE64_STD);
147
148	/* Extra cases without padding */
149	expect_encode_ok(test, (const u8 *)"Hello, world!", 13, "SGVsbG8sIHdvcmxkIQ",
150			 false, BASE64_STD);
151	expect_encode_ok(test, (const u8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26,
152			 "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo", false, BASE64_STD);
153	expect_encode_ok(test, (const u8 *)"abcdefghijklmnopqrstuvwxyz", 26,
154			 "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo", false, BASE64_STD);
155	expect_encode_ok(test, (const u8 *)"0123456789+/", 12, "MDEyMzQ1Njc4OSsv",
156			 false, BASE64_STD);
157}
158
159/* ---------- Decode Tests ---------- */
160static void base64_std_decode_tests(struct kunit *test)
161{
162	/* -------- With padding --------*/
163	expect_decode_ok(test, "", (const u8 *)"", 0, true, BASE64_STD);
164	expect_decode_ok(test, "Zg==", (const u8 *)"f", 1, true, BASE64_STD);
165	expect_decode_ok(test, "Zm8=", (const u8 *)"fo", 2, true, BASE64_STD);
166	expect_decode_ok(test, "Zm9v", (const u8 *)"foo", 3, true, BASE64_STD);
167	expect_decode_ok(test, "Zm9vYg==", (const u8 *)"foob", 4, true, BASE64_STD);
168	expect_decode_ok(test, "Zm9vYmE=", (const u8 *)"fooba", 5, true, BASE64_STD);
169	expect_decode_ok(test, "Zm9vYmFy", (const u8 *)"foobar", 6, true, BASE64_STD);
170	expect_decode_ok(test, "SGVsbG8sIHdvcmxkIQ==", (const u8 *)"Hello, world!", 13,
171			 true, BASE64_STD);
172	expect_decode_ok(test, "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=",
173			 (const u8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26, true, BASE64_STD);
174	expect_decode_ok(test, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=",
175			 (const u8 *)"abcdefghijklmnopqrstuvwxyz", 26, true, BASE64_STD);
176
177	/* Error cases */
178	expect_decode_err(test, "Zg=!", 4, true, BASE64_STD);
179	expect_decode_err(test, "Zm$=", 4, true, BASE64_STD);
180	expect_decode_err(test, "Z===", 4, true, BASE64_STD);
181	expect_decode_err(test, "Zg", 2, true, BASE64_STD);
182	expect_decode_err(test, "Zm9v====", 8, true, BASE64_STD);
183	expect_decode_err(test, "Zm==A", 5, true, BASE64_STD);
184
185	{
186		char with_nul[4] = { 'Z', 'g', '\0', '=' };
187
188		expect_decode_err(test, with_nul, 4, true, BASE64_STD);
189	}
190
191	/* -------- Without padding --------*/
192	expect_decode_ok(test, "", (const u8 *)"", 0, false, BASE64_STD);
193	expect_decode_ok(test, "Zg", (const u8 *)"f", 1, false, BASE64_STD);
194	expect_decode_ok(test, "Zm8", (const u8 *)"fo", 2, false, BASE64_STD);
195	expect_decode_ok(test, "Zm9v", (const u8 *)"foo", 3, false, BASE64_STD);
196	expect_decode_ok(test, "Zm9vYg", (const u8 *)"foob", 4, false, BASE64_STD);
197	expect_decode_ok(test, "Zm9vYmE", (const u8 *)"fooba", 5, false, BASE64_STD);
198	expect_decode_ok(test, "Zm9vYmFy", (const u8 *)"foobar", 6, false, BASE64_STD);
199	expect_decode_ok(test, "TWFu", (const u8 *)"Man", 3, false, BASE64_STD);
200	expect_decode_ok(test, "SGVsbG8sIHdvcmxkIQ", (const u8 *)"Hello, world!", 13,
201			 false, BASE64_STD);
202	expect_decode_ok(test, "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo",
203			 (const u8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26, false, BASE64_STD);
204	expect_decode_ok(test, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo",
205			 (const u8 *)"abcdefghijklmnopqrstuvwxyz", 26, false, BASE64_STD);
206	expect_decode_ok(test, "MDEyMzQ1Njc4OSsv", (const u8 *)"0123456789+/", 12,
207			 false, BASE64_STD);
208
209	/* Error cases */
210	expect_decode_err(test, "Zg=!", 4, false, BASE64_STD);
211	expect_decode_err(test, "Zm$=", 4, false, BASE64_STD);
212	expect_decode_err(test, "Z===", 4, false, BASE64_STD);
213	expect_decode_err(test, "Zg=", 3, false, BASE64_STD);
214	expect_decode_err(test, "Zm9v====", 8, false, BASE64_STD);
215	expect_decode_err(test, "Zm==v", 4, false, BASE64_STD);
216
217	{
218		char with_nul[4] = { 'Z', 'g', '\0', '=' };
219
220		expect_decode_err(test, with_nul, 4, false, BASE64_STD);
221	}
222}
223
224/* ---------- Variant tests (URLSAFE / IMAP) ---------- */
225static void base64_variant_tests(struct kunit *test)
226{
227	const u8 sample1[] = { 0x00, 0xfb, 0xff, 0x7f, 0x80 };
228	char std_buf[128], url_buf[128], imap_buf[128];
229	u8 back[128];
230	int n_std, n_url, n_imap, m;
231	int i;
232
233	n_std = base64_encode(sample1, sizeof(sample1), std_buf, false, BASE64_STD);
234	n_url = base64_encode(sample1, sizeof(sample1), url_buf, false, BASE64_URLSAFE);
235	std_buf[n_std] = '\0';
236	url_buf[n_url] = '\0';
237
238	for (i = 0; i < n_std; i++) {
239		if (std_buf[i] == '+')
240			std_buf[i] = '-';
241		else if (std_buf[i] == '/')
242			std_buf[i] = '_';
243	}
244	KUNIT_EXPECT_STREQ(test, std_buf, url_buf);
245
246	m = base64_decode(url_buf, n_url, back, false, BASE64_URLSAFE);
247	KUNIT_EXPECT_EQ(test, m, (int)sizeof(sample1));
248	KUNIT_EXPECT_MEMEQ(test, back, sample1, sizeof(sample1));
249
250	n_std  = base64_encode(sample1, sizeof(sample1), std_buf, false, BASE64_STD);
251	n_imap = base64_encode(sample1, sizeof(sample1), imap_buf, false, BASE64_IMAP);
252	std_buf[n_std]   = '\0';
253	imap_buf[n_imap] = '\0';
254
255	for (i = 0; i < n_std; i++)
256		if (std_buf[i] == '/')
257			std_buf[i] = ',';
258	KUNIT_EXPECT_STREQ(test, std_buf, imap_buf);
259
260	m = base64_decode(imap_buf, n_imap, back, false, BASE64_IMAP);
261	KUNIT_EXPECT_EQ(test, m, (int)sizeof(sample1));
262	KUNIT_EXPECT_MEMEQ(test, back, sample1, sizeof(sample1));
263
264	{
265		const char *bad = "Zg==";
266		u8 tmp[8];
267
268		m = base64_decode(bad, strlen(bad), tmp, false, BASE64_URLSAFE);
269		KUNIT_EXPECT_EQ(test, m, -1);
270
271		m = base64_decode(bad, strlen(bad), tmp, false, BASE64_IMAP);
272		KUNIT_EXPECT_EQ(test, m, -1);
273	}
274}
275
276/* ---------- Test registration ---------- */
277static struct kunit_case base64_test_cases[] = {
278	KUNIT_CASE(base64_performance_tests),
279	KUNIT_CASE(base64_std_encode_tests),
280	KUNIT_CASE(base64_std_decode_tests),
281	KUNIT_CASE(base64_variant_tests),
282	{}
283};
284
285static struct kunit_suite base64_test_suite = {
286	.name = "base64",
287	.test_cases = base64_test_cases,
288};
289
290kunit_test_suite(base64_test_suite);
291
292MODULE_AUTHOR("Guan-Chun Wu <409411716@gms.tku.edu.tw>");
293MODULE_DESCRIPTION("KUnit tests for Base64 encoding/decoding, including performance checks");
294MODULE_LICENSE("GPL");
~/ Read-only file preview.