297 lines
8.0 KiB
C
297 lines
8.0 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* KUnit test for the ACPI-WMI string conversion code.
|
|
*
|
|
* Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/string.h>
|
|
#include <linux/wmi.h>
|
|
|
|
#include <kunit/resource.h>
|
|
#include <kunit/test.h>
|
|
|
|
#include <asm/byteorder.h>
|
|
|
|
struct wmi_string_param {
|
|
const char *name;
|
|
const struct wmi_string *wmi_string;
|
|
/*
|
|
* Remember that using sizeof() on a struct wmi_string will
|
|
* always return a size of two bytes due to the flexible
|
|
* array member!
|
|
*/
|
|
size_t wmi_string_length;
|
|
const u8 *utf8_string;
|
|
size_t utf8_string_length;
|
|
};
|
|
|
|
#define TEST_WMI_STRING_LENGTH 12
|
|
|
|
static const struct wmi_string test_wmi_string = {
|
|
.length = cpu_to_le16(10),
|
|
.chars = {
|
|
cpu_to_le16(u'T'),
|
|
cpu_to_le16(u'E'),
|
|
cpu_to_le16(u'S'),
|
|
cpu_to_le16(u'T'),
|
|
cpu_to_le16(u'\0'),
|
|
},
|
|
};
|
|
|
|
static const u8 test_utf8_string[] = "TEST";
|
|
|
|
#define SPECIAL_WMI_STRING_LENGTH 14
|
|
|
|
static const struct wmi_string special_wmi_string = {
|
|
.length = cpu_to_le16(12),
|
|
.chars = {
|
|
cpu_to_le16(u'Ä'),
|
|
cpu_to_le16(u'Ö'),
|
|
cpu_to_le16(u'Ü'),
|
|
cpu_to_le16(u'ß'),
|
|
cpu_to_le16(u'€'),
|
|
cpu_to_le16(u'\0'),
|
|
},
|
|
};
|
|
|
|
static const u8 special_utf8_string[] = "ÄÖÜ߀";
|
|
|
|
#define MULTI_POINT_WMI_STRING_LENGTH 12
|
|
|
|
static const struct wmi_string multi_point_wmi_string = {
|
|
.length = cpu_to_le16(10),
|
|
.chars = {
|
|
cpu_to_le16(u'K'),
|
|
/* 🐧 */
|
|
cpu_to_le16(0xD83D),
|
|
cpu_to_le16(0xDC27),
|
|
cpu_to_le16(u'!'),
|
|
cpu_to_le16(u'\0'),
|
|
},
|
|
};
|
|
|
|
static const u8 multi_point_utf8_string[] = "K🐧!";
|
|
|
|
#define PADDED_TEST_WMI_STRING_LENGTH 14
|
|
|
|
static const struct wmi_string padded_test_wmi_string = {
|
|
.length = cpu_to_le16(12),
|
|
.chars = {
|
|
cpu_to_le16(u'T'),
|
|
cpu_to_le16(u'E'),
|
|
cpu_to_le16(u'S'),
|
|
cpu_to_le16(u'T'),
|
|
cpu_to_le16(u'\0'),
|
|
cpu_to_le16(u'\0'),
|
|
},
|
|
};
|
|
|
|
static const u8 padded_test_utf8_string[] = "TEST\0";
|
|
|
|
#define OVERSIZED_TEST_WMI_STRING_LENGTH 14
|
|
|
|
static const struct wmi_string oversized_test_wmi_string = {
|
|
.length = cpu_to_le16(8),
|
|
.chars = {
|
|
cpu_to_le16(u'T'),
|
|
cpu_to_le16(u'E'),
|
|
cpu_to_le16(u'S'),
|
|
cpu_to_le16(u'T'),
|
|
cpu_to_le16(u'!'),
|
|
cpu_to_le16(u'\0'),
|
|
},
|
|
};
|
|
|
|
static const u8 oversized_test_utf8_string[] = "TEST!";
|
|
|
|
#define INVALID_TEST_WMI_STRING_LENGTH 14
|
|
|
|
static const struct wmi_string invalid_test_wmi_string = {
|
|
.length = cpu_to_le16(12),
|
|
.chars = {
|
|
cpu_to_le16(u'T'),
|
|
/* 🐧, with low surrogate missing */
|
|
cpu_to_le16(0xD83D),
|
|
cpu_to_le16(u'E'),
|
|
cpu_to_le16(u'S'),
|
|
cpu_to_le16(u'T'),
|
|
cpu_to_le16(u'\0'),
|
|
},
|
|
};
|
|
|
|
/* We have to split the string here to end the hex escape sequence */
|
|
static const u8 invalid_test_utf8_string[] = "T" "\xF0\x9F" "EST";
|
|
|
|
static const struct wmi_string_param wmi_string_params_array[] = {
|
|
{
|
|
.name = "ascii_string",
|
|
.wmi_string = &test_wmi_string,
|
|
.wmi_string_length = TEST_WMI_STRING_LENGTH,
|
|
.utf8_string = test_utf8_string,
|
|
.utf8_string_length = sizeof(test_utf8_string),
|
|
},
|
|
{
|
|
.name = "special_string",
|
|
.wmi_string = &special_wmi_string,
|
|
.wmi_string_length = SPECIAL_WMI_STRING_LENGTH,
|
|
.utf8_string = special_utf8_string,
|
|
.utf8_string_length = sizeof(special_utf8_string),
|
|
},
|
|
{
|
|
.name = "multi_point_string",
|
|
.wmi_string = &multi_point_wmi_string,
|
|
.wmi_string_length = MULTI_POINT_WMI_STRING_LENGTH,
|
|
.utf8_string = multi_point_utf8_string,
|
|
.utf8_string_length = sizeof(multi_point_utf8_string),
|
|
},
|
|
};
|
|
|
|
static void wmi_string_param_get_desc(const struct wmi_string_param *param, char *desc)
|
|
{
|
|
strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE);
|
|
}
|
|
|
|
KUNIT_ARRAY_PARAM(wmi_string, wmi_string_params_array, wmi_string_param_get_desc);
|
|
|
|
static void wmi_string_to_utf8s_test(struct kunit *test)
|
|
{
|
|
const struct wmi_string_param *param = test->param_value;
|
|
ssize_t ret;
|
|
u8 *result;
|
|
|
|
result = kunit_kzalloc(test, param->utf8_string_length, GFP_KERNEL);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, result);
|
|
|
|
ret = wmi_string_to_utf8s(param->wmi_string, result, param->utf8_string_length);
|
|
|
|
KUNIT_EXPECT_EQ(test, ret, param->utf8_string_length - 1);
|
|
KUNIT_EXPECT_MEMEQ(test, result, param->utf8_string, param->utf8_string_length);
|
|
}
|
|
|
|
static void wmi_string_from_utf8s_test(struct kunit *test)
|
|
{
|
|
const struct wmi_string_param *param = test->param_value;
|
|
struct wmi_string *result;
|
|
size_t max_chars;
|
|
ssize_t ret;
|
|
|
|
max_chars = (param->wmi_string_length - sizeof(*result)) / 2;
|
|
result = kunit_kzalloc(test, param->wmi_string_length, GFP_KERNEL);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, result);
|
|
|
|
ret = wmi_string_from_utf8s(result, max_chars, param->utf8_string,
|
|
param->utf8_string_length);
|
|
|
|
KUNIT_EXPECT_EQ(test, ret, max_chars - 1);
|
|
KUNIT_EXPECT_MEMEQ(test, result, param->wmi_string, param->wmi_string_length);
|
|
}
|
|
|
|
static void wmi_string_to_utf8s_padded_test(struct kunit *test)
|
|
{
|
|
u8 result[sizeof(padded_test_utf8_string)];
|
|
ssize_t ret;
|
|
|
|
ret = wmi_string_to_utf8s(&padded_test_wmi_string, result, sizeof(result));
|
|
|
|
KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
|
|
KUNIT_EXPECT_MEMEQ(test, result, test_utf8_string, sizeof(test_utf8_string));
|
|
}
|
|
|
|
static void wmi_string_from_utf8s_padded_test(struct kunit *test)
|
|
{
|
|
struct wmi_string *result;
|
|
size_t max_chars;
|
|
ssize_t ret;
|
|
|
|
max_chars = (PADDED_TEST_WMI_STRING_LENGTH - sizeof(*result)) / 2;
|
|
result = kunit_kzalloc(test, PADDED_TEST_WMI_STRING_LENGTH, GFP_KERNEL);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, result);
|
|
|
|
ret = wmi_string_from_utf8s(result, max_chars, padded_test_utf8_string,
|
|
sizeof(padded_test_utf8_string));
|
|
|
|
KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
|
|
KUNIT_EXPECT_MEMEQ(test, result, &test_wmi_string, sizeof(test_wmi_string));
|
|
}
|
|
|
|
static void wmi_string_to_utf8s_oversized_test(struct kunit *test)
|
|
{
|
|
u8 result[sizeof(oversized_test_utf8_string)];
|
|
ssize_t ret;
|
|
|
|
ret = wmi_string_to_utf8s(&oversized_test_wmi_string, result, sizeof(result));
|
|
|
|
KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
|
|
KUNIT_EXPECT_MEMEQ(test, result, test_utf8_string, sizeof(test_utf8_string));
|
|
}
|
|
|
|
static void wmi_string_from_utf8s_oversized_test(struct kunit *test)
|
|
{
|
|
struct wmi_string *result;
|
|
size_t max_chars;
|
|
ssize_t ret;
|
|
|
|
max_chars = (TEST_WMI_STRING_LENGTH - sizeof(*result)) / 2;
|
|
result = kunit_kzalloc(test, TEST_WMI_STRING_LENGTH, GFP_KERNEL);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, result);
|
|
|
|
ret = wmi_string_from_utf8s(result, max_chars, oversized_test_utf8_string,
|
|
sizeof(oversized_test_utf8_string));
|
|
|
|
KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
|
|
KUNIT_EXPECT_MEMEQ(test, result, &test_wmi_string, sizeof(test_wmi_string));
|
|
}
|
|
|
|
static void wmi_string_to_utf8s_invalid_test(struct kunit *test)
|
|
{
|
|
u8 result[sizeof(invalid_test_utf8_string)];
|
|
ssize_t ret;
|
|
|
|
ret = wmi_string_to_utf8s(&invalid_test_wmi_string, result, sizeof(result));
|
|
|
|
KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
|
|
KUNIT_EXPECT_MEMEQ(test, result, test_utf8_string, sizeof(test_utf8_string));
|
|
}
|
|
|
|
static void wmi_string_from_utf8s_invalid_test(struct kunit *test)
|
|
{
|
|
struct wmi_string *result;
|
|
size_t max_chars;
|
|
ssize_t ret;
|
|
|
|
max_chars = (INVALID_TEST_WMI_STRING_LENGTH - sizeof(*result)) / 2;
|
|
result = kunit_kzalloc(test, INVALID_TEST_WMI_STRING_LENGTH, GFP_KERNEL);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, result);
|
|
|
|
ret = wmi_string_from_utf8s(result, max_chars, invalid_test_utf8_string,
|
|
sizeof(invalid_test_utf8_string));
|
|
|
|
KUNIT_EXPECT_EQ(test, ret, -EINVAL);
|
|
}
|
|
|
|
static struct kunit_case wmi_string_test_cases[] = {
|
|
KUNIT_CASE_PARAM(wmi_string_to_utf8s_test, wmi_string_gen_params),
|
|
KUNIT_CASE_PARAM(wmi_string_from_utf8s_test, wmi_string_gen_params),
|
|
KUNIT_CASE(wmi_string_to_utf8s_padded_test),
|
|
KUNIT_CASE(wmi_string_from_utf8s_padded_test),
|
|
KUNIT_CASE(wmi_string_to_utf8s_oversized_test),
|
|
KUNIT_CASE(wmi_string_from_utf8s_oversized_test),
|
|
KUNIT_CASE(wmi_string_to_utf8s_invalid_test),
|
|
KUNIT_CASE(wmi_string_from_utf8s_invalid_test),
|
|
{}
|
|
};
|
|
|
|
static struct kunit_suite wmi_string_test_suite = {
|
|
.name = "wmi_string",
|
|
.test_cases = wmi_string_test_cases,
|
|
};
|
|
|
|
kunit_test_suite(wmi_string_test_suite);
|
|
|
|
MODULE_AUTHOR("Armin Wolf <W_Armin@gmx.de>");
|
|
MODULE_DESCRIPTION("KUnit test for the ACPI-WMI string conversion code");
|
|
MODULE_LICENSE("GPL");
|