mirror of
https://github.com/linux-msm/qdl.git
synced 2026-10-07 06:29:17 -07:00
test_contents_selectors.c pulls in contents.c via #include, and contents.c calls firehose_alloc_op(). The test target links neither firehose.c nor libqdl_common, so the only reason it linked at all is that at -O2 the compiler drops the (unreachable in this test) call. At -O0 the call survives and the link fails: src/contents.c:899: undefined reference to `firehose_alloc_op' Provide a firehose_alloc_op() stub, like the other contents tests already do, so the test links regardless of optimization level. Closes: https://github.com/linux-msm/qdl/issues/260 Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
433 lines
11 KiB
C
433 lines
11 KiB
C
// SPDX-License-Identifier: BSD-3-Clause
|
|
/*
|
|
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
|
*/
|
|
#define _FILE_OFFSET_BITS 64
|
|
#define _XOPEN_SOURCE 700
|
|
|
|
#include <setjmp.h>
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <cmocka.h>
|
|
|
|
#include "common.h"
|
|
#include "../src/contents.c"
|
|
|
|
bool qdl_debug;
|
|
|
|
void ux_err(const char *fmt, ...)
|
|
{
|
|
(void)fmt;
|
|
}
|
|
|
|
void ux_info(const char *fmt, ...)
|
|
{
|
|
(void)fmt;
|
|
}
|
|
|
|
void ux_debug(const char *fmt, ...)
|
|
{
|
|
(void)fmt;
|
|
}
|
|
|
|
enum qdl_storage_type decode_storage_type(const char *storage)
|
|
{
|
|
if (!strcmp(storage, "emmc"))
|
|
return QDL_STORAGE_EMMC;
|
|
if (!strcmp(storage, "nand"))
|
|
return QDL_STORAGE_NAND;
|
|
if (!strcmp(storage, "ufs"))
|
|
return QDL_STORAGE_UFS;
|
|
if (!strcmp(storage, "nvme"))
|
|
return QDL_STORAGE_NVME;
|
|
if (!strcmp(storage, "spinor"))
|
|
return QDL_STORAGE_SPINOR;
|
|
|
|
return QDL_STORAGE_UNKNOWN;
|
|
}
|
|
|
|
const char *encode_storage_type(enum qdl_storage_type storage)
|
|
{
|
|
switch (storage) {
|
|
case QDL_STORAGE_EMMC:
|
|
return "emmc";
|
|
case QDL_STORAGE_NAND:
|
|
return "nand";
|
|
case QDL_STORAGE_UFS:
|
|
return "ufs";
|
|
case QDL_STORAGE_NVME:
|
|
return "nvme";
|
|
case QDL_STORAGE_SPINOR:
|
|
return "spinor";
|
|
case QDL_STORAGE_UNKNOWN:
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
int load_sahara_image(struct qdl_zip *zip, const char *filename, struct sahara_image *image)
|
|
{
|
|
(void)zip;
|
|
(void)filename;
|
|
(void)image;
|
|
|
|
return -1;
|
|
}
|
|
|
|
void sahara_images_free(struct sahara_image *images, size_t count)
|
|
{
|
|
(void)images;
|
|
(void)count;
|
|
}
|
|
|
|
int decode_sahara_config(struct sahara_image *blob, struct sahara_image *images,
|
|
struct contents_filter *contents_filter)
|
|
{
|
|
(void)blob;
|
|
(void)images;
|
|
(void)contents_filter;
|
|
|
|
return -1;
|
|
}
|
|
|
|
int program_load(struct list_head *ops, const char *program_file, bool is_nand,
|
|
bool allow_missing, struct contents_filter *contents_filter,
|
|
const char *incdir)
|
|
{
|
|
(void)ops;
|
|
(void)program_file;
|
|
(void)is_nand;
|
|
(void)allow_missing;
|
|
(void)contents_filter;
|
|
(void)incdir;
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* contents.c references firehose_alloc_op(), but this test pulls it in via
|
|
* #include and links neither firehose.c nor libqdl_common. Provide a stub so
|
|
* the test links regardless of whether the optimizer drops the unreachable
|
|
* call (it does at -O2 but not at -O0), matching the other contents tests.
|
|
*/
|
|
struct firehose_op *firehose_alloc_op(int type)
|
|
{
|
|
struct firehose_op *op = calloc(1, sizeof(*op));
|
|
|
|
if (!op)
|
|
return NULL;
|
|
|
|
op->type = type;
|
|
return op;
|
|
}
|
|
|
|
int patch_load(struct list_head *ops, const char *patch_file)
|
|
{
|
|
(void)ops;
|
|
(void)patch_file;
|
|
|
|
return -1;
|
|
}
|
|
|
|
struct selector_fixture {
|
|
struct contents contents;
|
|
char *flavors[3];
|
|
};
|
|
|
|
static void add_entry(struct contents *contents, enum contents_file_type file_type,
|
|
enum qdl_storage_type storage_type, const char *flavor)
|
|
{
|
|
struct contents_entry *entry;
|
|
|
|
entry = calloc(1, sizeof(*entry));
|
|
assert_non_null(entry);
|
|
|
|
entry->file_type = file_type;
|
|
entry->storage_type = storage_type;
|
|
entry->flavor = flavor ? strdup(flavor) : NULL;
|
|
assert_true(!flavor || entry->flavor);
|
|
|
|
list_append(&contents->entries, &entry->node);
|
|
}
|
|
|
|
static int setup_single(void **state)
|
|
{
|
|
struct selector_fixture *fixture;
|
|
|
|
fixture = calloc(1, sizeof(*fixture));
|
|
assert_non_null(fixture);
|
|
|
|
fixture->flavors[0] = "flavor_a";
|
|
|
|
list_init(&fixture->contents.entries);
|
|
fixture->contents.flavors = fixture->flavors;
|
|
fixture->contents.num_flavors = 1;
|
|
|
|
add_entry(&fixture->contents, CONTENTS_FILE_PROGRAM, QDL_STORAGE_UFS, "flavor_a");
|
|
add_entry(&fixture->contents, CONTENTS_FILE_PROGRAM, QDL_STORAGE_UFS, NULL);
|
|
add_entry(&fixture->contents, CONTENTS_FILE_PATCH, QDL_STORAGE_UFS, NULL);
|
|
add_entry(&fixture->contents, CONTENTS_FILE_OTHER, QDL_STORAGE_UNKNOWN, "flavor_a");
|
|
|
|
*state = fixture;
|
|
return 0;
|
|
}
|
|
|
|
static int setup_multi(void **state)
|
|
{
|
|
struct selector_fixture *fixture;
|
|
|
|
fixture = calloc(1, sizeof(*fixture));
|
|
assert_non_null(fixture);
|
|
|
|
fixture->flavors[0] = "flavor_a";
|
|
fixture->flavors[1] = "flavor_b";
|
|
fixture->flavors[2] = "flavor_c";
|
|
|
|
list_init(&fixture->contents.entries);
|
|
fixture->contents.flavors = fixture->flavors;
|
|
fixture->contents.num_flavors = 3;
|
|
|
|
add_entry(&fixture->contents, CONTENTS_FILE_PROGRAM, QDL_STORAGE_UFS, "flavor_a");
|
|
add_entry(&fixture->contents, CONTENTS_FILE_PATCH, QDL_STORAGE_UFS, "flavor_a");
|
|
add_entry(&fixture->contents, CONTENTS_FILE_PROGRAM, QDL_STORAGE_SPINOR, "flavor_b");
|
|
add_entry(&fixture->contents, CONTENTS_FILE_PATCH, QDL_STORAGE_SPINOR, "flavor_b");
|
|
add_entry(&fixture->contents, CONTENTS_FILE_PROGRAM, QDL_STORAGE_SPINOR, "flavor_c");
|
|
add_entry(&fixture->contents, CONTENTS_FILE_PATCH, QDL_STORAGE_SPINOR, "flavor_c");
|
|
add_entry(&fixture->contents, CONTENTS_FILE_OTHER, QDL_STORAGE_UNKNOWN, "flavor_a");
|
|
|
|
*state = fixture;
|
|
return 0;
|
|
}
|
|
|
|
static int teardown_fixture(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
struct contents_entry *entry;
|
|
struct contents_entry *next;
|
|
|
|
if (!fixture)
|
|
return 0;
|
|
|
|
list_for_each_entry_safe(entry, next, &fixture->contents.entries, node) {
|
|
list_del(&entry->node);
|
|
free(entry->flavor);
|
|
free(entry);
|
|
}
|
|
|
|
free(fixture);
|
|
return 0;
|
|
}
|
|
|
|
static void assert_selector(struct contents_selector *selector,
|
|
enum qdl_storage_type storage_type, const char *flavor)
|
|
{
|
|
assert_int_equal(selector->storage_type, storage_type);
|
|
assert_string_equal(selector->flavor, flavor);
|
|
}
|
|
|
|
static void assert_decode_success(struct contents *contents, const char *pattern,
|
|
int expected_count,
|
|
const struct contents_selector *expected)
|
|
{
|
|
struct contents_selector *selectors = NULL;
|
|
char *pattern_copy = NULL;
|
|
int ret;
|
|
int i;
|
|
|
|
if (pattern) {
|
|
pattern_copy = strdup(pattern);
|
|
assert_non_null(pattern_copy);
|
|
}
|
|
|
|
ret = contents_decode_selectors(contents, pattern_copy, &selectors);
|
|
assert_int_equal(ret, expected_count);
|
|
assert_non_null(selectors);
|
|
|
|
for (i = 0; i < expected_count; i++)
|
|
assert_selector(&selectors[i], expected[i].storage_type, expected[i].flavor);
|
|
|
|
free(selectors);
|
|
free(pattern_copy);
|
|
}
|
|
|
|
static void assert_decode_failure(struct contents *contents, const char *pattern)
|
|
{
|
|
struct contents_selector *selectors = NULL;
|
|
char *pattern_copy = NULL;
|
|
int ret;
|
|
|
|
if (pattern) {
|
|
pattern_copy = strdup(pattern);
|
|
assert_non_null(pattern_copy);
|
|
}
|
|
|
|
ret = contents_decode_selectors(contents, pattern_copy, &selectors);
|
|
assert_int_equal(ret, -1);
|
|
assert_null(selectors);
|
|
|
|
free(pattern_copy);
|
|
}
|
|
|
|
static void test_single_autoselects_only_combination(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
const struct contents_selector expected[] = {
|
|
{ QDL_STORAGE_UFS, "flavor_a" },
|
|
};
|
|
|
|
assert_decode_success(&fixture->contents, NULL, 1, expected);
|
|
}
|
|
|
|
static void test_single_accepts_storage_shorthand(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
const struct contents_selector expected[] = {
|
|
{ QDL_STORAGE_UFS, "flavor_a" },
|
|
};
|
|
|
|
assert_decode_success(&fixture->contents, "ufs", 1, expected);
|
|
}
|
|
|
|
static void test_single_accepts_flavor_shorthand(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
const struct contents_selector expected[] = {
|
|
{ QDL_STORAGE_UFS, "flavor_a" },
|
|
};
|
|
|
|
assert_decode_success(&fixture->contents, "flavor_a", 1, expected);
|
|
}
|
|
|
|
static void test_multi_requires_explicit_selector(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
|
|
assert_decode_failure(&fixture->contents, NULL);
|
|
}
|
|
|
|
static void test_multi_accepts_full_multi_selector(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
const struct contents_selector expected[] = {
|
|
{ QDL_STORAGE_UFS, "flavor_a" },
|
|
{ QDL_STORAGE_SPINOR, "flavor_b" },
|
|
};
|
|
|
|
assert_decode_success(&fixture->contents,
|
|
"ufs/flavor_a,spinor/flavor_b",
|
|
2, expected);
|
|
}
|
|
|
|
static void test_multi_accepts_storage_shorthand_when_unique(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
const struct contents_selector expected[] = {
|
|
{ QDL_STORAGE_UFS, "flavor_a" },
|
|
};
|
|
|
|
assert_decode_success(&fixture->contents, "ufs", 1, expected);
|
|
}
|
|
|
|
static void test_multi_accepts_flavor_shorthand_when_unique(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
const struct contents_selector expected[] = {
|
|
{ QDL_STORAGE_SPINOR, "flavor_b" },
|
|
};
|
|
|
|
assert_decode_success(&fixture->contents, "flavor_b", 1, expected);
|
|
}
|
|
|
|
static void test_multi_accepts_mixed_shorthand_selector(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
const struct contents_selector expected[] = {
|
|
{ QDL_STORAGE_UFS, "flavor_a" },
|
|
{ QDL_STORAGE_SPINOR, "flavor_b" },
|
|
};
|
|
|
|
assert_decode_success(&fixture->contents, "ufs,spinor/flavor_b", 2, expected);
|
|
}
|
|
|
|
static void test_multi_rejects_ambiguous_storage_shorthand(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
|
|
assert_decode_failure(&fixture->contents, "spinor");
|
|
}
|
|
|
|
static void test_multi_rejects_invalid_combination(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
|
|
assert_decode_failure(&fixture->contents, "ufs/flavor_b");
|
|
}
|
|
|
|
static void test_multi_rejects_duplicate_storage_full_selectors(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
|
|
assert_decode_failure(&fixture->contents, "spinor/flavor_b,spinor/flavor_c");
|
|
}
|
|
|
|
static void test_multi_rejects_duplicate_storage_after_shorthand(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
|
|
assert_decode_failure(&fixture->contents, "flavor_b,spinor/flavor_c");
|
|
}
|
|
|
|
static void test_multi_rejects_unknown_selector(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
|
|
assert_decode_failure(&fixture->contents, "does_not_exist");
|
|
}
|
|
|
|
static void test_multi_rejects_empty_selector(void **state)
|
|
{
|
|
struct selector_fixture *fixture = *state;
|
|
|
|
assert_decode_failure(&fixture->contents, "");
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
const struct CMUnitTest tests[] = {
|
|
cmocka_unit_test_setup_teardown(test_single_autoselects_only_combination,
|
|
setup_single, teardown_fixture),
|
|
cmocka_unit_test_setup_teardown(test_single_accepts_storage_shorthand,
|
|
setup_single, teardown_fixture),
|
|
cmocka_unit_test_setup_teardown(test_single_accepts_flavor_shorthand,
|
|
setup_single, teardown_fixture),
|
|
cmocka_unit_test_setup_teardown(test_multi_requires_explicit_selector,
|
|
setup_multi, teardown_fixture),
|
|
cmocka_unit_test_setup_teardown(test_multi_accepts_full_multi_selector,
|
|
setup_multi, teardown_fixture),
|
|
cmocka_unit_test_setup_teardown(test_multi_accepts_storage_shorthand_when_unique,
|
|
setup_multi, teardown_fixture),
|
|
cmocka_unit_test_setup_teardown(test_multi_accepts_flavor_shorthand_when_unique,
|
|
setup_multi, teardown_fixture),
|
|
cmocka_unit_test_setup_teardown(test_multi_accepts_mixed_shorthand_selector,
|
|
setup_multi, teardown_fixture),
|
|
cmocka_unit_test_setup_teardown(test_multi_rejects_ambiguous_storage_shorthand,
|
|
setup_multi, teardown_fixture),
|
|
cmocka_unit_test_setup_teardown(test_multi_rejects_invalid_combination,
|
|
setup_multi, teardown_fixture),
|
|
cmocka_unit_test_setup_teardown(test_multi_rejects_duplicate_storage_full_selectors,
|
|
setup_multi, teardown_fixture),
|
|
cmocka_unit_test_setup_teardown(test_multi_rejects_duplicate_storage_after_shorthand,
|
|
setup_multi, teardown_fixture),
|
|
cmocka_unit_test_setup_teardown(test_multi_rejects_unknown_selector,
|
|
setup_multi, teardown_fixture),
|
|
cmocka_unit_test_setup_teardown(test_multi_rejects_empty_selector,
|
|
setup_multi, teardown_fixture),
|
|
};
|
|
|
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
|
}
|