| 1 | |
| 2 | |
| 3 | * KUnit test for the ACPI-WMI string conversion code.
|
| 4 | *
|
| 5 | * Copyright (C) 2025 Armin Wolf <[email protected]>
|
| 6 |
|
| 7 |
|
| 8 | #include <linux/module.h>
|
| 9 | #include <linux/slab.h>
|
| 10 | #include <linux/string.h>
|
| 11 | #include <linux/wmi.h>
|
| 12 |
|
| 13 | #include <kunit/resource.h>
|
| 14 | #include <kunit/test.h>
|
| 15 |
|
| 16 | #include <asm/byteorder.h>
|
| 17 |
|
| 18 | struct wmi_string_param {
|
| 19 | const char *name;
|
| 20 | const struct wmi_string *wmi_string;
|
| 21 | |
| 22 | * Remember that using sizeof() on a struct wmi_string will
|
| 23 | * always return a size of two bytes due to the flexible
|
| 24 | * array member!
|
| 25 |
|
| 26 | size_t wmi_string_length;
|
| 27 | const u8 *utf8_string;
|
| 28 | size_t utf8_string_length;
|
| 29 | };
|
| 30 |
|
| 31 | #define TEST_WMI_STRING_LENGTH 12
|
| 32 |
|
| 33 | static const struct wmi_string test_wmi_string = {
|
| 34 | .length = cpu_to_le16(10),
|
| 35 | .chars = {
|
| 36 | cpu_to_le16(u'T'),
|
| 37 | cpu_to_le16(u'E'),
|
| 38 | cpu_to_le16(u'S'),
|
| 39 | cpu_to_le16(u'T'),
|
| 40 | cpu_to_le16(u'\0'),
|
| 41 | },
|
| 42 | };
|
| 43 |
|
| 44 | static const u8 test_utf8_string[] = "TEST";
|
| 45 |
|
| 46 | #define SPECIAL_WMI_STRING_LENGTH 14
|
| 47 |
|
| 48 | static const struct wmi_string special_wmi_string = {
|
| 49 | .length = cpu_to_le16(12),
|
| 50 | .chars = {
|
| 51 | cpu_to_le16(u'Ä'),
|
| 52 | cpu_to_le16(u'Ö'),
|
| 53 | cpu_to_le16(u'Ü'),
|
| 54 | cpu_to_le16(u'ß'),
|
| 55 | cpu_to_le16(u'€'),
|
| 56 | cpu_to_le16(u'\0'),
|
| 57 | },
|
| 58 | };
|
| 59 |
|
| 60 | static const u8 special_utf8_string[] = "ÄÖÜ߀";
|
| 61 |
|
| 62 | #define MULTI_POINT_WMI_STRING_LENGTH 12
|
| 63 |
|
| 64 | static const struct wmi_string multi_point_wmi_string = {
|
| 65 | .length = cpu_to_le16(10),
|
| 66 | .chars = {
|
| 67 | cpu_to_le16(u'K'),
|
| 68 |
|
| 69 | cpu_to_le16(0xD83D),
|
| 70 | cpu_to_le16(0xDC27),
|
| 71 | cpu_to_le16(u'!'),
|
| 72 | cpu_to_le16(u'\0'),
|
| 73 | },
|
| 74 | };
|
| 75 |
|
| 76 | static const u8 multi_point_utf8_string[] = "K🐧!";
|
| 77 |
|
| 78 | #define PADDED_TEST_WMI_STRING_LENGTH 14
|
| 79 |
|
| 80 | static const struct wmi_string padded_test_wmi_string = {
|
| 81 | .length = cpu_to_le16(12),
|
| 82 | .chars = {
|
| 83 | cpu_to_le16(u'T'),
|
| 84 | cpu_to_le16(u'E'),
|
| 85 | cpu_to_le16(u'S'),
|
| 86 | cpu_to_le16(u'T'),
|
| 87 | cpu_to_le16(u'\0'),
|
| 88 | cpu_to_le16(u'\0'),
|
| 89 | },
|
| 90 | };
|
| 91 |
|
| 92 | static const u8 padded_test_utf8_string[] = "TEST\0";
|
| 93 |
|
| 94 | #define OVERSIZED_TEST_WMI_STRING_LENGTH 14
|
| 95 |
|
| 96 | static const struct wmi_string oversized_test_wmi_string = {
|
| 97 | .length = cpu_to_le16(8),
|
| 98 | .chars = {
|
| 99 | cpu_to_le16(u'T'),
|
| 100 | cpu_to_le16(u'E'),
|
| 101 | cpu_to_le16(u'S'),
|
| 102 | cpu_to_le16(u'T'),
|
| 103 | cpu_to_le16(u'!'),
|
| 104 | cpu_to_le16(u'\0'),
|
| 105 | },
|
| 106 | };
|
| 107 |
|
| 108 | static const u8 oversized_test_utf8_string[] = "TEST!";
|
| 109 |
|
| 110 | #define INVALID_TEST_WMI_STRING_LENGTH 14
|
| 111 |
|
| 112 | static const struct wmi_string invalid_test_wmi_string = {
|
| 113 | .length = cpu_to_le16(12),
|
| 114 | .chars = {
|
| 115 | cpu_to_le16(u'T'),
|
| 116 |
|
| 117 | cpu_to_le16(0xD83D),
|
| 118 | cpu_to_le16(u'E'),
|
| 119 | cpu_to_le16(u'S'),
|
| 120 | cpu_to_le16(u'T'),
|
| 121 | cpu_to_le16(u'\0'),
|
| 122 | },
|
| 123 | };
|
| 124 |
|
| 125 |
|
| 126 | static const u8 invalid_test_utf8_string[] = "T" "\xF0\x9F" "EST";
|
| 127 |
|
| 128 | static const struct wmi_string_param wmi_string_params_array[] = {
|
| 129 | {
|
| 130 | .name = "ascii_string",
|
| 131 | .wmi_string = &test_wmi_string,
|
| 132 | .wmi_string_length = TEST_WMI_STRING_LENGTH,
|
| 133 | .utf8_string = test_utf8_string,
|
| 134 | .utf8_string_length = sizeof(test_utf8_string),
|
| 135 | },
|
| 136 | {
|
| 137 | .name = "special_string",
|
| 138 | .wmi_string = &special_wmi_string,
|
| 139 | .wmi_string_length = SPECIAL_WMI_STRING_LENGTH,
|
| 140 | .utf8_string = special_utf8_string,
|
| 141 | .utf8_string_length = sizeof(special_utf8_string),
|
| 142 | },
|
| 143 | {
|
| 144 | .name = "multi_point_string",
|
| 145 | .wmi_string = &multi_point_wmi_string,
|
| 146 | .wmi_string_length = MULTI_POINT_WMI_STRING_LENGTH,
|
| 147 | .utf8_string = multi_point_utf8_string,
|
| 148 | .utf8_string_length = sizeof(multi_point_utf8_string),
|
| 149 | },
|
| 150 | };
|
| 151 |
|
| 152 | static void wmi_string_param_get_desc(const struct wmi_string_param *param, char *desc)
|
| 153 | {
|
| 154 | strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE);
|
| 155 | }
|
| 156 |
|
| 157 | KUNIT_ARRAY_PARAM(wmi_string, wmi_string_params_array, wmi_string_param_get_desc);
|
| 158 |
|
| 159 | static void wmi_string_to_utf8s_test(struct kunit *test)
|
| 160 | {
|
| 161 | const struct wmi_string_param *param = test->param_value;
|
| 162 | ssize_t ret;
|
| 163 | u8 *result;
|
| 164 |
|
| 165 | result = kunit_kzalloc(test, param->utf8_string_length, GFP_KERNEL);
|
| 166 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, result);
|
| 167 |
|
| 168 | ret = wmi_string_to_utf8s(param->wmi_string, result, param->utf8_string_length);
|
| 169 |
|
| 170 | KUNIT_EXPECT_EQ(test, ret, param->utf8_string_length - 1);
|
| 171 | KUNIT_EXPECT_MEMEQ(test, result, param->utf8_string, param->utf8_string_length);
|
| 172 | }
|
| 173 |
|
| 174 | static void wmi_string_from_utf8s_test(struct kunit *test)
|
| 175 | {
|
| 176 | const struct wmi_string_param *param = test->param_value;
|
| 177 | struct wmi_string *result;
|
| 178 | size_t max_chars;
|
| 179 | ssize_t ret;
|
| 180 |
|
| 181 | max_chars = (param->wmi_string_length - sizeof(*result)) / 2;
|
| 182 | result = kunit_kzalloc(test, param->wmi_string_length, GFP_KERNEL);
|
| 183 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, result);
|
| 184 |
|
| 185 | ret = wmi_string_from_utf8s(result, max_chars, param->utf8_string,
|
| 186 | param->utf8_string_length);
|
| 187 |
|
| 188 | KUNIT_EXPECT_EQ(test, ret, max_chars - 1);
|
| 189 | KUNIT_EXPECT_MEMEQ(test, result, param->wmi_string, param->wmi_string_length);
|
| 190 | }
|
| 191 |
|
| 192 | static void wmi_string_to_utf8s_padded_test(struct kunit *test)
|
| 193 | {
|
| 194 | u8 result[sizeof(padded_test_utf8_string)];
|
| 195 | ssize_t ret;
|
| 196 |
|
| 197 | ret = wmi_string_to_utf8s(&padded_test_wmi_string, result, sizeof(result));
|
| 198 |
|
| 199 | KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
|
| 200 | KUNIT_EXPECT_MEMEQ(test, result, test_utf8_string, sizeof(test_utf8_string));
|
| 201 | }
|
| 202 |
|
| 203 | static void wmi_string_from_utf8s_padded_test(struct kunit *test)
|
| 204 | {
|
| 205 | struct wmi_string *result;
|
| 206 | size_t max_chars;
|
| 207 | ssize_t ret;
|
| 208 |
|
| 209 | max_chars = (PADDED_TEST_WMI_STRING_LENGTH - sizeof(*result)) / 2;
|
| 210 | result = kunit_kzalloc(test, PADDED_TEST_WMI_STRING_LENGTH, GFP_KERNEL);
|
| 211 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, result);
|
| 212 |
|
| 213 | ret = wmi_string_from_utf8s(result, max_chars, padded_test_utf8_string,
|
| 214 | sizeof(padded_test_utf8_string));
|
| 215 |
|
| 216 | KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
|
| 217 | KUNIT_EXPECT_MEMEQ(test, result, &test_wmi_string, sizeof(test_wmi_string));
|
| 218 | }
|
| 219 |
|
| 220 | static void wmi_string_to_utf8s_oversized_test(struct kunit *test)
|
| 221 | {
|
| 222 | u8 result[sizeof(oversized_test_utf8_string)];
|
| 223 | ssize_t ret;
|
| 224 |
|
| 225 | ret = wmi_string_to_utf8s(&oversized_test_wmi_string, result, sizeof(result));
|
| 226 |
|
| 227 | KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
|
| 228 | KUNIT_EXPECT_MEMEQ(test, result, test_utf8_string, sizeof(test_utf8_string));
|
| 229 | }
|
| 230 |
|
| 231 | static void wmi_string_from_utf8s_oversized_test(struct kunit *test)
|
| 232 | {
|
| 233 | struct wmi_string *result;
|
| 234 | size_t max_chars;
|
| 235 | ssize_t ret;
|
| 236 |
|
| 237 | max_chars = (TEST_WMI_STRING_LENGTH - sizeof(*result)) / 2;
|
| 238 | result = kunit_kzalloc(test, TEST_WMI_STRING_LENGTH, GFP_KERNEL);
|
| 239 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, result);
|
| 240 |
|
| 241 | ret = wmi_string_from_utf8s(result, max_chars, oversized_test_utf8_string,
|
| 242 | sizeof(oversized_test_utf8_string));
|
| 243 |
|
| 244 | KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
|
| 245 | KUNIT_EXPECT_MEMEQ(test, result, &test_wmi_string, sizeof(test_wmi_string));
|
| 246 | }
|
| 247 |
|
| 248 | static void wmi_string_to_utf8s_invalid_test(struct kunit *test)
|
| 249 | {
|
| 250 | u8 result[sizeof(invalid_test_utf8_string)];
|
| 251 | ssize_t ret;
|
| 252 |
|
| 253 | ret = wmi_string_to_utf8s(&invalid_test_wmi_string, result, sizeof(result));
|
| 254 |
|
| 255 | KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
|
| 256 | KUNIT_EXPECT_MEMEQ(test, result, test_utf8_string, sizeof(test_utf8_string));
|
| 257 | }
|
| 258 |
|
| 259 | static void wmi_string_from_utf8s_invalid_test(struct kunit *test)
|
| 260 | {
|
| 261 | struct wmi_string *result;
|
| 262 | size_t max_chars;
|
| 263 | ssize_t ret;
|
| 264 |
|
| 265 | max_chars = (INVALID_TEST_WMI_STRING_LENGTH - sizeof(*result)) / 2;
|
| 266 | result = kunit_kzalloc(test, INVALID_TEST_WMI_STRING_LENGTH, GFP_KERNEL);
|
| 267 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, result);
|
| 268 |
|
| 269 | ret = wmi_string_from_utf8s(result, max_chars, invalid_test_utf8_string,
|
| 270 | sizeof(invalid_test_utf8_string));
|
| 271 |
|
| 272 | KUNIT_EXPECT_EQ(test, ret, -EINVAL);
|
| 273 | }
|
| 274 |
|
| 275 | static struct kunit_case wmi_string_test_cases[] = {
|
| 276 | KUNIT_CASE_PARAM(wmi_string_to_utf8s_test, wmi_string_gen_params),
|
| 277 | KUNIT_CASE_PARAM(wmi_string_from_utf8s_test, wmi_string_gen_params),
|
| 278 | KUNIT_CASE(wmi_string_to_utf8s_padded_test),
|
| 279 | KUNIT_CASE(wmi_string_from_utf8s_padded_test),
|
| 280 | KUNIT_CASE(wmi_string_to_utf8s_oversized_test),
|
| 281 | KUNIT_CASE(wmi_string_from_utf8s_oversized_test),
|
| 282 | KUNIT_CASE(wmi_string_to_utf8s_invalid_test),
|
| 283 | KUNIT_CASE(wmi_string_from_utf8s_invalid_test),
|
| 284 | {}
|
| 285 | };
|
| 286 |
|
| 287 | static struct kunit_suite wmi_string_test_suite = {
|
| 288 | .name = "wmi_string",
|
| 289 | .test_cases = wmi_string_test_cases,
|
| 290 | };
|
| 291 |
|
| 292 | kunit_test_suite(wmi_string_test_suite);
|
| 293 |
|
| 294 | MODULE_AUTHOR("Armin Wolf <[email protected]>");
|
| 295 | MODULE_DESCRIPTION("KUnit test for the ACPI-WMI string conversion code");
|
| 296 | MODULE_LICENSE("GPL");
|