tests/lib: Add unit tests for ux_locales_get_text()
Add unit tests for ux_locales_get_text() in lib/ux_locales.c. BUG=b:264666392, b:289995591 BRANCH=brya TEST=make tests/lib/ux_locales-test TEST=Make sure ux_locales.c has 100% test coverage Signed-off-by: Hsuan Ting Chen <roccochen@chromium.org> Change-Id: I4d73419c02478870942828d324c258ef0eaa983c Reviewed-on: https://review.coreboot.org/c/coreboot/+/76253 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Yu-Ping Wu <yupingso@google.com> Reviewed-by: Jakub Czapiga <jacz@semihalf.com>
This commit is contained in:
parent
cbedae116c
commit
abaa4b5a96
|
@ -40,6 +40,7 @@ tests-y += cbfs-no-verification-has-sha512-test
|
|||
tests-y += cbfs-lookup-no-mcache-test
|
||||
tests-y += cbfs-lookup-has-mcache-test
|
||||
tests-y += lzma-test
|
||||
tests-y += ux_locales-test
|
||||
|
||||
lib-test-srcs += tests/lib/lib-test.c
|
||||
|
||||
|
@ -241,3 +242,11 @@ lzma-test-srcs += tests/lib/lzma-test.c
|
|||
lzma-test-srcs += tests/stubs/console.c
|
||||
lzma-test-srcs += src/lib/lzma.c
|
||||
lzma-test-srcs += src/lib/lzmadecode.c
|
||||
|
||||
ux_locales-test-srcs += tests/lib/ux_locales-test.c
|
||||
ux_locales-test-srcs += tests/stubs/console.c
|
||||
ux_locales-test-srcs += src/lib/ux_locales.c
|
||||
ux_locales-test-mocks += _cbfs_alloc \
|
||||
cbfs_unmap \
|
||||
vb2api_get_locale_id \
|
||||
vboot_get_context
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <cbfs.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <tests/test.h>
|
||||
#include <ux_locales.h>
|
||||
#include <vb2_api.h>
|
||||
|
||||
#define DATA_DEFAULT \
|
||||
( \
|
||||
"\x01" /* Version. */ \
|
||||
"name_1\x00" /* name_1, langs = [0, 2, 30]. */ \
|
||||
"0\x00translation_1_0\x00" \
|
||||
"2\x00translation_1_2\x00" \
|
||||
"30\x00translation_1_30\x00" \
|
||||
"\x01" \
|
||||
"name_15\x00" /* name_15, langs = [4, 25, 60]. */ \
|
||||
"4\x00translation_15_4\x00" \
|
||||
"25\x00translation_15_25\x00" \
|
||||
"60\x00translation_15_60\x00" \
|
||||
"\x01" \
|
||||
"name_20\x00" /* name_20, langs = [8]. */ \
|
||||
"8\x00translation_20_8\x00" \
|
||||
"\x01" \
|
||||
)
|
||||
const unsigned char data_default[] = DATA_DEFAULT;
|
||||
|
||||
/*
|
||||
* The data must be set in the setup function and might be used in cbfs related functions.
|
||||
* The size of the data must be recorded because the data contains the null character \x00.
|
||||
*
|
||||
* Note that sizeof(DATA_DEFAULT) will count the '\0' at the end, so DATA_DEFAULT_SIZE, i.e.
|
||||
* the real data size must be minus one.
|
||||
*/
|
||||
#define DATA_DEFAULT_SIZE (sizeof(DATA_DEFAULT) - 1)
|
||||
|
||||
#define MAX_DATA_SIZE (DATA_DEFAULT_SIZE + 1)
|
||||
struct {
|
||||
unsigned char raw[MAX_DATA_SIZE];
|
||||
size_t size;
|
||||
} data;
|
||||
|
||||
/* Mock functions. */
|
||||
void cbfs_unmap(void *mapping)
|
||||
{
|
||||
/* No-op. */
|
||||
}
|
||||
|
||||
/* We can't mock cbfs_ro_map() directly as it's a static inline function. */
|
||||
void *_cbfs_alloc(const char *name, cbfs_allocator_t allocator, void *arg,
|
||||
size_t *size_out, bool force_ro, enum cbfs_type *type)
|
||||
{
|
||||
/* Mock a successful CBFS mapping. */
|
||||
if (mock_type(bool)) {
|
||||
*size_out = data.size;
|
||||
return data.raw;
|
||||
}
|
||||
*size_out = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t vb2api_get_locale_id(struct vb2_context *ctx)
|
||||
{
|
||||
return mock_type(uint32_t);
|
||||
}
|
||||
|
||||
struct vb2_context *vboot_get_context(void)
|
||||
{
|
||||
static struct vb2_context vboot2_ctx;
|
||||
return &vboot2_ctx;
|
||||
}
|
||||
|
||||
/* Test states for test_ux_locales_get_text with valid CBFS data. */
|
||||
struct ux_locales_test_state {
|
||||
const char *name;
|
||||
uint32_t lang_id;
|
||||
const char *expect;
|
||||
};
|
||||
|
||||
/* Setup and teardown functions. */
|
||||
static int setup_default(void **state)
|
||||
{
|
||||
void *ret;
|
||||
/* Setup the mocked cbfs region data. */
|
||||
data.size = DATA_DEFAULT_SIZE;
|
||||
ret = memset(data.raw, 0xff, MAX_DATA_SIZE);
|
||||
if (!ret)
|
||||
return 1;
|
||||
ret = memcpy(data.raw, data_default, data.size);
|
||||
if (!ret)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_bad_version(void **state)
|
||||
{
|
||||
int ret = setup_default(state);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Modify the version byte. */
|
||||
data.raw[0] = ~data.raw[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int teardown_unmap(void **state)
|
||||
{
|
||||
/* We need to reset the cached_state in src/lib/ux_locales.c. */
|
||||
ux_locales_unmap();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Test items. */
|
||||
static void test_ux_locales_get_text(void **state)
|
||||
{
|
||||
struct ux_locales_test_state *s = *state;
|
||||
const char *ret;
|
||||
|
||||
will_return(_cbfs_alloc, true);
|
||||
will_return(vb2api_get_locale_id, s->lang_id);
|
||||
ret = ux_locales_get_text(s->name);
|
||||
if (s->expect) {
|
||||
assert_non_null(ret);
|
||||
assert_string_equal(ret, s->expect);
|
||||
} else {
|
||||
assert_null(ret);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_ux_locales_bad_cbfs(void **state)
|
||||
{
|
||||
will_return(_cbfs_alloc, false);
|
||||
will_return_maybe(vb2api_get_locale_id, 0);
|
||||
assert_null(ux_locales_get_text("name_1"));
|
||||
}
|
||||
|
||||
static void test_ux_locales_bad_version(void **state)
|
||||
{
|
||||
will_return(_cbfs_alloc, true);
|
||||
will_return(vb2api_get_locale_id, 0);
|
||||
assert_null(ux_locales_get_text("name_1"));
|
||||
}
|
||||
|
||||
static void test_ux_locales_two_calls(void **state)
|
||||
{
|
||||
const char *ret;
|
||||
|
||||
/* We do not need to ensure that we cached the cbfs region. */
|
||||
will_return_always(_cbfs_alloc, true);
|
||||
|
||||
/* Call #1: read (15, 60). */
|
||||
will_return(vb2api_get_locale_id, 60);
|
||||
ret = ux_locales_get_text("name_15");
|
||||
assert_non_null(ret);
|
||||
assert_string_equal(ret, "translation_15_60");
|
||||
|
||||
/* Call #2: read (1, 0). */
|
||||
will_return(vb2api_get_locale_id, 0);
|
||||
ret = ux_locales_get_text("name_1");
|
||||
assert_non_null(ret);
|
||||
assert_string_equal(ret, "translation_1_0");
|
||||
}
|
||||
|
||||
static void test_ux_locales_null_terminated(void **state)
|
||||
{
|
||||
will_return_always(_cbfs_alloc, true);
|
||||
will_return_always(vb2api_get_locale_id, 8);
|
||||
|
||||
/* Verify the access to the very last text. */
|
||||
assert_non_null(ux_locales_get_text("name_20"));
|
||||
|
||||
/* Modify the last 2 bytes from "\x00\x01" to "XX" and unmap, */
|
||||
data.raw[data.size - 1] = 'X';
|
||||
data.raw[data.size - 2] = 'X';
|
||||
ux_locales_unmap();
|
||||
|
||||
/* The last few characters are now changed so that the data is not NULL terminated.
|
||||
This will prevent us from accessing the last text. */
|
||||
assert_null(ux_locales_get_text("name_20"));
|
||||
}
|
||||
|
||||
/*
|
||||
* This macro helps test ux_locales_get_text with `_name` and `_lang_id`.
|
||||
* If `_expect` is NULL, then the function should not find anything.
|
||||
* Otherwise, the function should find the corresponding expect value.
|
||||
*/
|
||||
#define _UX_LOCALES_GET_TEXT_TEST(_test_name, _name, _lang_id, _expect) \
|
||||
((struct CMUnitTest) { \
|
||||
.name = _test_name, \
|
||||
.test_func = test_ux_locales_get_text, \
|
||||
.setup_func = setup_default, \
|
||||
.teardown_func = teardown_unmap, \
|
||||
.initial_state = &(struct ux_locales_test_state) \
|
||||
{ \
|
||||
.name = _name, \
|
||||
.lang_id = _lang_id, \
|
||||
.expect = _expect, \
|
||||
}, \
|
||||
})
|
||||
|
||||
/*
|
||||
* When exporting test results to xml files, cmocka doesn't escape double quotes for test names.
|
||||
* Therefore, double quotes in CMUnitTest.name will lead to invalid xml files, causing build
|
||||
* failure (with JUNIT_OUTPUT=y). As a result, we can only use _expect for CMUnitTest.name in
|
||||
* the macro, but not #_expect.
|
||||
*/
|
||||
#define UX_LOCALES_GET_TEXT_FOUND_TEST(_name, _lang_id, _expect) \
|
||||
(_UX_LOCALES_GET_TEXT_TEST \
|
||||
( \
|
||||
( \
|
||||
"test_ux_locales_get_text_found(name=" _name \
|
||||
", lang_id=" #_lang_id ", expect=" _expect ")" \
|
||||
), \
|
||||
_name, _lang_id, _expect \
|
||||
))
|
||||
|
||||
#define UX_LOCALES_GET_TEXT_NOT_FOUND_TEST(_name, _lang_id) \
|
||||
(_UX_LOCALES_GET_TEXT_TEST \
|
||||
( \
|
||||
( \
|
||||
"test_ux_locales_get_text_not_found(name=" _name \
|
||||
", lang_id=" #_lang_id ")" \
|
||||
), \
|
||||
_name, _lang_id, NULL \
|
||||
))
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
/* Get text successfully. */
|
||||
UX_LOCALES_GET_TEXT_FOUND_TEST("name_1", 0, "translation_1_0"),
|
||||
/* Get text with name and id both in the middle. */
|
||||
UX_LOCALES_GET_TEXT_FOUND_TEST("name_15", 25, "translation_15_25"),
|
||||
/* Ensure we check the whole string of 'name'.
|
||||
('name_2' is the prefix of 'name_20') */
|
||||
UX_LOCALES_GET_TEXT_NOT_FOUND_TEST("name_2", 3),
|
||||
/* Ensure we check the whole string of 'lang_id'.
|
||||
(id:'2' is the prefix of id:'25' in 'name_15') */
|
||||
UX_LOCALES_GET_TEXT_NOT_FOUND_TEST("name_15", 2),
|
||||
/* Ensure we will fallback to 0. */
|
||||
UX_LOCALES_GET_TEXT_FOUND_TEST("name_1", 7, "translation_1_0"),
|
||||
/* Do not search for locale id with unmatched name. */
|
||||
UX_LOCALES_GET_TEXT_NOT_FOUND_TEST("name_15", 8),
|
||||
/* Validity check of lang_id > 100. We will fallback to 0. */
|
||||
UX_LOCALES_GET_TEXT_FOUND_TEST("name_1", 100, "translation_1_0"),
|
||||
/* cbfs not found. */
|
||||
cmocka_unit_test_setup_teardown(test_ux_locales_bad_cbfs, setup_default,
|
||||
teardown_unmap),
|
||||
/* Bad version. */
|
||||
cmocka_unit_test_setup_teardown(test_ux_locales_bad_version, setup_bad_version,
|
||||
teardown_unmap),
|
||||
/* Read multiple times. */
|
||||
cmocka_unit_test_setup_teardown(test_ux_locales_two_calls, setup_default,
|
||||
teardown_unmap),
|
||||
/* Validity check of NULL terminated. */
|
||||
cmocka_unit_test_setup_teardown(test_ux_locales_null_terminated,
|
||||
setup_default, teardown_unmap),
|
||||
};
|
||||
|
||||
return cb_run_group_tests(tests, NULL, NULL);
|
||||
}
|
Loading…
Reference in New Issue