// SPDX-License-Identifier: GPL-2.0
/*
* KUnit tests for HFS+ Unicode string operations
*
* Copyright (C) 2025 Viacheslav Dubeyko <slava@dubeyko.com>
*/
#include <kunit/test.h>
#include <linux/nls.h>
#include <linux/dcache.h>
#include <linux/stringhash.h>
#include "hfsplus_fs.h"
struct test_mock_string_env {
struct hfsplus_unistr str1;
struct hfsplus_unistr str2;
char *buf;
u32 buf_size;
};
static struct test_mock_string_env *setup_mock_str_env(u32 buf_size)
{
struct test_mock_string_env *env;
env = kzalloc_obj(struct test_mock_string_env);
if (!env)
return NULL;
env->buf = kzalloc(buf_size, GFP_KERNEL);
if (!env->buf) {
kfree(env);
return NULL;
}
env->buf_size = buf_size;
return env;
}
static void free_mock_str_env(struct test_mock_string_env *env)
{
if (env->buf)
kfree(env->buf);
kfree(env);
}
/* Helper function to create hfsplus_unistr */
static void create_unistr(struct hfsplus_unistr *ustr, const char *ascii_str)
{
int len = strlen(ascii_str);
int i;
memset(ustr->unicode, 0, sizeof(ustr->unicode));
ustr->length = cpu_to_be16(len);
for (i = 0; i < len && i < HFSPLUS_MAX_STRLEN; i++)
ustr->unicode[i] = cpu_to_be16((u16)ascii_str[i]);
}
static void corrupt_unistr(struct hfsplus_unistr *ustr)
{
ustr->length = cpu_to_be16(U16_MAX);
}
/* Test hfsplus_strcasecmp function */
static void hfsplus_strcasecmp_test(struct kunit *test)
{
struct test_mock_string_env *mock_env;
mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1);
KUNIT_ASSERT_NOT_NULL(test, mock_env);
/* Test identical strings */
create_unistr(&mock_env->str1, "hello");
create_unistr(&mock_env->str2, "hello");
KUNIT_EXPECT_EQ(test, 0, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2));
/* Test case insensitive comparison */
create_unistr(&mock_env->str1, "Hello");
create_unistr(&mock_env->str2, "hello");
KUNIT_EXPECT_EQ(test, 0, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2));
create_unistr(&mock_env->str1, "HELLO");
create_unistr(&mock_env->str2, "hello");
KUNIT_EXPECT_EQ(test, 0, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2));
/* Test different strings */
create_unistr(&mock_env->str1, "apple");
create_unistr(&mock_env->str2, "banana");
KUNIT_EXPECT_LT(test, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2), 0);
create_unistr(&mock_env->str1, "zebra");
create_unistr(&mock_env->str2, "apple");
KUNIT_EXPECT_GT(test, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2), 0);
/* Test different lengths */
create_unistr(&mock_env->str1, "test");
create_unistr(&mock_env->str2, "testing");
KUNIT_EXPECT_LT(test, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2), 0);
create_unistr(&mock_env->str1, "testing");
create_unistr(&mock_env->str2, "test");
KUNIT_EXPECT_GT(test, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2), 0);
/* Test empty strings */
create_unistr(&mock_env->str1, "");
create_unistr(&mock_env->str2, "");
KUNIT_EXPECT_EQ(test, 0, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2));
create_unistr(&mock_env->str1, "");
create_unistr(&mock_env->str2, "test");
KUNIT_EXPECT_LT(test, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2), 0);
/* Test single characters */
create_unistr(&mock_env->str1, "A");
create_unistr(&mock_env->str2, "a");
KUNIT_EXPECT_EQ(test, 0, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2));
create_unistr(&mock_env->str1, "A");
create_unistr(&mock_env->str2, "B");
KUNIT_EXPECT_LT(test, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2), 0);
/* Test maximum length strings */
memset(mock_env->buf, 'a', HFSPLUS_MAX_STRLEN);
mock_env->buf[HFSPLUS_MAX_STRLEN] = '\0';
create_unistr(&mock_env->str1, mock_env->buf);
create_unistr(&mock_env->str2, mock_env->buf);
KUNIT_EXPECT_EQ(test, 0, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2));
/* Change one character in the middle */
mock_env->buf[HFSPLUS_MAX_STRLEN / 2] = 'b';
create_unistr(&mock_env->str2, mock_env->buf);
KUNIT_EXPECT_LT(test, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2), 0);
/* Test corrupted strings */
create_unistr(&mock_env->str1, "");
corrupt_unistr(&mock_env->str1);
create_unistr(&mock_env->str2, "");
KUNIT_EXPECT_NE(test, 0, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2));
create_unistr(&mock_env->str1, "");
create_unistr(&mock_env->str2, "");
corrupt_unistr(&mock_env->str2);
KUNIT_EXPECT_NE(test, 0, hfsplus_strcasecmp(&mock_env->str1,
&mock_env->str2));
create_unistr(&mock_env->str1, "test");
corrupt_unistr(&mock_env->str1);
create_unistr
|