summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authortaeyoung <ty317.kim@samsung.com>2016-09-23 19:46:01 +0900
committertaeyoung <ty317.kim@samsung.com>2016-09-23 19:46:39 +0900
commitaf80c789ed18bffe59ff815f0fddabbda56b9442 (patch)
tree2edbc50a8a91662cd022f9b5c5d0693f6a8b4071 /tests
parent6521a52d94e2a43f69ca856bf921b0362c910e21 (diff)
downloadlibusbg-af80c789ed18bffe59ff815f0fddabbda56b9442.tar.gz
libusbg-af80c789ed18bffe59ff815f0fddabbda56b9442.tar.bz2
libusbg-af80c789ed18bffe59ff815f0fddabbda56b9442.zip
Imported Upstream version 0.0.1
Change-Id: I7f9821384b1c58f400c5e4935edb8b89f30d503e
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.am14
-rw-r--r--tests/test.c2697
-rwxr-xr-xtests/test.sh78
-rw-r--r--tests/usbg-io-wrappers.c203
-rw-r--r--tests/usbg-test.c1389
-rw-r--r--tests/usbg-test.h549
6 files changed, 4930 insertions, 0 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..01feea4
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,14 @@
+check_PROGRAMS = test
+test_SOURCES = test.c usbg-test.c usbg-io-wrappers.c
+test_LDFLAGS = -ldl
+test_LDFLAGS += $(CMOCKA_LIBS)
+test_LDFLAGS += $(LIBCONFIG_LIBS)
+test_LDADD = ./libusbgx.so
+test_CPPFLAGS = -I$(top_srcdir)/include/
+
+./libusbgx.so:
+ -ln -s $(top_srcdir)/src/.libs/libusbgx.so* .
+CLEANFILES = libusbgx.so*
+
+check_SCRIPTS = ./test.sh
+TESTS = $(check_SCRIPTS)
diff --git a/tests/test.c b/tests/test.c
new file mode 100644
index 0000000..bd17af9
--- /dev/null
+++ b/tests/test.c
@@ -0,0 +1,2697 @@
+#include <usbg/usbg.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <time.h>
+
+#ifdef HAS_LIBCONFIG
+#include <libconfig.h>
+#endif
+
+#include "usbg-test.h"
+
+/**
+ * @file tests/test.c
+ */
+
+#define USBG_TEST(name, test, setup, teardown) \
+ {name, test, setup, teardown}
+
+#define FILLED_STR(len, c) \
+ { [0 ... len - 2] = c, [len - 1] = '\0' }
+
+/* two levels of macros allow to strigify result of macro expansion */
+#define STR(s) #s
+#define XSTR(s) STR(s)
+/* unique string */
+#define UNIQUE XSTR(__COUNTER__)
+
+#define FUNC_FROM_TYPE(t) { \
+ .type = t, \
+ .instance = "instance"UNIQUE \
+}
+
+#define CONF_FROM_BOUND(b) { \
+ .label = "c", \
+ .id = __COUNTER__, \
+ .bound_funcs = b \
+}
+
+static usbg_gadget_attrs min_gadget_attrs = {
+ .bcdUSB = 0x0000,
+ .bDeviceClass = 0x0,
+ .bDeviceSubClass = 0x0,
+ .bDeviceProtocol = 0x0,
+ .bMaxPacketSize0 = 0x0,
+ .idVendor = 0x0000,
+ .idProduct = 0x0000,
+ .bcdDevice = 0x0000
+};
+
+static usbg_gadget_attrs max_gadget_attrs = {
+ .bcdUSB = 0xffff,
+ .bDeviceClass = 0xff,
+ .bDeviceSubClass = 0xff,
+ .bDeviceProtocol = 0xff,
+ .bMaxPacketSize0 = 0xff,
+ .idVendor = 0xffff,
+ .idProduct = 0xffff,
+ .bcdDevice = 0xffff
+};
+
+/* PATH_MAX is limit for path length */
+#define LONG_PATH_LEN PATH_MAX/2
+static char long_path_str[] = FILLED_STR(LONG_PATH_LEN, 'x');
+
+/* NAME_MAX is limit for filename length */
+static char long_usbg_string[] = FILLED_STR(NAME_MAX, 'x');
+
+static usbg_config_strs simple_config_strs= {
+ .configuration = "configuration string"
+};
+
+static usbg_config_attrs max_config_attrs = {
+ .bmAttributes = 0xff,
+ .bMaxPower = 0xff
+};
+
+static usbg_config_attrs min_config_attrs = {
+ .bmAttributes = 0x00,
+ .bMaxPower = 0x00
+};
+
+/**
+ * @brief Simplest udcs names
+ * @details Used to go through init when testing other things
+ */
+static char *simple_udcs[] = {
+ "UDC1",
+ "UDC2",
+ NULL
+};
+
+static char *long_udcs[] = {
+ long_usbg_string,
+ "UDC1",
+ NULL
+};
+
+/**
+ * @brief Simplest functions names
+ * @details Used to go through init when testing other things
+ */
+static struct test_function simple_funcs[] = {
+ FUNC_FROM_TYPE(F_ECM),
+ FUNC_FROM_TYPE(F_ACM),
+ TEST_FUNCTION_LIST_END
+};
+
+/**
+ * @brief All functions types
+ * @details When testing with this in state, check if all func types are
+ * processed correctly
+ */
+static struct test_function all_funcs[] = {
+ FUNC_FROM_TYPE(F_SERIAL),
+ FUNC_FROM_TYPE(F_ACM),
+ FUNC_FROM_TYPE(F_OBEX),
+ FUNC_FROM_TYPE(F_ECM),
+ FUNC_FROM_TYPE(F_SUBSET),
+ FUNC_FROM_TYPE(F_NCM),
+ FUNC_FROM_TYPE(F_EEM),
+ FUNC_FROM_TYPE(F_RNDIS),
+ FUNC_FROM_TYPE(F_PHONET),
+ FUNC_FROM_TYPE(F_FFS),
+ TEST_FUNCTION_LIST_END
+};
+
+static struct test_function same_type_funcs[] = {
+ FUNC_FROM_TYPE(F_SERIAL),
+ FUNC_FROM_TYPE(F_SERIAL),
+ FUNC_FROM_TYPE(F_SERIAL),
+ TEST_FUNCTION_LIST_END
+};
+
+/**
+ * @brief No functions at all
+ * @details Check if gadget with no functions (or config with no bindings)
+ * is processed correctly.
+ */
+static struct test_function no_funcs[] = {
+ TEST_FUNCTION_LIST_END
+};
+
+/**
+ * @brief Simple configs
+ * @details Used to pass through init when testing other things
+ */
+static struct test_config simple_confs[] = {
+ CONF_FROM_BOUND(simple_funcs),
+ TEST_CONFIG_LIST_END
+};
+
+/**
+ * @brief Configs bound to all avaible function types
+ */
+static struct test_config all_bindings_confs[] = {
+ CONF_FROM_BOUND(no_funcs),
+ CONF_FROM_BOUND(all_funcs),
+ TEST_CONFIG_LIST_END
+};
+
+#define GADGET(n, u, c, f) \
+ { \
+ .name = n, \
+ .udc = u, \
+ .configs = c, \
+ .functions = f \
+ }
+
+/**
+ * @brief Simplest gadget
+ */
+static struct test_gadget simple_gadgets[] = {
+ GADGET("g1", "UDC1", simple_confs, simple_funcs),
+ TEST_GADGET_LIST_END
+};
+
+/**
+ * @brief Gadgets with all avaible functions
+ */
+static struct test_gadget all_funcs_gadgets[] = {
+ GADGET("all_funcs_gadget1", "UDC1", all_bindings_confs, all_funcs),
+ TEST_GADGET_LIST_END
+};
+
+static struct test_gadget long_udc_gadgets[] = {
+ GADGET("long_udc_gadgets", long_usbg_string, simple_confs, simple_funcs),
+ TEST_GADGET_LIST_END
+};
+
+struct test_function_attrs_data {
+ struct test_state *state;
+ usbg_function_attrs *attrs;
+};
+struct test_data {
+ struct test_state *state;
+ struct usbg_state *usbg_state;
+};
+
+#define FUNC_ATTRS(t, label, a...) { \
+ .header = { \
+ .attrs_type = t \
+ }, \
+ .attrs = { \
+ .label = { a } \
+ }, \
+}
+
+static usbg_function_attrs simple_serial_attrs = FUNC_ATTRS(USBG_F_ATTRS_SERIAL, serial, 42);
+static usbg_function_attrs simple_net_attrs = FUNC_ATTRS(USBG_F_ATTRS_NET, net, {}, {}, "if", 1);
+static usbg_function_attrs simple_phonet_attrs = FUNC_ATTRS(USBG_F_ATTRS_PHONET, phonet, "if");
+static usbg_function_attrs writable_serial_attrs = FUNC_ATTRS(USBG_F_ATTRS_SERIAL, serial, 0);
+static usbg_function_attrs writable_net_attrs = FUNC_ATTRS(USBG_F_ATTRS_NET, net, {}, {}, "", 42);
+static usbg_function_attrs writable_phonet_attrs = FUNC_ATTRS(USBG_F_ATTRS_PHONET, phonet, "");
+static usbg_function_attrs simple_ffs_attrs = FUNC_ATTRS(USBG_F_ATTRS_FFS, ffs, "0");
+static usbg_function_attrs writable_ffs_attrs = FUNC_ATTRS(USBG_F_ATTRS_FFS, ffs, "");
+
+struct test_gadget_strs_data {
+ struct test_state *state;
+ usbg_gadget_strs *strs;
+};
+
+#define STATE(p, g, u) { \
+ .configfs_path = p, \
+ .gadgets = g, \
+ .udcs = u \
+}
+
+/**
+ * @brief Simple state
+ */
+static struct test_state simple_state = STATE("config", simple_gadgets, simple_udcs);
+
+/**
+ * @brief State with all functions avaible
+ */
+static struct test_state all_funcs_state = STATE("all_funcs_configfs", all_funcs_gadgets, simple_udcs);
+
+static struct test_state long_path_state = STATE(long_path_str, simple_gadgets, simple_udcs);
+
+static struct test_state long_udc_state = STATE("simple_path", long_udc_gadgets, long_udcs);
+
+static usbg_config_attrs *get_random_config_attrs()
+{
+ usbg_config_attrs *ret;
+
+ ret = safe_malloc(sizeof(*ret));
+
+ srand(time(NULL));
+ ret->bmAttributes = rand() % max_config_attrs.bmAttributes;
+ ret->bMaxPower = rand() % max_config_attrs.bMaxPower;
+
+ return ret;
+}
+
+static usbg_gadget_attrs *get_random_gadget_attrs()
+{
+ usbg_gadget_attrs *ret;
+
+ ret = safe_malloc(sizeof(*ret));
+
+ srand(time(NULL));
+ ret->bcdUSB = rand() % max_gadget_attrs.bcdUSB;
+ ret->bDeviceClass = rand() % max_gadget_attrs.bDeviceClass;
+ ret->bDeviceSubClass = rand() % max_gadget_attrs.bDeviceSubClass;
+ ret->bDeviceProtocol = rand() % max_gadget_attrs.bDeviceProtocol;
+ ret->bMaxPacketSize0 = rand() % max_gadget_attrs.bMaxPacketSize0;
+ ret->idVendor = rand() % max_gadget_attrs.idVendor;
+ ret->idProduct = rand() % max_gadget_attrs.idProduct;
+ ret->bcdDevice = rand() % max_gadget_attrs.bcdDevice;
+
+ return ret;
+}
+
+/**
+ * @brief Add given attributes to all configs in state
+ * @return Prepared state where configs has given attributes
+ */
+static void *prepare_state_with_config_attrs(struct test_state *state,
+ usbg_config_attrs *attrs)
+{
+ struct test_gadget *tg;
+ struct test_config *tc;
+
+ for (tg = state->gadgets; tg->name; ++tg)
+ for (tc = tg->configs; tc->label; ++tc)
+ tc->attrs = attrs;
+
+ state = prepare_state(state);
+ return state;
+}
+
+static int setup_max_config_attrs_state(void **state)
+{
+ *state = prepare_state_with_config_attrs(&simple_state, &max_config_attrs);
+ return 0;
+}
+
+static int setup_min_config_attrs_state(void **state)
+{
+ *state = prepare_state_with_config_attrs(&simple_state, &min_config_attrs);
+ return 0;
+}
+
+static int setup_random_config_attrs_state(void **state)
+{
+ *state = prepare_state_with_config_attrs(&simple_state, get_random_config_attrs());
+ return 0;
+}
+
+static int setup_simple_config_strs_state(void **state)
+{
+ struct test_gadget *tg;
+ struct test_config *tc;
+
+ for (tg = simple_state.gadgets; tg->name; ++tg)
+ for (tc = tg->configs; tc->label; ++tc)
+ tc->strs = &simple_config_strs;
+
+ *state = prepare_state(&simple_state);
+ return 0;
+}
+
+/**
+ * @brief Prepare test_state with one gadget containing given function list
+ * @details For testing only functions. We put them in a gadget as simply
+ * as possible.
+ * @param[in] func Pointer to list of functions
+ * @return Pointer to test state with given functions
+ */
+static struct test_state *put_func_in_state(struct test_function *func)
+{
+ struct test_state *st;
+ struct test_gadget *g;
+ struct test_config *c;
+ char **udcs;
+
+ st = safe_calloc(1, sizeof(*st));
+ /* Do not need config */
+ c = safe_calloc(1, sizeof(*c));
+ g = safe_calloc(2, sizeof(*g));
+ udcs = safe_calloc(2, sizeof(*udcs));
+
+ g[0].name = "g1";
+ g[0].udc = "UDC1";
+ g[0].configs = c;
+ g[0].functions = func;
+ g[0].writable = 1;
+
+ udcs[0] = "UDC1";
+ g[0].writable = 1;
+
+ st->configfs_path = "config";
+ st->gadgets = g;
+ st->udcs = udcs;
+ st->writable = 1;
+
+ st = prepare_state(st);
+
+ return st;
+}
+
+/**
+ * @brief Setup simple state with some gadgets, configs and functions
+ */
+static int setup_simple_state(void **state)
+{
+ *state = prepare_state(&simple_state);
+ return 0;
+}
+
+/**
+ * @brief Setup state with all avaible functions
+ */
+static int setup_all_funcs_state(void **state)
+{
+ *state = prepare_state(&all_funcs_state);
+ return 0;
+}
+
+/**
+ * @brief Setup state with few functions of the same type
+ */
+static int setup_same_type_funcs_state(void **state)
+{
+ *state = put_func_in_state(same_type_funcs);
+ return 0;
+}
+
+/**
+ * @brief Setup state with very long path name
+ */
+static int setup_long_path_state(void **state)
+{
+ *state = prepare_state(&long_path_state);
+ return 0;
+}
+
+/**
+ * @brief Setup state with long udc name
+ */
+static int setup_long_udc_state(void **state)
+{
+ *state = prepare_state(&long_udc_state);
+ return 0;
+}
+
+/**
+ * @brief Setup state with gadget strings of random length
+ * @param[out] state Pointer to pointer to test_gadget_strs_data structure
+ * with initialized state and strings
+ */
+static int setup_random_len_gadget_strs_data(void **state)
+{
+ usbg_gadget_strs *strs;
+ struct test_gadget_strs_data *data;
+
+ /* will fill memory with zeros */
+ strs = safe_calloc(1, sizeof(*strs));
+ data = safe_malloc(sizeof(*data));
+
+ srand(time(NULL));
+
+ memset(strs->str_ser, 'x', rand() % USBG_MAX_STR_LENGTH);
+ memset(strs->str_mnf, 'x', rand() % USBG_MAX_STR_LENGTH);
+ memset(strs->str_prd, 'x', rand() % USBG_MAX_STR_LENGTH);
+
+ data->strs = strs;
+
+ data->state = prepare_state(&simple_state);
+ *state = data;
+ return 0;
+}
+
+static void *setup_f_attrs(int f_type, usbg_function_attrs *attrs)
+{
+ struct test_function_attrs_data *data;
+ struct test_function *func;
+
+ data = safe_malloc(sizeof(*data));
+
+ func = safe_calloc(2, sizeof(*func));
+ func[0].type = f_type;
+ func[0].instance = "0";
+ func[0].writable = 1;
+
+ data->state = put_func_in_state(func);
+ data->attrs = attrs;
+ return data;
+}
+
+static int setup_f_serial_attrs(void **state)
+{
+ *state = setup_f_attrs(F_SERIAL, &simple_serial_attrs);
+ return 0;
+}
+
+static int setup_f_serial_writable_attrs(void **state)
+{
+ *state = setup_f_attrs(F_SERIAL, &writable_serial_attrs);
+ return 0;
+}
+
+static int setup_f_acm_attrs(void **state)
+{
+ *state = setup_f_attrs(F_ACM, &simple_serial_attrs);
+ return 0;
+}
+
+static int setup_f_acm_writable_attrs(void **state)
+{
+ *state = setup_f_attrs(F_ACM, &writable_serial_attrs);
+ return 0;
+}
+
+static int setup_f_obex_attrs(void **state)
+{
+ *state = setup_f_attrs(F_OBEX, &simple_serial_attrs);
+ return 0;
+}
+
+static int setup_f_obex_writable_attrs(void **state)
+{
+ *state = setup_f_attrs(F_OBEX, &writable_serial_attrs);
+ return 0;
+}
+
+static int setup_f_ecm_attrs(void **state)
+{
+ *state = setup_f_attrs(F_ECM, &simple_net_attrs);
+ return 0;
+}
+
+static int setup_f_ecm_writable_attrs(void **state)
+{
+ *state = setup_f_attrs(F_ECM, &writable_net_attrs);
+ return 0;
+}
+
+static int setup_f_subset_attrs(void **state)
+{
+ *state = setup_f_attrs(F_SUBSET, &simple_net_attrs);
+ return 0;
+}
+
+static int setup_f_subset_writable_attrs(void **state)
+{
+ *state = setup_f_attrs(F_SUBSET, &writable_net_attrs);
+ return 0;
+}
+
+static int setup_f_ncm_attrs(void **state)
+{
+ *state = setup_f_attrs(F_NCM, &simple_net_attrs);
+ return 0;
+}
+
+static int setup_f_ncm_writable_attrs(void **state)
+{
+ *state = setup_f_attrs(F_NCM, &writable_net_attrs);
+ return 0;
+}
+
+static int setup_f_eem_attrs(void **state)
+{
+ *state = setup_f_attrs(F_EEM, &simple_net_attrs);
+ return 0;
+}
+
+static int setup_f_eem_writable_attrs(void **state)
+{
+ *state = setup_f_attrs(F_EEM, &writable_net_attrs);
+ return 0;
+}
+
+static int setup_f_rndis_attrs(void **state)
+{
+ *state = setup_f_attrs(F_RNDIS, &simple_net_attrs);
+ return 0;
+}
+
+static int setup_f_rndis_writable_attrs(void **state)
+{
+ *state = setup_f_attrs(F_RNDIS, &writable_net_attrs);
+ return 0;
+}
+
+static int setup_f_phonet_attrs(void **state)
+{
+ *state = setup_f_attrs(F_PHONET, &simple_phonet_attrs);
+ return 0;
+}
+
+static int setup_f_phonet_writable_attrs(void **state)
+{
+ *state = setup_f_attrs(F_PHONET, &writable_phonet_attrs);
+ return 0;
+}
+
+static int setup_f_ffs_attrs(void **state)
+{
+ *state = setup_f_attrs(F_FFS, &simple_ffs_attrs);
+ return 0;
+}
+
+static int setup_f_ffs_writable_attrs(void **state)
+{
+ *state = setup_f_attrs(F_FFS, &writable_ffs_attrs);
+ return 0;
+}
+
+/**
+ * @brief Tests usbg_get_gadget function with given state
+ * @details Check if gadgets are returned correctly
+ */
+static void test_get_gadget(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_gadget(ts, s, assert_gadget_equal);
+}
+
+/**
+ * @brief Tests usbg_get_gadget with non-existing gadget name
+ * @details Check if get_gadget will not find non-existing gadgets and
+ * will not cause crash.
+ */
+static void test_get_gadget_fail(void **state)
+{
+ usbg_gadget *g = NULL;
+ usbg_state *s = NULL;
+ struct test_state *st;
+
+ safe_init_with_state(state, &st, &s);
+
+ g = usbg_get_gadget(s, "non-existing-gadget");
+ assert_null(g);
+}
+
+/**
+ * @brief Tests usbg_get_first_gadget function
+ * @details Check if gadget returned by get_first_gadget is actually first one
+ */
+static void test_get_first_gadget(void **state)
+{
+ usbg_gadget *g = NULL;
+ usbg_state *s = NULL;
+ struct test_state *st;
+
+ safe_init_with_state(state, &st, &s);
+
+ g = usbg_get_first_gadget(s);
+ assert_non_null(g);
+ assert_gadget_equal(g, &st->gadgets[0]);
+}
+
+/**
+ * @brief Tests get_first_gadget with invalid arguments
+ */
+static void test_get_first_gadget_fail(void **state)
+{
+ usbg_gadget *g;
+
+ g = usbg_get_first_gadget(NULL);
+ assert_null(g);
+}
+
+static void try_get_gadget_name(usbg_gadget *g, struct test_gadget *tg)
+{
+ const char *name;
+
+ name = usbg_get_gadget_name(g);
+ assert_string_equal(name, tg->name);
+}
+
+/**
+ * @brief Tests getting name of gadget
+ * @details Check if gadget name is returned correctly
+ */
+static void test_get_gadget_name(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_gadget(ts, s, try_get_gadget_name);
+}
+
+static void try_get_gadget_name_len(usbg_gadget *g, struct test_gadget *tg)
+{
+ int len;
+ int expected;
+
+ expected = strlen(tg->name);
+ len = usbg_get_gadget_name_len(g);
+ assert_int_equal(len, expected);
+}
+
+/**
+ * @brief Tests getting name length of gadget
+ * @details Check if returned name length is equal original
+ */
+static void test_get_gadget_name_len(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_gadget(ts, s, try_get_gadget_name_len);
+}
+
+/**
+ * @brief Tests getting name of gadget with invalid arguments
+ * @details Check if trying to get name of wrong (non-existing) gadget
+ * will not cause crash, but return NULL as expected.
+ */
+static void test_get_gadget_name_fail(void **state)
+{
+ const char *name;
+
+ name = usbg_get_gadget_name(NULL);
+ assert_null(name);
+}
+
+static void try_cpy_gadget_name(usbg_gadget *g, struct test_gadget *tg)
+{
+ char name[USBG_MAX_NAME_LENGTH];
+ int ret;
+
+ ret = usbg_cpy_gadget_name(g, name, USBG_MAX_NAME_LENGTH);
+ assert_int_equal(ret, USBG_SUCCESS);
+ assert_string_equal(name, tg->name);
+}
+
+/**
+ * @brief Tests copying gadget's name
+ * @details Check if copying gadget name copy actual name correctly
+ */
+static void test_cpy_gadget_name(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_gadget(ts, s, try_cpy_gadget_name);
+}
+
+/**
+ * @brief Test copying gadet name with invalid arguments
+ * @details Check if trying to copy gadget name into non-existing buffer,
+ * or give invalid buffer length, or invalid gadget will be handled by library
+ * and return correct error codes
+ */
+static void test_cpy_gadget_name_fail(void **state)
+{
+ usbg_gadget *g = NULL;
+ usbg_state *s = NULL;
+ struct test_state *st;
+ int i = 0;
+ char name[USBG_MAX_NAME_LENGTH];
+ int ret;
+
+ safe_init_with_state(state, &st, &s);
+
+ for (i = 0; st->gadgets[i].name; i++) {
+ g = usbg_get_gadget(s, st->gadgets[i].name);
+ assert_non_null(g);
+
+ ret = usbg_cpy_gadget_name(g, name, 0);
+ assert_int_equal(ret, USBG_ERROR_INVALID_PARAM);
+
+ ret = usbg_cpy_gadget_name(g, NULL, USBG_MAX_NAME_LENGTH);
+ assert_int_equal(ret, USBG_ERROR_INVALID_PARAM);
+ }
+
+ ret = usbg_cpy_gadget_name(NULL, name, USBG_MAX_NAME_LENGTH);
+ assert_int_equal(ret, USBG_ERROR_INVALID_PARAM);
+}
+
+/**
+ * @brief Tests init by comparing test state and usbg state
+ * @details Check if usbg state after init match given state and
+ * if init returned success code
+ */
+static void test_init(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *st;
+
+ safe_init_with_state(state, &st, &s);
+
+ assert_state_equal(s, st);
+}
+
+/**
+ * @brief Test getting function by name
+ * @param[in] state Pointer to pointer to correctly initialized test_state structure
+ */
+static void test_get_function(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_function(ts, s, assert_func_equal);
+}
+
+/**
+ * @brief Tests usbg_get_function with some non-existing functions
+ * @details Check if get function will return NULL, when invalid
+ * functions names and types are passed as arguments and will not cause crash.
+ * @param[in] state Pointer to pointer to correctly initialized test_state structure
+ */
+static void test_get_function_fail(void **state)
+{
+ usbg_state *s = NULL;
+ usbg_gadget *g = NULL;
+ usbg_function *f = NULL;
+ struct test_state *st;
+
+ safe_init_with_state(state, &st, &s);
+
+ g = usbg_get_first_gadget(s);
+ assert_non_null(g);
+
+ f = usbg_get_function(g, F_ACM, "non-existing-instance");
+ assert_null(f);
+
+ f = usbg_get_function(g, 9001, "0");
+ assert_null(f);
+}
+
+
+/**
+ * @brief Tests function type translation to string
+ * @param[in] state Pointer to pointer to correctly initialized test_state structure
+ * @details Check if get_function_type_str returns proper strings for all types.
+ */
+static void test_get_function_type_str(void **state)
+{
+ struct {
+ usbg_function_type type;
+ const char *str;
+ } types[] = {
+ {F_SERIAL, "gser"},
+ {F_ACM, "acm"},
+ {F_OBEX, "obex"},
+ {F_ECM, "ecm"},
+ {F_SUBSET, "geth"},
+ {F_NCM, "ncm"},
+ {F_EEM, "eem"},
+ {F_RNDIS, "rndis"},
+ {F_PHONET, "phonet"},
+ {F_FFS, "ffs"},
+ };
+
+ const char *str;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(types); i++) {
+ str = usbg_get_function_type_str(types[i].type);
+ assert_non_null(str);
+ assert_string_equal(str, types[i].str);
+ }
+}
+
+static struct {
+ usbg_gadget_str code;
+ const char *name;
+} gadget_str_names[] = {
+ {STR_PRODUCT, "product"},
+ {STR_MANUFACTURER, "manufacturer"},
+ {STR_SERIAL_NUMBER, "serialnumber"},
+};
+
+/**
+ * @brief Tests gadget codeing name getting
+ * @param[in] state Pointer to pointer to correctly initialized test_state codeucture
+ * @details Check if usbg_get_gadget_code_name returns proper codeings for all types.
+ */
+static void test_get_gadget_str_name(void **state)
+{
+ const char *name;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(gadget_str_names); i++) {
+ name = usbg_get_gadget_str_name(gadget_str_names[i].code);
+ assert_non_null(name);
+ assert_string_equal(name, gadget_str_names[i].name);
+ }
+}
+
+/**
+ * @brief Tests gadget codeing code getting by its name
+ * @param[in] state Pointer to pointer to correctly initialized test_state codeucture
+ * @details Check if usbg_lookup_gadget_code returns values matching codeings
+ */
+static void test_lookup_gadget_str(void **state)
+{
+ int i, code;
+
+ for (i = 0; i < ARRAY_SIZE(gadget_str_names); i++) {
+ code = usbg_lookup_gadget_str(gadget_str_names[i].name);
+ assert_return_code(code, 0);
+ assert_int_equal(code, gadget_str_names[i].code);
+ }
+}
+
+/**
+ * @brief Tests function type translation to string with unknown funcs
+ * @param[in] state Not used parameter
+ * @details Check if get_function_type_str returns NULL, when given
+ * function type is unknown.
+ */
+static void test_get_function_type_str_fail(void **state)
+{
+ const char *str;
+
+ str = usbg_get_function_type_str(-1);
+ assert_null(str);
+}
+
+/**
+ * @brief Get instance of given function and check it
+ * @param[in] f Usbg function
+ * @param[in] tf Test function which should match f
+ */
+static void try_get_function_instance(usbg_function *f, struct test_function *tf)
+{
+ const char *str;
+
+ str = usbg_get_function_instance(f);
+ assert_string_equal(str, tf->instance);
+}
+
+/**
+ * @brief Tests getting function instance from usbg_function structure
+ * @param[in] state Pointer to pointer to correctly initialized test_state structure
+ * @details Check if returned instance name is correct.
+ */
+static void test_get_function_instance(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_function(ts, s, try_get_function_instance);
+}
+
+/**
+ * @brief Cpy instance of given usbg function and check it
+ * @param[in] f Usbg function
+ * @param[in] tf Test function which should match f
+ */
+static void try_cpy_function_instance(usbg_function *f, struct test_function *tf)
+{
+ char str[USBG_MAX_NAME_LENGTH];
+ int ret;
+ int small_len = 2;
+
+ ret = usbg_cpy_function_instance(f, str, USBG_MAX_NAME_LENGTH);
+ assert_int_equal(ret, USBG_SUCCESS);
+ assert_string_equal(str, tf->instance);
+
+ ret = usbg_cpy_function_instance(f, str, small_len);
+ assert_int_equal(ret, USBG_SUCCESS);
+ assert_memory_equal(str, tf->instance, small_len - 1);
+ assert_int_equal(str[small_len - 1], '\0');
+}
+
+/**
+ * @brief Tests copying function instance from usbg_function structure into buffer
+ * @param[in] state Pointer to pointer to correctly initialized state
+ * @details Check if buffer contains expected string
+ */
+static void test_cpy_function_instance(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_function(ts, s, try_cpy_function_instance);
+}
+
+/**
+ * @brief Get function type and check it
+ * @param[in] f Usbg function
+ * @param[in] tf Test function which should match f by type
+ */
+static void try_get_function_type(usbg_function *f, struct test_function *tf)
+{
+ usbg_function_type type;
+
+ type = usbg_get_function_type(f);
+ assert_int_equal(type, tf->type);
+}
+
+/**
+ * @brief Tests getting function type
+ * @details Check if getting function type returns what was expected.
+ * State must be proper (init must end with success).
+ * @param[in] state Pointer to pointer to correctly initialized state
+ */
+static void test_get_function_type(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_function(ts, s, try_get_function_type);
+}
+
+/**
+ * @brief Check if function instance length is correct
+ * @param[in] f Usbg function
+ * @param[in] tf Test function which should match f
+ */
+static void try_get_function_instance_len(usbg_function *f, struct test_function *tf)
+{
+ size_t len;
+ len = usbg_get_function_instance_len(f);
+ assert_int_equal(len, strlen(tf->instance));
+}
+
+/**
+ * @brief Tests getting length of function instance name
+ * @details Check if returned instance name length matches
+ * actual length of instance name
+ * @param[in] state Pointer to pointer to correctly initialized state
+ */
+static void test_get_function_instance_len(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_function(ts, s, try_get_function_instance_len);
+}
+
+/**
+ * @brief Tests getting configfs path from usbg state
+ * @param[in,out] state Pointer to pointer to correctly initialized test state.
+ * When finished, it contains pointer to usbg_state which should be cleaned.
+ */
+static void test_get_configfs_path(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *st;
+ const char *path;
+
+ safe_init_with_state(state, &st, &s);
+
+ path = usbg_get_configfs_path(s);
+ assert_path_equal(path, st->configfs_path);
+}
+
+/**
+ * @brief Tests getting configfs path length from usbg state
+ * @param[in,out] state Pointer to pointer to correctly initialized test state.
+ * When finished, it contains pointer to usbg_state which should be cleaned.
+ */
+static void test_get_configfs_path_len(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *st;
+ int ret, len;
+
+ safe_init_with_state(state, &st, &s);
+
+ ret = usbg_get_configfs_path_len(s);
+ len = strlen(st->configfs_path);
+ assert_int_equal(ret, len);
+}
+
+/**
+ * @brief Tests copying configfs path into buffer
+ * @param[in,out] state Pointer to pointer to correctly initialized test state.
+ * When finished, it contains pointer to usbg_state which should be cleaned.
+ */
+static void test_cpy_configfs_path(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *st;
+ char path[PATH_MAX];
+ int ret;
+
+ safe_init_with_state(state, &st, &s);
+
+ ret = usbg_cpy_configfs_path(s, path, PATH_MAX);
+ assert_int_equal(ret, USBG_SUCCESS);
+ assert_path_equal(path, st->configfs_path);
+}
+
+/**
+ * @brief Tests getting config by name
+ * @param[in,out] state Pointer to pointer to correctly initialized test state.
+ * When finished, it contains pointer to usbg_state which should be cleaned.
+ */
+static void test_get_config(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_config(ts, s, assert_config_equal);
+}
+
+static void test_get_config_without_label(void **state)
+{
+ usbg_state *s = NULL;
+ usbg_gadget *g = NULL;
+ usbg_config *c = NULL;
+ struct test_state *ts;
+ struct test_gadget *tg;
+ struct test_config *tc;
+
+ safe_init_with_state(state, &ts, &s);
+
+ for (tg = ts->gadgets; tg->name; tg++) {
+ g = usbg_get_gadget(s, tg->name);
+ assert_non_null(g);
+ for (tc = tg->configs; tc->label; tc++) {
+ c = usbg_get_config(g, tc->id, NULL);
+ assert_non_null(c);
+ assert_config_equal(c, tc);
+ }
+ }
+}
+
+/**
+ * @bried Tests getting non-existing config
+ * @param[in,out] state Pointer to pointer to correctly initialized test state.
+ * When finished, it contains pointer to usbg_state which should be cleaned.
+ */
+static void test_get_config_fail(void **state)
+{
+ usbg_state *s = NULL;
+ usbg_gadget *g = NULL;
+ usbg_config *c = NULL;
+ struct test_state *ts;
+ struct test_gadget *tg;
+
+ safe_init_with_state(state, &ts, &s);
+
+ for (tg = ts->gadgets; tg->name; tg++) {
+ g = usbg_get_gadget(s, tg->name);
+ assert_non_null(g);
+
+ c = usbg_get_config(g, 0, "non-existing-config");
+ assert_null(c);
+
+ c = usbg_get_config(g, -9001, "c");
+ assert_null(c);
+
+ c = usbg_get_config(g, -9001, NULL);
+ assert_null(c);
+ }
+}
+
+/**
+ * @brief Get config label and check it
+ * @param[in] c Usbg config
+ * @param[in] tc Test config which should match c
+ */
+static void try_get_config_label(usbg_config *c, struct test_config *tc)
+{
+ const char *label;
+ label = usbg_get_config_label(c);
+ assert_string_equal(label, tc->label);
+}
+
+/**
+ * @brief Tests getting config label
+ * @param[in,out] state Pointer to pointer to correctly initialized test state.
+ * When finished, it contains pointer to usbg_state which should be cleaned.
+ */
+static void test_get_config_label(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_config(ts, s, try_get_config_label);
+}
+
+/**
+ * @brief Check config id with test structure
+ * @param[in] c Usbg config
+ * @param[in] tc Test config which should match c
+ */
+static void try_get_config_id(usbg_config *c, struct test_config *tc)
+{
+ int id;
+ id = usbg_get_config_id(c);
+ assert_int_equal(id, tc->id);
+}
+
+/**
+ * @brief Tests getting config id
+ * @param[in,out] state Pointer to pointer to correctly initialized test state.
+ * When finished, it contains pointer to usbg_state which should be cleaned.
+ */
+static void test_get_config_id(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_config(ts, s, try_get_config_id);
+}
+
+/**
+ * @brief Test getting given attributes from gadgets present in state
+ * @param[in] s Pointer to usbg state
+ * @param[in] ts Pointer to test state matching given usbg state
+ * @param[in] attrs Pointer to gadget attributes which should be put in
+ * virtual filesystem for writting by usbg
+ */
+static void try_get_gadget_attrs(usbg_state *s, struct test_state *ts,
+ usbg_gadget_attrs *attrs)
+{
+ usbg_gadget *g = NULL;
+ usbg_gadget_attrs actual;
+ struct test_gadget *tg;
+ int ret;
+
+ for (tg = ts->gadgets; tg->name; tg++) {
+ g = usbg_get_gadget(s, tg->name);
+ assert_non_null(g);
+
+ push_gadget_attrs(tg, attrs);
+ ret = usbg_get_gadget_attrs(g, &actual);
+
+ assert_int_equal(ret, 0);
+ assert_gadget_attrs_equal(&actual, attrs);
+ }
+}
+
+/**
+ * @brief Tests getting gadget attributes
+ * @param[in] state Pointer to correctly initialized test_state structure
+ **/
+static void test_get_gadget_attrs(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+
+ try_get_gadget_attrs(s, ts, &min_gadget_attrs);
+ try_get_gadget_attrs(s, ts, &max_gadget_attrs);
+ try_get_gadget_attrs(s, ts, get_random_gadget_attrs());
+}
+
+/**
+ * @brief Test setting given attributes on gadgets present in state
+ * @param[in] s Pointer to usbg state
+ * @param[in] ts Pointer to test state matching given usbg state
+ * @param[in] attrs Pointer to gadget attributes to be set
+ */
+static void try_set_gadget_attrs(usbg_state *s, struct test_state *ts,
+ usbg_gadget_attrs *attrs)
+{
+ usbg_gadget *g = NULL;
+ struct test_gadget *tg;
+ int ret;
+
+ for (tg = ts->gadgets; tg->name; tg++) {
+ g = usbg_get_gadget(s, tg->name);
+ assert_non_null(g);
+
+ pull_gadget_attrs(tg, attrs);
+ ret = usbg_set_gadget_attrs(g, attrs);
+
+ assert_int_equal(ret, 0);
+ }
+}
+/**
+ * @brief Tests setting gadget attributes
+ * @param[in] state Pointer to correctly initialized test_state structure
+ **/
+static void test_set_gadget_attrs(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+
+ try_set_gadget_attrs(s, ts, &min_gadget_attrs);
+ try_set_gadget_attrs(s, ts, &max_gadget_attrs);
+ try_set_gadget_attrs(s, ts, get_random_gadget_attrs());
+}
+
+/**
+ * @brief Test setting given attributes on gadgets present in state one by one,
+ * using functions specific for each attribute
+ * @param[in] s Pointer to usbg state
+ * @param[in] ts Pointer to test state matching given usbg state
+ * @param[in] attrs Pointer to gadget attributes to be set
+ */
+static void try_set_specific_gadget_attr(usbg_state *s, struct test_state *ts,
+ usbg_gadget_attrs *attrs)
+{
+ usbg_gadget *g = NULL;
+ struct test_gadget *tg;
+ int ret;
+ int i;
+ int attr;
+
+ for (tg = ts->gadgets; tg->name; tg++) {
+ g = usbg_get_gadget(s, tg->name);
+ assert_non_null(g);
+
+ for (i = USBG_GADGET_ATTR_MIN; i < USBG_GADGET_ATTR_MAX; i++) {
+ attr = get_gadget_attr(attrs, i);
+ pull_gadget_attribute(tg, i, attr);
+ usbg_set_gadget_attr(g, i, attr);
+ assert_int_equal(ret, 0);
+ }
+ }
+}
+
+/**
+ * @brief Tests setting gadget attributes one by one
+ * @param[in] state Pointer to correctly initialized test_state structure
+ **/
+static void test_set_specific_gadget_attr(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+
+ try_set_specific_gadget_attr(s, ts, &min_gadget_attrs);
+ try_set_specific_gadget_attr(s, ts, &max_gadget_attrs);
+ try_set_specific_gadget_attr(s, ts, get_random_gadget_attrs());
+}
+
+/**
+ * @brief Tests getting udc from state
+ * @param[in] state Pointer to correctly initialized test_state structure
+ **/
+void test_get_udc(void **state)
+{
+ struct test_state *ts;
+ char **tu;
+ struct test_gadget *tg;
+ usbg_state *s = NULL;
+ usbg_udc *u = NULL;
+ usbg_gadget *g = NULL;
+
+ safe_init_with_state(state, &ts, &s);
+
+ for (tu = ts->udcs; *tu; tu++) {
+ u = usbg_get_udc(s, *tu);
+ assert_non_null(u);
+ assert_string_equal(*tu, u->name);
+ assert_int_equal(s, u->parent);
+ }
+
+ for (tg = ts->gadgets; tg->name; tg++) {
+ u = usbg_get_udc(s, tg->udc);
+ g = usbg_get_gadget(s, tg->name);
+ assert_int_equal(u->gadget, g);
+ }
+}
+
+static void test_get_gadget_attr_str(void **state)
+{
+ struct {
+ usbg_gadget_attr attr;
+ const char *str;
+ } attrs[] = {
+ {BCD_USB, "bcdUSB"},
+ {B_DEVICE_CLASS, "bDeviceClass"},
+ {B_DEVICE_SUB_CLASS, "bDeviceSubClass"},
+ {B_DEVICE_PROTOCOL, "bDeviceProtocol"},
+ {B_MAX_PACKET_SIZE_0, "bMaxPacketSize0"},
+ {ID_VENDOR, "idVendor"},
+ {ID_PRODUCT, "idProduct"},
+ {BCD_DEVICE, "bcdDevice"},
+ };
+
+ const char *str;
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(attrs); i++) {
+ str = usbg_get_gadget_attr_str(attrs[i].attr);
+ assert_non_null(str);
+ assert_string_equal(str, attrs[i].str);
+ }
+
+ /* Check if iteration over values works */
+ for (i = USBG_GADGET_ATTR_MIN; i < USBG_GADGET_ATTR_MAX; ++i) {
+ str = usbg_get_gadget_attr_str(i);
+ assert_non_null(str);
+
+ for (j = 0; j < ARRAY_SIZE(attrs); ++j)
+ if (attrs[j].attr == i) {
+ assert_string_equal(str, attrs[j].str);
+ break;
+ }
+
+ assert_int_not_equal(j, ARRAY_SIZE(attrs));
+ }
+}
+
+static void test_get_gadget_attr_str_fail(void **state)
+{
+ const char *str;
+
+ str = usbg_get_gadget_attr_str(USBG_GADGET_ATTR_MIN - 1);
+ assert_null(str);
+
+ str = usbg_get_gadget_attr_str(USBG_GADGET_ATTR_MAX);
+ assert_null(str);
+}
+
+/**
+ * @brief set gadget strings
+ * @details Also do it one by one
+ * @param[in] data Pointer to correctly initialized test_gadget_strs_data structure
+ */
+static void test_set_gadget_strs(void **data)
+{
+ struct test_gadget_strs_data *ts;
+ struct test_gadget *tg;
+ usbg_state *s = NULL;
+ usbg_gadget *g = NULL;
+ int i;
+ int ret;
+
+ ts = (struct test_gadget_strs_data *)(*data);
+ *data = NULL;
+
+ init_with_state(ts->state, &s);
+ *data = s;
+
+ for (tg = ts->state->gadgets; tg->name; tg++) {
+ g = usbg_get_gadget(s, tg->name);
+
+ pull_gadget_strs(tg, LANG_US_ENG, ts->strs);
+ ret = usbg_set_gadget_strs(g, LANG_US_ENG, ts->strs);
+ assert_int_equal(ret, 0);
+
+ for (i = 0; i < GADGET_STR_MAX; i++)
+ pull_gadget_string(tg, LANG_US_ENG, i, get_gadget_str(ts->strs, i));
+
+ ret = usbg_set_gadget_serial_number(g, LANG_US_ENG, ts->strs->str_ser);
+ assert_int_equal(ret, 0);
+
+ ret = usbg_set_gadget_manufacturer(g, LANG_US_ENG, ts->strs->str_mnf);
+ assert_int_equal(ret, 0);
+
+ ret = usbg_set_gadget_product(g, LANG_US_ENG, ts->strs->str_prd);
+ assert_int_equal(ret, 0);
+
+ for (i = 0; i < GADGET_STR_MAX; i++)
+ pull_gadget_string(tg, LANG_US_ENG, i, get_gadget_str(ts->strs, i));
+
+
+ ret = usbg_set_gadget_str(g, STR_SERIAL_NUMBER, LANG_US_ENG, ts->strs->str_ser);
+ assert_int_equal(ret, 0);
+
+ ret = usbg_set_gadget_str(g, STR_MANUFACTURER, LANG_US_ENG, ts->strs->str_mnf);
+ assert_int_equal(ret, 0);
+
+ ret = usbg_set_gadget_str(g, STR_PRODUCT, LANG_US_ENG, ts->strs->str_prd);
+ assert_int_equal(ret, 0);
+ }
+}
+
+/**
+ * @brief get gadget strings
+ * @param[in] data Pointer to correctly initialized test_gadget_strs_data structure
+ */
+static void test_get_gadget_strs(void **data)
+{
+ struct test_gadget_strs_data *ts;
+ struct test_gadget *tg;
+ usbg_state *s = NULL;
+ usbg_gadget *g = NULL;
+ usbg_gadget_strs strs;
+
+ ts = (struct test_gadget_strs_data *)(*data);
+ *data = NULL;
+
+ init_with_state(ts->state, &s);
+ *data = s;
+
+ for (tg = ts->state->gadgets; tg->name; tg++) {
+ g = usbg_get_gadget(s, tg->name);
+ push_gadget_strs(tg, LANG_US_ENG, ts->strs);
+ usbg_get_gadget_strs(g, LANG_US_ENG, &strs);
+ assert_gadget_strs_equal(&strs, ts->strs);
+ }
+}
+
+/**
+ * @brief Get binding target
+ * @details Check if given function is target of given binding
+ * @param[in] tb Test function
+ * @param[in] b Binding
+ */
+static void try_get_binding_target(struct test_binding *tb, usbg_binding *b)
+{
+ usbg_function *f;
+
+ f = usbg_get_binding_target(b);
+ assert_non_null(f);
+ assert_func_equal(f, tb->target);
+}
+
+/**
+ * @brief Test get binding target
+ * @details Test all bindings present in given state
+ * @param[in, out] state Pointer to pointer to correctly initialized test state,
+ * will point to usbg state when finished.
+ */
+static void test_get_binding_target(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_binding(ts, s, try_get_binding_target);
+}
+
+/**
+ * @brief Get binding name
+ * @details Check if name of given binding is equal name of given function
+ * @param[in] tb Test function
+ * @param[in] b Binding
+ */
+static void try_get_binding_name(struct test_binding *tb, usbg_binding *b)
+{
+ const char *s;
+
+ s = usbg_get_binding_name(b);
+ assert_non_null(s);
+ assert_string_equal(s, tb->name);
+}
+
+/**
+ * @brief Test get bindig name from all binding present in state
+ * @param[in, out] state Pointer to pointer to correctly initialized test state,
+ * will point to usbg state when finished.
+ */
+static void test_get_binding_name(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_binding(ts, s, try_get_binding_name);
+}
+
+/**
+ * @brief Get binding name length
+ * @param[in] tb Test function
+ * @param[in] b Binding
+ */
+static void try_get_binding_name_len(struct test_binding *tb, usbg_binding *b)
+{
+ int n;
+
+ n = usbg_get_binding_name_len(b);
+ assert_int_equal(n, strlen(tb->name));
+}
+
+/**
+ * @brief Test get binding name length from all bindings present in state
+ * @param[in, out] state Pointer to pointer to correctly initialized test state,
+ * will point to usbg state when finished.
+ */
+static void test_get_binding_name_len(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_binding(ts, s, try_get_binding_name_len);
+}
+
+/**
+ * @brief Set config strings
+ * @param[in] c Config on which string should be set
+ * @param[in] tc Test config containing strings to be set
+ */
+static void try_set_config_strs(usbg_config *c, struct test_config *tc)
+{
+ pull_config_strs(tc, LANG_US_ENG, tc->strs);
+ usbg_set_config_strs(c, LANG_US_ENG, tc->strs);
+}
+
+/**
+ * @brief Test setting strings
+ * @details Set strings in all configs present in state
+ * @param[in, out] state Pointer to pointer to correctly initialized test state,
+ * will point to usbg state when finished.
+ */
+static void test_set_config_strs(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_config(ts, s, try_set_config_strs);
+}
+
+/**
+ * @brief Set strings one by one on config
+ * @param[in] c Config on which string should be set
+ * @param[in] tc Test config containing strings to be set
+ */
+static void try_set_config_string(usbg_config *c, struct test_config *tc)
+{
+ pull_config_string(tc, LANG_US_ENG, tc->strs->configuration);
+ usbg_set_config_string(c, LANG_US_ENG, tc->strs->configuration);
+}
+
+/**
+ * @brief Test setting strings one by one
+ * @details Set strings on all configs present in given state
+ * @param[in, out] state Pointer to pointer to correctly initialized test state,
+ * will point to usbg state when finished.
+ */
+static void test_set_config_string(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_config(ts, s, try_set_config_string);
+}
+
+/**
+ * @brief Get config strings
+ * @details Assume that given configs have the same strings
+ * @param[in] c Config from which strings should be get
+ * @param[in] tc Test config expected to have the same string as c
+ */
+static void try_get_config_strs(usbg_config *c, struct test_config *tc)
+{
+ usbg_config_strs strs;
+ push_config_strs(tc, LANG_US_ENG, tc->strs);
+ usbg_get_config_strs(c, LANG_US_ENG, &strs);
+ assert_string_equal(tc->strs->configuration, strs.configuration);
+}
+
+/**
+ * @brief Test getting congig strings
+ * @details Get config strings on all configs present in given state
+ * @param[in, out] state Pointer to pointer to correctly initialized test state,
+ * will point to usbg state when finished.
+ */
+static void test_get_config_strs(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_config(ts, s, try_get_config_strs);
+}
+
+/**
+ * @brief Get config attributes
+ * @details Assume that attributes which will be returned are the same as
+ * given test state contains.
+ * @param[in] c Usbg config
+ * @param[in] tc Test config with set attributes
+ */
+static void try_get_config_attrs(usbg_config *c, struct test_config *tc)
+{
+ usbg_config_attrs attrs;
+
+ push_config_attrs(tc, tc->attrs);
+ usbg_get_config_attrs(c, &attrs);
+ assert_config_attrs_equal(tc->attrs, &attrs);
+}
+
+/**
+ * @brief Test getting config attributes
+ * @details Get config attributes on all configfs in state
+ * @param[in, out] state Pointer to pointer to correctly initialized test state,
+ * will point to usbg state when finished.
+ */
+static void test_get_config_attrs(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_config(ts, s, try_get_config_attrs);
+}
+
+/**
+ * @brief Set config attributes in given config
+ * @param[in] c Usbg config
+ * @param[in] tc Test config with attributes which will be set
+ */
+static void try_set_config_attrs(usbg_config *c, struct test_config *tc)
+{
+ pull_config_attrs(tc, tc->attrs);
+ usbg_set_config_attrs(c, tc->attrs);
+}
+
+/**
+ * @brief Test setting config attributes
+ * @details Set config attributes on all configs in state
+ * @param[in, out] state Pointer to pointer to correctly initialized test state,
+ * will point to usbg state when finished.
+ */
+static void test_set_config_attrs(void **state)
+{
+ usbg_state *s = NULL;
+ struct test_state *ts;
+
+ safe_init_with_state(state, &ts, &s);
+ for_each_test_config(ts, s, try_set_config_attrs);
+}
+
+/**
+ * @brieg Test creating config
+ * @details Start with empty gadgets, add all functions from given state
+ * @param[in, out] state Pointer to pointer to correctly initialized test state,
+ * will point to usbg state when finished.
+ */
+static void test_create_config(void **state)
+{
+ usbg_state *s = NULL;
+ usbg_gadget *g = NULL;
+ usbg_config *c = NULL;
+ struct test_state *ts;
+ struct test_state *empty;
+ struct test_gadget *tg;
+ struct test_config *tc;
+
+ ts = (struct test_state *)(*state);
+ *state = NULL;
+
+ empty = build_empty_gadget_state(ts);
+
+ init_with_state(empty, &s);
+ *state = s;
+
+ for (tg = ts->gadgets; tg->name; tg++) {
+ g = usbg_get_gadget(s, tg->name);
+ assert_non_null(g);
+ for (tc = tg->configs; tc->label; tc++) {
+ pull_create_config(tc);
+ usbg_create_config(g, tc->id, tc->label,
+ tc->attrs, tc->strs, &c);
+ assert_config_equal(c, tc);
+ }
+ }
+}
+
+/**
+ * @brief Start with empty gadget, add all functions from given one
+ */
+static void test_create_function(void **state)
+{
+ usbg_state *s = NULL;
+ usbg_gadget *g = NULL;
+ usbg_function *f = NULL;
+ struct test_state *ts;
+ struct test_state *empty;
+ struct test_gadget *tg;
+ struct test_function *tf;
+
+ ts = (struct test_state *)(*state);
+ *state = NULL;
+
+ empty = build_empty_gadget_state(ts);
+
+ init_with_state(empty, &s);
+ *state = s;
+
+ for (tg = ts->gadgets; tg->name; tg++) {
+ g = usbg_get_gadget(s, tg->name);
+ assert_non_null(g);
+ for (tf = tg->functions; tf->instance; tf++) {
+ pull_create_function(tf);
+ usbg_create_function(g, tf->type, tf->instance,
+ tf->attrs, &f);
+ assert_func_equal(f, tf);
+ }
+ }
+}
+
+/**
+ * @brief Test only one given function for attribute getting
+ * @param[in] state Pointer to pointer to correctly initialized state
+ */
+static void test_get_function_attrs(void **state)
+{
+ struct test_function_attrs_data *data;
+ usbg_state *s;
+ usbg_function *f;
+ usbg_gadget *g;
+ usbg_function_attrs actual;
+ int ret;
+
+ data = (struct test_function_attrs_data *)(*state);
+ *state = NULL;
+
+
+ init_with_state(data->state, &s);
+ *state = s;
+
+ g = usbg_get_first_gadget(s);
+ assert_non_null(g);
+ f = usbg_get_first_function(g);
+ assert_non_null(f);
+
+ push_function_attrs(&data->state->gadgets[0].functions[0], data->attrs);
+ ret = usbg_get_function_attrs(f, &actual);
+
+ assert_int_equal(ret, 0);
+ assert_function_attrs_equal(&actual, data->attrs, data->attrs->header.attrs_type);
+
+ usbg_cleanup_function_attrs(&actual);
+}
+
+/**
+ * @brief Test setting attributes in only one given function
+ * @param[in] state Pointer to pointer to correctly initialized state
+ */
+static void test_set_function_attrs(void **state)
+{
+ struct test_function_attrs_data *data;
+ usbg_state *s;
+ usbg_function *f;
+ usbg_gadget *g;
+ int ret;
+
+ data = (struct test_function_attrs_data *)(*state);
+ *state = NULL;
+
+ init_with_state(data->state, &s);
+ *state = s;
+
+ g = usbg_get_first_gadget(s);
+ assert_non_null(g);
+ f = usbg_get_first_function(g);
+ assert_non_null(f);
+
+ pull_function_attrs(&data->state->gadgets[0].functions[0], data->attrs);
+ ret = usbg_set_function_attrs(f, data->attrs);
+
+ assert_int_equal(ret, 0);
+}
+
+/**
+ *
+ * @brief cleanup usbg state
+ */
+static int teardown_state(void **state)
+{
+ usbg_state *s = NULL;
+
+ s = (usbg_state *)(*state);
+ if (s != NULL)
+ usbg_cleanup(s);
+
+ cleanup_stack();
+ return 0;
+}
+
+/* Custom macro for defining test with given name and fixed teardown function */
+#define USBG_TEST_TS(name, test, setup) \
+ USBG_TEST(name, test, setup, teardown_state)
+
+/**
+ * @page usbg_tests Tests
+ * @brief This is list of test cases
+ * @tests_start
+ */
+
+#ifndef DOXYGEN
+static struct CMUnitTest tests[] = {
+#endif
+
+ /**
+ * @usbg_test
+ * @test_desc{test_init_simple,
+ * Check if init was successfull on simple configfs state,
+ * usbg_init}
+ */
+ USBG_TEST_TS("test_init_simple",
+ test_init, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_init_all_funcs,
+ * Check if init was successfull when all avaible functions
+ * are present in configfs,
+ * usbg_init}
+ */
+ USBG_TEST_TS("test_init_all_funcs",
+ test_init, setup_all_funcs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_init_long_path,
+ * Try to initialize libusbg with long configfs path,
+ * usbg_init}
+ */
+ USBG_TEST_TS("test_init_long_path",
+ test_init, setup_long_path_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_init_long_udc,
+ * Try to initialize libusbg with long udc name,
+ * usbg_init}
+ */
+ USBG_TEST_TS("test_init_long_udc",
+ test_init, setup_long_udc_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_gadget_simple,
+ * Check if simple gadget will be correcty returned,
+ * usbg_get_gadget}
+ */
+ USBG_TEST_TS("test_get_gadget_simple",
+ test_get_gadget, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_gadget_fail_simple,
+ * Check if getting non-existing and wrong gadgets cause
+ * expected failure and error codes are correct,
+ * usbg_get_gadget}
+ */
+ USBG_TEST_TS("test_get_gadget_fail_simple",
+ test_get_gadget_fail, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_first_gadget_simple,
+ * Check if gadget returned by get_first_gadget
+ * is actually first one,
+ * usbg_get_first_gadget}
+ */
+ USBG_TEST_TS("test_get_first_gadget_simple",
+ test_get_first_gadget, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_first_gadget_fail,
+ * Check if getting first gadget from state returns NULL when
+ * invalid parameters are passed,
+ * usbg_get_first_gadget}
+ */
+ unit_test(test_get_first_gadget_fail),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_gadget_name_simple,
+ * Check if returned gadget name matches expected value,
+ * usbg_get_gadget_name}
+ */
+ USBG_TEST_TS("test_get_gadget_name_simple",
+ test_get_gadget_name, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_gadget_name_len,
+ * Check if returned simple gadget name length matches expected value,
+ * usbg_get_gadget_name}
+ */
+ USBG_TEST_TS("test_get_gadget_name_len_simple",
+ test_get_gadget_name_len, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_gadget_name_fail,
+ * Check if trying to get name of invalid gadget
+ * cause expected failure (name is null),
+ * usbg_get_gadget_name}
+ */
+ unit_test(test_get_gadget_name_fail),
+ /**
+ * @usbg_test
+ * @test_desc{test_cpy_gadget_name_simple,
+ * Check if getting simple gadget name into buffer work as expected,
+ * usbg_cpy_gadget_name}
+ */
+ USBG_TEST_TS("test_cpy_gadget_name_simple",
+ test_cpy_gadget_name, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_cpy_gadget_name_fail_simple,
+ * Check if writting gadget name into buffer fail when
+ * invalid parameters are passed,
+ * usbg_cpy_gadget_name}
+ */
+ USBG_TEST_TS("test_cpy_gadget_name_fail_simple",
+ test_cpy_gadget_name_fail, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_function_simple,
+ * Check if function can be correctly get from simple state,
+ * usbg_get_function}
+ */
+ USBG_TEST_TS("test_get_function_simple",
+ test_get_function, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_function_all_funcs,
+ * Check if getting function work on all function types,
+ * usbg_get_function}
+ */
+ USBG_TEST_TS("test_get_function_all_funcs",
+ test_get_function, setup_all_funcs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_function_same_type_funcs,
+ * Check if having multiple functions with the same type does not
+ * cause failure
+ * usbg_get_function}
+ */
+ USBG_TEST_TS("test_get_function_same_type_funcs",
+ test_get_function, setup_same_type_funcs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_function_fail_simple,
+ * Check if trying to get invalid function's name ends
+ * with expected error,
+ * usbg_get_function}
+ */
+ USBG_TEST_TS("test_get_function_fail_simple",
+ test_get_function_fail, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_function_instance_simple,
+ * Check if getting simple instance returns what expected,
+ * usbg_get_function_instance}
+ */
+ USBG_TEST_TS("test_get_function_instance_simple",
+ test_get_function_instance, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_cpy_function_instance_simple,
+ * Check if copying simple instance into buffer returns what expected,
+ * usbg_cpy_function_instance}
+ */
+ USBG_TEST_TS("test_cpy_function_instance_simple",
+ test_cpy_function_instance, setup_all_funcs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_function_type_simple,
+ * Check if function type is returned correctly,
+ * usbg_get_function_type}
+ */
+ USBG_TEST_TS("test_get_function_type_simple",
+ test_get_function_type, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_function_type_all_funcs,
+ * Check if all function types are returned correctly,
+ * usbg_get_function_type}
+ */
+ USBG_TEST_TS("test_get_function_type_all_funcs",
+ test_get_function_type, setup_all_funcs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_function_instance_len_simple,
+ * Check if function instance length is returned correctly,
+ * usbg_get_function_instance_len}
+ */
+ USBG_TEST_TS("test_get_function_instance_len_simple",
+ test_get_function_instance_len, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_function_type_str,
+ * Compare returned function types strings with expected values,
+ * usbg_get_function_type_str}
+ */
+ unit_test(test_get_function_type_str),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_function_type_str_fail,
+ * Try to get type string of unknown type,
+ * usbg_get_function_type_str}
+ */
+ unit_test(test_get_function_type_str_fail),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_configfs_path_simple,
+ * heck if simple configfs path was returned correctly,
+ * usbg_get_configfs_path}
+ */
+ USBG_TEST_TS("test_get_configfs_path_simple",
+ test_get_configfs_path, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_configfs_path_len,
+ * Check if configfs path length is correctly calculated,
+ * usbg_get_configfs_path_len}
+ */
+ USBG_TEST_TS("test_get_configfs_path_len_simple",
+ test_get_configfs_path_len, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_cpy_configfs_path_simple,
+ * Copy simple configfs path into buffer and compare with original,
+ * usbg_cpy_configfs_path}
+ */
+ USBG_TEST_TS("test_cpy_configfs_path_simple",
+ test_cpy_configfs_path, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_config_simple,
+ * Check if returned simple config matches original one,
+ * usbg_get_config}
+ */
+ USBG_TEST_TS("test_get_config_simple",
+ test_get_config, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_config_without_label_simple,
+ * Check if returned simple config matches original one,
+ * usbg_get_config}
+ */
+ USBG_TEST_TS("test_get_config_without_label_simple",
+ test_get_config_without_label, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_config_fail,
+ * Check if trying to get non-existing or invalid config
+ * fails as expected,
+ * usbg_get_config}*/
+ USBG_TEST_TS("test_get_config_fail",
+ test_get_config_fail, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_config_label_simple,
+ * Check if returned simple config label matches original one,
+ * usbg_get_config_label}
+ */
+ USBG_TEST_TS("test_get_config_label_simple",
+ test_get_config_label, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_config_id_simple,
+ * Check if returned simple config id matches original one,
+ * usbg_get_config_id}
+ */
+ USBG_TEST_TS("test_get_config_id_simple",
+ test_get_config_id, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_gadget_attrs_simple,
+ * Get gadget attributes list and compare them with original,
+ * usbg_get_gadget_attrs}
+ */
+ USBG_TEST_TS("test_get_gadget_attrs_simple",
+ test_get_gadget_attrs, setup_simple_state),
+ /**
+ * @usbg_tets
+ * @test_desc{test_set_gadget_attrs_simple,
+ * Set gadget attributes list\, check if everything is wrote
+ * as expected,
+ * usbg_set_gadget_attrs}
+ */
+ USBG_TEST_TS("test_set_gadget_attrs_simple",
+ test_set_gadget_attrs, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_set_specific_gadget_attr_simple,
+ * Set gadget attributes one by one,
+ * usbg_set_gadget_attrs}
+ */
+ USBG_TEST_TS("test_set_specific_gadget_attr_simple",
+ test_set_specific_gadget_attr, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_udc_simple,
+ * Get udc name from state,
+ * usbg_get_udc}
+ */
+ USBG_TEST_TS("test_get_udc_simple",
+ test_get_udc, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_udc_long,
+ * Get udc name witch very long name,
+ * usbg_get_udc}
+ */
+ USBG_TEST_TS("test_get_udc_long",
+ test_get_udc, setup_long_udc_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_gadget_attr_str,
+ * Compare returned gadget attribute strings witch expected values
+ * usbg_get_gadget_attr_str}
+ */
+ unit_test(test_get_gadget_attr_str),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_gadget_attr_str_fail,
+ * Check returned gadget attribute strings for invalid arguments
+ * usbg_get_gadget_attr_str}
+ */
+ unit_test(test_get_gadget_attr_str_fail),
+ /**
+ * @usbg_test
+ * @test_desc{test_set_gadget_strs_random,
+ * Set gadget strings of random length,
+ * usbg_set_gadget_strs}
+ */
+ USBG_TEST_TS("test_set_gadget_strs_random",
+ test_set_gadget_strs, setup_random_len_gadget_strs_data),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_gadget_strs_random,
+ * Get gadget strings,
+ * usbg_get_gadget_strs}
+ */
+ USBG_TEST_TS("test_get_gadget_strs_random",
+ test_get_gadget_strs, setup_random_len_gadget_strs_data),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_binding_target_simple,
+ * Get binding target,
+ * usbg_get_binding_target}
+ */
+ USBG_TEST_TS("test_get_binding_target_simple",
+ test_get_binding_target, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_binding_name_simple,
+ * Get binding name,
+ * usbg_get_binding_name}
+ */
+ USBG_TEST_TS("test_get_binding_name_simple",
+ test_get_binding_name, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_binding_name_len_simple,
+ * Get binding name length,
+ * usbg_get_binding_name_len}
+ */
+ USBG_TEST_TS("test_get_binding_name_len_simple",
+ test_get_binding_name_len, setup_simple_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_set_config_strs_simple,
+ * Set simple strings in set of configurations,
+ * usbg_set_config_strs}
+ */
+ USBG_TEST_TS("test_set_config_strs_simple",
+ test_set_config_strs, setup_simple_config_strs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_set_config_string_simple,
+ * Set simple string in set of configurations,
+ * usbg_set_config_string}
+ */
+ USBG_TEST_TS("test_set_config_string_simple",
+ test_set_config_string, setup_simple_config_strs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_config_strs_simple,
+ * Get simple strings from set of configurations,
+ * usbg_get_config_strs}
+ */
+ USBG_TEST_TS("test_get_config_strs_simple",
+ test_get_config_strs, setup_simple_config_strs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_config_attrs_max,
+ * Get config attributes with max values,
+ * usbg_get_config_attrs}
+ */
+ USBG_TEST_TS("test_get_config_attrs_max",
+ test_get_config_attrs, setup_max_config_attrs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_config_attrs_min,
+ * Get config attributes with minimum values,
+ * usbg_get_config_attrs}
+ */
+ USBG_TEST_TS("test_get_config_attrs_min",
+ test_get_config_attrs, setup_min_config_attrs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_config_attrs_random,
+ * Get config attributes with random values,
+ * usbg_get_config_attrs}
+ */
+ USBG_TEST_TS("test_get_config_attrs_random",
+ test_get_config_attrs, setup_random_config_attrs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_set_config_attrs_max,
+ * Set config attributes with max values,
+ * usbg_set_config_attrs}
+ */
+ USBG_TEST_TS("test_set_config_attrs_max",
+ test_set_config_attrs, setup_max_config_attrs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_set_config_attrs_min,
+ * Set config attributes with minimum values,
+ * usbg_set_config_attrs}
+ */
+ USBG_TEST_TS("test_set_config_attrs_min",
+ test_set_config_attrs, setup_min_config_attrs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_set_config_attrs_random,
+ * Set config attributes with random values,
+ * usbg_set_config_attrs}
+ */
+ USBG_TEST_TS("test_set_config_attrs_random",
+ test_set_config_attrs, setup_random_config_attrs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_create_config_random,
+ * Create config with random attributes
+ * usbg_create_config}
+ */
+ USBG_TEST_TS("test_create_config_random",
+ test_create_config, setup_random_config_attrs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_serial_attrs,
+ * Get f_serial function attributes,
+ * usbg_get_function_attrs}
+ */
+ USBG_TEST_TS("test_get_f_serial_attrs",
+ test_get_function_attrs, setup_f_serial_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_obex_attrs,
+ * Get f_obex function attributes,
+ * usbg_get_function_attrs}
+ */
+ USBG_TEST_TS("test_get_f_obex_attrs",
+ test_get_function_attrs, setup_f_obex_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_acm_attrs,
+ * Get f_acm function attributes,
+ * usbg_get_function_attrs}
+ */
+ USBG_TEST_TS("test_get_f_acm_attrs",
+ test_get_function_attrs, setup_f_acm_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_ecm_attrs,
+ * Get f_ecm function attributes,
+ * usbg_get_function_attrs}
+ */
+ USBG_TEST_TS("test_get_f_ecm_attrs",
+ test_get_function_attrs, setup_f_ecm_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_eem_attrs,
+ * Get f_eem function attributes,
+ * usbg_get_function_attrs}
+ */
+ USBG_TEST_TS("test_get_f_eem_attrs",
+ test_get_function_attrs, setup_f_eem_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_subset_attrs,
+ * Get f_subset function attributes,
+ * usbg_get_function_attrs}
+ */
+ USBG_TEST_TS("test_get_f_subset_attrs",
+ test_get_function_attrs, setup_f_subset_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_ncm_attrs,
+ * Get f_ncm function attributes,
+ * usbg_get_function_attrs}
+ */
+ USBG_TEST_TS("test_get_f_ncm_attrs",
+ test_get_function_attrs, setup_f_ncm_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_serial_attrs,
+ * Get f_rndis function attributes,
+ * usbg_get_function_attrs}
+ */
+ USBG_TEST_TS("test_get_f_rndis_attrs",
+ test_get_function_attrs, setup_f_rndis_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_phonet_attrs,
+ * Get f_phonet function attributes,
+ * usbg_get_function_attrs}
+ */
+ USBG_TEST_TS("test_get_f_phonet_attrs",
+ test_get_function_attrs, setup_f_phonet_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_serial_attrs,
+ * Get f_ffs function attributes,
+ * usbg_get_function_attrs}
+ */
+ USBG_TEST_TS("test_get_f_ffs_attrs",
+ test_get_function_attrs, setup_f_ffs_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_serial_attrs,
+ * Set f_serial function attributes,
+ * usbg_set_function_attrs}
+ */
+ USBG_TEST_TS("test_set_f_serial_attrs",
+ test_set_function_attrs, setup_f_serial_writable_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_acm_attrs,
+ * Set f_acm function attributes,
+ * usbg_set_function_attrs}
+ */
+ USBG_TEST_TS("test_set_f_acm_attrs",
+ test_set_function_attrs, setup_f_acm_writable_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_serial_obex,
+ * Set f_obex function attributes,
+ * usbg_set_function_attrs}
+ */
+ USBG_TEST_TS("test_set_f_obex_attrs",
+ test_set_function_attrs, setup_f_obex_writable_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_ecm_attrs,
+ * Set f_ecm function attributes,
+ * usbg_set_function_attrs}
+ */
+ USBG_TEST_TS("test_set_f_ecm_attrs",
+ test_set_function_attrs, setup_f_ecm_writable_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_eem_attrs,
+ * Set f_eem function attributes,
+ * usbg_set_function_attrs}
+ */
+ USBG_TEST_TS("test_set_f_eem_attrs",
+ test_set_function_attrs, setup_f_eem_writable_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_subset_attrs,
+ * Set f_subset function attributes,
+ * usbg_set_function_attrs}
+ */
+ USBG_TEST_TS("test_set_f_subset_attrs",
+ test_set_function_attrs, setup_f_subset_writable_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_ncm_attrs,
+ * Set f_ncm function attributes,
+ * usbg_set_function_attrs}
+ */
+ USBG_TEST_TS("test_set_f_ncm_attrs",
+ test_set_function_attrs, setup_f_ncm_writable_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_serial_attrs,
+ * Set f_rndis function attributes,
+ * usbg_get_function_attrs}
+ */
+ USBG_TEST_TS("test_set_f_rndis_attrs",
+ test_set_function_attrs, setup_f_rndis_writable_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_phonet_attrs,
+ * Set f_phonet function attributes,
+ * usbg_set_function_attrs}
+ */
+ USBG_TEST_TS("test_set_f_phonet_attrs",
+ test_set_function_attrs, setup_f_phonet_writable_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_f_serial_attrs,
+ * Set f_ffs function attributes,
+ * usbg_set_function_attrs}
+ */
+ USBG_TEST_TS("test_set_f_ffs_attrs",
+ test_set_function_attrs, setup_f_ffs_writable_attrs),
+ /**
+ * @usbg_test
+ * @test_desc{test_create_all_functions,
+ * Create full set of functions in empty state,
+ * usbg_get_binding_name_len}
+ */
+ USBG_TEST_TS("test_create_all_functions",
+ test_create_function, setup_all_funcs_state),
+ /**
+ * @usbg_test
+ * @test_desc{test_get_gadget_str_name,
+ * Compare returned gadget string name with expected
+ * usbg_get_gadget_str_name}
+ */
+ unit_test(test_get_gadget_str_name),
+ /**
+ * @usbg_test
+ * @test_desc{test_lookup_gadget_str,
+ * Compare returned gadget string code with expected
+ * usbg_lookup_gadget_str}
+ */
+ unit_test(test_lookup_gadget_str),
+
+#ifndef DOXYGEN
+};
+#endif
+
+/**
+ * @usbg_test
+ * @tests_end
+ */
+
+#define TESTS_TAG "tests"
+/* for autotools compability */
+#define SKIPPED_CODE 77
+
+#ifdef HAS_LIBCONFIG
+
+static int gen_test_config(FILE *output)
+{
+ config_t cfg;
+ config_setting_t *root;
+ config_setting_t *tests_node, *node;
+ int i;
+ int ret = SKIPPED_CODE, cfg_ret = 0;
+
+ config_init(&cfg);
+ config_set_tab_width(&cfg, 4);
+
+ root = config_root_setting(&cfg);
+ tests_node = config_setting_add(root, TESTS_TAG, CONFIG_TYPE_LIST);
+ if (!tests_node) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i) {
+ node = config_setting_add(tests_node, NULL, CONFIG_TYPE_STRING);
+ if (!node) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cfg_ret = config_setting_set_string(node, tests[i].name);
+ if (cfg_ret != CONFIG_TRUE) {
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ config_write(&cfg, output);
+out:
+ config_destroy(&cfg);
+ return ret;
+}
+
+#else
+
+static int gen_test_config(FILE *output)
+{
+ fprintf(stderr, "Libconfig is not supported\n");
+ return -ENOTSUP;
+}
+
+#endif /* HAS_LIBCONFIG */
+
+static int lookup_test(const char *name)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(tests); ++i)
+ if (!strcmp(name, tests[i].name))
+ return i;
+
+ return -1;
+}
+
+static void test_skipped(void **state)
+{
+ skip();
+}
+
+#ifdef HAS_LIBCONFIG
+static int apply_test_config(FILE *input)
+{
+ config_t cfg;
+ config_setting_t *root;
+ config_setting_t *tests_node, *node;
+ int i, count, ind;
+ int ret = 0, cfg_ret = 0;
+ const char *test_name;
+ char selected[ARRAY_SIZE(tests)];
+
+ for (i = 0; i < ARRAY_SIZE(selected); ++i)
+ selected[i] = 0;
+
+ config_init(&cfg);
+
+ cfg_ret = config_read(&cfg, input);
+ if (cfg_ret != CONFIG_TRUE) {
+ fprintf(stderr, "Wrong config format\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ root = config_root_setting(&cfg);
+ tests_node = config_setting_get_member(root, TESTS_TAG);
+ if (!tests_node || !config_setting_is_list(tests_node)) {
+ fprintf(stderr, "Missing or incorrect tests list\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ count = config_setting_length(tests_node);
+ for (i = 0; i < count; ++i) {
+ node = config_setting_get_elem(tests_node, i);
+ if (!node) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ test_name = config_setting_get_string(node);
+ if (!test_name) {
+ fprintf(stderr, "Incorrect tests list. Element %d\n", i);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ind = lookup_test(test_name);
+ if (ind < 0) {
+ fprintf(stderr, "Test %s not found.\n", test_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ selected[ind] = 1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(selected); ++i) {
+ if (selected[i])
+ continue;
+
+ tests[i].test_func = &test_skipped;
+ tests[i].setup_func = NULL;
+ tests[i].teardown_func = NULL;
+ }
+out:
+ config_destroy(&cfg);
+ return ret;
+}
+
+#else
+
+static int apply_test_config(FILE *input)
+{
+ fprintf(stderr, "Libconfig is not supported\n");
+ return -ENOTSUP;
+}
+
+#endif /* HAS_LIBCONFIG */
+
+static void print_help()
+{
+ fprintf(stderr,
+ "libusbgx test suit:\n"
+ " --generate-config - generates config to stdout and exit\n"
+ " --use-config - runs test suit using config from stdin\n"
+ " -h --help - print this message\n"
+ );
+}
+
+int main(int argc, char **argv)
+{
+ enum {
+ GENERATE_CONFIG = 0x01,
+ USE_CONFIG = 0x02,
+ };
+
+ int options = 0;
+ int opt;
+ int ret = -EINVAL;
+
+ static struct option long_options[] = {
+ {"generate-config", no_argument, 0, 1},
+ {"use-config", no_argument, 0, 2},
+ {"help", no_argument, 0, 'h'},
+ {NULL, 0, 0, 0}
+ };
+
+ while (1) {
+ opt = getopt_long(argc, argv, "h", long_options, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt) {
+ case 1:
+ options |= GENERATE_CONFIG;
+ break;
+ case 2:
+ options |= USE_CONFIG;
+ break;
+ case 'h':
+ default:
+ print_help();
+ goto out;
+ }
+ }
+
+ if (optind < argc ||
+ ((options & GENERATE_CONFIG) &&
+ (options & USE_CONFIG))) {
+ print_help();
+ goto out;
+ }
+
+ if (options & GENERATE_CONFIG) {
+ ret = gen_test_config(stdout);
+ goto out;
+ }
+
+ if (options & USE_CONFIG) {
+ ret = apply_test_config(stdin);
+ if (ret)
+ goto out;
+ }
+
+ ret = cmocka_run_group_tests(tests, NULL, NULL);
+
+out:
+ return ret;
+}
diff --git a/tests/test.sh b/tests/test.sh
new file mode 100755
index 0000000..45b8e3e
--- /dev/null
+++ b/tests/test.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+
+#USE_CONFIG=0
+#GENERATE_CONFIG=0
+#HELP=$HELP
+
+# for autotools compability (config can be passed by environment variable)
+if [[ -n $USE_CONFIG ]]
+then
+ CONFIG_FILE=$USE_CONFIG
+elif [[ -n $GENERATE_CONFIG ]]
+then
+ CONFIG_FILE=$GENERATE_CONFIG
+fi
+
+function usage {
+ echo "libusbgx test suit"
+ echo "Usage: ./test.sh [option]"
+ echo "Options:"
+ echo " --generate-config filename - generates config to given file and exit"
+ echo " --use-config filename - runs test suit using config from given file"
+ echo " -h --help - print this message"
+}
+
+# Parse arguments
+
+ARGS=$(getopt --long generate-config:,use-config:,help -o h -- "$@" )
+
+if [ $? -ne 0 ]
+then
+ HELP=1
+fi
+
+eval set -- $ARGS
+
+while true; do
+ case $1 in
+ -h|--help)
+ HELP=1
+ shift
+ ;;
+ --use-config)
+ USE_CONFIG=1
+ CONFIG_FILE=$2
+ shift 2
+ ;;
+ --generate-config)
+ GENERATE_CONFIG=1
+ CONFIG_FILE=$2
+ shift 2
+ ;;
+ --)
+ shift
+ break
+ ;;
+ *)
+ HELP=1
+ shift
+ ;;
+ esac
+done
+
+# Run test with io functions ovverride
+
+if [[ -n $USE_CONFIG ]]
+then
+ LD_LIBRARY_PATH=. ./test --use-config < $CONFIG_FILE
+elif [[ -n $GENERATE_CONFIG ]]
+then
+ LD_LIBRARY_PATH=. ./test --generate-config > $CONFIG_FILE
+elif [[ -n $HELP ]]
+then
+ usage
+ exit 77 # autotools consider it skipped
+else
+ LD_LIBRARY_PATH=. ./test
+fi
+
diff --git a/tests/usbg-io-wrappers.c b/tests/usbg-io-wrappers.c
new file mode 100644
index 0000000..d8f471a
--- /dev/null
+++ b/tests/usbg-io-wrappers.c
@@ -0,0 +1,203 @@
+#define _GNU_SOURCE
+#include <dirent.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <cmocka.h>
+#include <dlfcn.h>
+#include <errno.h>
+
+typedef int (*fputs_f_type)(const char *, FILE *);
+typedef int (*fflush_f_type)(FILE *);
+typedef fflush_f_type ferror_f_type;
+
+/**
+ * @brief Simulates opening file
+ * @details Checks if path is equal expected value and returns given pointer
+ * from cmocka queue
+ */
+FILE *fopen(const char *path, const char *mode)
+{
+ check_expected(path);
+ return mock_ptr_type(FILE *);
+}
+
+/**
+ * @brief Simulates closing file
+ * @details Does absolutely nothing, always acts as successfull close
+ */
+int fclose(FILE *fp)
+{
+ check_expected(fp);
+ return mock_type(int);
+}
+
+/**
+ * @brief Simulates reading file
+ * @details Does not read any file, instead returns value from cmocka queue
+ * @return value specified by caller previously
+ */
+char *fgets(char *s, int size, FILE *stream)
+{
+ check_expected(stream);
+ strncpy(s, mock_ptr_type(char *), size);
+ return s;
+}
+
+/**
+ * @brief Simulates opening directory
+ * @details Does not open any dir, instead returns user-specified value
+ * @return value specified by caller previously
+ */
+DIR *opendir(const char *name)
+{
+ int err;
+
+ check_expected(name);
+ err = mock_type(int);
+ if (err)
+ errno = err;
+
+ return mock_ptr_type(DIR *);
+}
+
+/**
+ * @brief Simulates closing directory
+ * @details Does nothing and ends successfully.
+ */
+int closedir(DIR *dirp)
+{
+ check_expected(dirp);
+ return mock_type(int);
+}
+
+/**
+ * @brief Simulates scanning directory
+ * @details Checks if dirp has expected value. Then consecutive values from
+ * cmocka queue are proceed. First value must be integer and indicates number
+ * of directory entries which should be returned. Next number of values indicate
+ * names of directory entries.
+ */
+int scandir(const char *dirp, struct dirent ***namelist,
+ int (*filter)(const struct dirent *),
+ int (*compar)(const struct dirent **, const struct dirent **))
+{
+ int count;
+ int i, j = 0;
+ char *name;
+ struct dirent **entries;
+ struct dirent *entry;
+ int tmp, expected;
+
+ check_expected(dirp);
+ count = mock_type(int);
+
+ if (count > 0)
+ entries = calloc(count, sizeof(*entries));
+ else
+ entries = NULL;
+
+ for (i = 0; i < count; i++) {
+ name = mock_ptr_type(char *);
+ entry = malloc(sizeof(*entry));
+ if (strlen(name) >= NAME_MAX)
+ fail();
+
+ strcpy(entry->d_name, name);
+ entry->d_type = mock_type(unsigned char);
+
+ expected = mock_type(int);
+ if (filter) {
+ tmp = filter(entry);
+ assert_int_equal(tmp, expected);
+ if (tmp)
+ entries[j++] = entry;
+ else
+ free(entry);
+ }
+ }
+
+ if (compar)
+ qsort(entries, count, sizeof(*entries),
+ (int (*)(const void *,const void *))compar);
+
+ *namelist = entries;
+ return j;
+}
+
+/**
+ * @brief Simultes readlink, with user-specified behavior
+ * @datails Check if path and bufsiz equal expedted values and
+ * write to buf string given by cmocka
+ */
+ssize_t readlink(const char *path, char *buf, size_t bufsiz)
+{
+ char *res;
+ int reslen;
+
+ check_expected(path);
+ check_expected(bufsiz);
+ res = mock_ptr_type(char *);
+ reslen = strlen(res);
+ if (bufsiz <= reslen)
+ fail();
+
+ strcpy(buf, res);
+
+ return reslen;
+}
+
+/**
+ * @brief Simulates puts, with user-specified behavior
+ * @details Check if user is trying to write expected data
+ * @return value received from cmocka queue
+ */
+int fputs(const char *s, FILE *stream)
+{
+ /* Cmocka (or anything else) may want to print some errors.
+ * Especially when running fputs itself */
+ if (stream == stderr || stream == stdout) {
+ fputs_f_type orig_fputs;
+ orig_fputs = (fputs_f_type)dlsym(RTLD_NEXT, "fputs");
+ return orig_fputs(s, stream);
+ }
+
+ check_expected(stream);
+ check_expected(s);
+ return mock_type(int);
+}
+
+int mkdir(const char *pathname, mode_t mode)
+{
+ check_expected(pathname);
+ check_expected(mode);
+ return mock_type(int);
+}
+
+/**
+ * @brief Does nothing.
+ */
+int fflush(FILE *stream)
+{
+ if (stream == stderr || stream == stdout) {
+ fflush_f_type orig_fflush;
+ orig_fflush = (fflush_f_type)dlsym(RTLD_NEXT, "fflush");
+ return orig_fflush(stream);
+ }
+
+ return 0;
+}
+
+int ferror(FILE *stream)
+{
+ if (stream == stderr || stream == stdout) {
+ ferror_f_type orig_ferror;
+ orig_ferror = (ferror_f_type)dlsym(RTLD_NEXT, "ferror");
+ return orig_ferror(stream);
+ }
+
+ return 0;
+}
diff --git a/tests/usbg-test.c b/tests/usbg-test.c
new file mode 100644
index 0000000..c332795
--- /dev/null
+++ b/tests/usbg-test.c
@@ -0,0 +1,1389 @@
+#include <usbg/usbg.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <limits.h>
+#include <errno.h>
+#include <time.h>
+
+#include "usbg-test.h"
+
+static struct simple_stack{
+ void *ptr;
+ struct simple_stack *next;
+} *cleanup_top = NULL;
+
+static const char *gadget_str_names[] = {
+ "serialnumber",
+ "manufacturer",
+ "product"
+};
+
+static const char *config_attr_names[] = {
+ "MaxPower",
+ "bmAttributes"
+};
+
+static attr_format config_attr_format[] = {
+ [MAX_POWER] = FORMAT_DEC,
+ [BM_ATTRIBUTES] = FORMAT_HEX
+};
+
+void free_later(void *ptr)
+{
+ struct simple_stack *t;
+
+ t = malloc(sizeof(*t));
+ t->ptr = ptr;
+ t->next = cleanup_top;
+ cleanup_top = t;
+}
+
+void cleanup_stack()
+{
+ struct simple_stack *t;
+
+ while (cleanup_top) {
+ free(cleanup_top->ptr);
+ t = cleanup_top->next;
+ free(cleanup_top);
+ cleanup_top = t;
+ }
+}
+
+/* Represent last file/dir opened, next should have bigger numbers.*/
+static int file_id = 0;
+static int dir_id = 0;
+
+#define PUSH_FILE(file, content) do {\
+ file_id++;\
+ expect_path(fopen, path, file);\
+ will_return(fopen, file_id);\
+ expect_value(fgets, stream, file_id);\
+ will_return(fgets, content);\
+ expect_value(fclose, fp, file_id);\
+ will_return(fclose, 0);\
+} while(0)
+
+#define PUSH_FILE_ALWAYS(dflt) do {\
+ expect_any_count(fopen, path, -1);\
+ will_return_always(fopen, 1);\
+ expect_any_count(fgets, stream, 1);\
+ will_return_always(fgets, dflt);\
+ expect_any_count(fclose, fp, 1);\
+ will_return_always(fclose, 0);\
+} while(0)
+
+#define PUSH_EMPTY_DIR(p) do {\
+ expect_string(scandir, dirp, p);\
+ will_return(scandir, 0);\
+} while(0)
+
+#define EXPECT_OPENDIR(n) do {\
+ dir_id++;\
+ expect_path(opendir, name, n);\
+ will_return(opendir, 0);\
+ will_return(opendir, dir_id);\
+ expect_value(closedir, dirp, dir_id);\
+ will_return(closedir, 0);\
+} while(0)
+
+#define EXPECT_OPENDIR_ERROR(n, e) do {\
+ expect_path(opendir, name, n);\
+ will_return(opendir, e);\
+ will_return(opendir, NULL);\
+} while(0)
+
+#define PUSH_DIR(p, c) do {\
+ expect_path(scandir, dirp, p);\
+ will_return(scandir, c);\
+} while(0)
+
+#define PUSH_DIR_ENTRY(name, type) do {\
+ will_return(scandir, name);\
+ will_return(scandir, type);\
+ will_return(scandir, 1);\
+} while(0)
+
+#define PUSH_LINK(p, c, len) do {\
+ expect_path(readlink, path, p);\
+ expect_in_range(readlink, bufsiz, len, INT_MAX);\
+ will_return(readlink, c);\
+} while(0)
+
+#define EXPECT_WRITE(file, content) do {\
+ file_id++;\
+ expect_path(fopen, path, file);\
+ will_return(fopen, file_id);\
+ expect_value(fputs, stream, file_id);\
+ expect_string(fputs, s, content);\
+ will_return(fputs, 0);\
+ expect_value(fclose, fp, file_id);\
+ will_return(fclose, 0);\
+} while(0)
+
+#define EXPECT_HEX_WRITE(file, content) do {\
+ file_id++;\
+ expect_path(fopen, path, file);\
+ will_return(fopen, file_id);\
+ expect_value(fputs, stream, file_id);\
+ expect_check(fputs, s, hex_str_equal_display_error, content);\
+ will_return(fputs, 0);\
+ expect_value(fclose, fp, file_id);\
+ will_return(fclose, 0);\
+} while(0)
+
+#define EXPECT_MKDIR(p) do {\
+ expect_path(mkdir, pathname, p);\
+ expect_value(mkdir, mode, 00777);\
+ will_return(mkdir, 0);\
+} while(0)
+
+/**
+ * @brief Compare test gadgets' names
+ */
+static int test_gadget_cmp(struct test_gadget *a, struct test_gadget *b)
+{
+ return strcoll(a->name, b->name);
+}
+
+/**
+ * @brief Compare test functions' names
+ */
+static int test_function_cmp(struct test_function *a, struct test_function *b)
+{
+ return strcoll(a->name, b->name);
+}
+
+/**
+ * @brief Compare test bindings' names
+ */
+static int test_binding_cmp(struct test_binding *a, struct test_binding *b)
+{
+ return strcoll(a->name, b->name);
+}
+
+/**
+ * @brief Compare test configs' names
+ */
+static int test_config_cmp(struct test_config *a, struct test_config *b)
+{
+ return strcoll(a->name, b->name);
+}
+
+void prepare_binding(struct test_binding *b, struct test_function *f, char *fpath)
+{
+ if (!f->name)
+ prepare_function(f, fpath);
+
+ if (!b->name) {
+ b->name = strdup(f->name);
+ if (b->name == NULL)
+ fail();
+ free_later(b->name);
+ }
+
+ b->target = f;
+}
+
+void prepare_config(struct test_config *c, char *cpath, char *fpath)
+{
+ int count = 0;
+ struct test_function *f;
+ struct test_binding *b;
+ int i;
+
+ safe_asprintf(&c->name, "%s.%d", c->label, c->id);
+
+ c->path = cpath;
+
+ /* check if bindings has been already filled */
+ if (!c->bindings) {
+ for (f = c->bound_funcs; f->instance; f++)
+ count++;
+
+ c->bindings = safe_calloc(count + 1, sizeof(*c->bindings));
+ } else {
+ for (b = c->bindings; b->name; b++)
+ count++;
+ }
+
+ for (i = 0; i < count; i++)
+ prepare_binding(&c->bindings[i], &c->bound_funcs[i], fpath);
+
+ qsort(c->bindings, count, sizeof(*c->bindings),
+ (int (*)(const void *, const void *))test_binding_cmp);
+
+}
+
+void prepare_function(struct test_function *f, char *path)
+{
+ const char *func_type;
+
+ func_type = usbg_get_function_type_str(f->type);
+ if (func_type == NULL)
+ fail();
+
+ safe_asprintf(&f->name, "%s.%s", func_type, f->instance);
+
+ f->path = path;
+}
+
+void prepare_gadget(struct test_state *state, struct test_gadget *g)
+{
+ struct test_config *c;
+ struct test_function *f;
+ char *fpath;
+ char *cpath;
+ int count;
+
+ g->path = strdup(state->path);
+ if (!g->path)
+ fail();
+
+ free_later(g->path);
+
+ safe_asprintf(&fpath, "%s/%s/functions", g->path, g->name);
+
+ count = 0;
+ for (f = g->functions; f->instance; f++) {
+ prepare_function(f, fpath);
+ count++;
+ }
+
+ /* Path needs to be known somehow when list is empty */
+ f->path = fpath;
+
+ qsort(g->functions, count, sizeof(*g->functions),
+ (int (*)(const void *, const void *))test_function_cmp);
+
+ safe_asprintf(&cpath, "%s/%s/configs", g->path, g->name);
+
+ count = 0;
+ for (c = g->configs; c->label; c++) {
+ prepare_config(c, cpath, fpath);
+ count++;
+ }
+
+ /* Path needs to be known somehow when list is empty */
+ c->path = cpath;
+
+ qsort(g->configs, count, sizeof(*g->configs),
+ (int (*)(const void *, const void *))test_config_cmp);
+
+}
+
+static void cpy_test_function(struct test_function *to,
+ struct test_function *from)
+{
+ /* Reuse instance */
+ to->instance = from->instance;
+ to->type = from->type;
+ /* path and name is not being copied because
+ it has not been allocated now */
+
+ to->writable = 1;
+}
+
+static struct test_function *dup_test_functions(struct test_function *functions)
+{
+ struct test_function *f, *nf, *new_functions;
+ int count = 0;
+
+ for (f = functions; f->instance; ++f)
+ ++count;
+
+ new_functions = safe_calloc(count + 1, sizeof(*f));
+
+ for (f = functions, nf = new_functions; f->instance; ++f, ++nf)
+ cpy_test_function(nf, f);
+
+ return new_functions;
+}
+
+static struct test_function *get_new_binding_target(struct test_function *which,
+ struct test_function *old,
+ int count,
+ struct test_function *new)
+{
+ struct test_function *ret = NULL;
+
+ /* Should duplicate function? */
+ if (which < old || ((which - old) > count)) {
+ /* We may need to do a deep copy */
+ if (!which->writable) {
+ ret = safe_calloc(1, sizeof(*ret));
+ cpy_test_function(ret, which);
+ } else {
+ ret = which;
+ }
+ } else if (old != new) {
+ /* Function has been copied in bound_funcs so just
+ set new address */
+ ret = which - old + new;
+ } else {
+ /* Functions are reused so leave address as is */
+ ret = which;
+ }
+
+ return ret;
+}
+
+static void cpy_test_binding(struct test_binding *to,
+ struct test_binding *from,
+ struct test_function *old,
+ int func_count,
+ struct test_function *new)
+{
+ /* Reuse name */
+ to->name = from->name;
+ to->target = get_new_binding_target(from->target, old, func_count, new);
+
+ to->writable = 1;
+}
+
+static struct test_binding *dup_test_bindings(struct test_binding *bindings,
+ struct test_function *old,
+ int func_count,
+ struct test_function *new)
+{
+ struct test_binding *b, *nb, *new_bindings;
+ int count = 0;
+
+ for (b = bindings; b->name; ++b)
+ ++count;
+
+ new_bindings = safe_calloc(count + 1, sizeof(*b));
+
+ for (b = bindings, nb = new_bindings; b->name; ++b, ++nb)
+ cpy_test_binding(nb, b, old, func_count, new);
+
+ return new_bindings;
+}
+
+static void cpy_test_config(struct test_config *to,
+ struct test_config *from)
+{
+ int func_count = 0;
+ struct test_function *f;
+ struct test_binding *b;
+
+ /* Reuse label */
+ to->label = from->label;
+ to->id = from->id;
+ to->strs = from->strs;
+ to->attrs = from->attrs;
+
+ if (from->bound_funcs) {
+ /* If at least one function is not writable
+ we have to copy all of them */
+ for (f = from->bound_funcs; f->instance; ++f) {
+ ++func_count;
+ if (!f->writable && !to->bound_funcs) {
+ to->bound_funcs =
+ dup_test_functions(from->bound_funcs);
+ }
+ }
+
+ if (!f->name && !to->bound_funcs)
+ to->bound_funcs = from->bound_funcs;
+ }
+
+ /* If bindings are set copy also them */
+ if (from->bindings) {
+ /* If at least one function is not writable
+ we have to copy all of them */
+ for (b = from->bindings; b->name; ++b)
+ if (!b->writable)
+ to->bindings =
+ dup_test_bindings(from->bindings,
+ from->bound_funcs,
+ func_count,
+ to->bound_funcs);
+
+ /* if we are reusing binding we have to translate target
+ address to new one which is writable */
+ if (!b->name && !to->bindings) {
+ to->bindings = from->bindings;
+ for (b = from->bindings; b->name; ++b)
+ b->target =
+ get_new_binding_target(
+ b->target,
+ from->bound_funcs,
+ func_count,
+ to->bound_funcs);
+ }
+ }
+
+ to->writable = 1;
+}
+
+static struct test_config *dup_test_configs(struct test_config *configs)
+{
+ struct test_config *c, *nc, *new_configs;
+ int count = 0;
+
+ for (c = configs; c->label; ++c)
+ ++count;
+
+ new_configs = safe_calloc(count + 1, sizeof(*c));
+
+ for (c = configs, nc = new_configs; c->label; ++c, ++nc)
+ cpy_test_config(nc, c);
+
+ return new_configs;
+}
+
+static void cpy_test_gadget(struct test_gadget *to, struct test_gadget *from)
+{
+ struct test_function *f;
+ struct test_config *c;
+
+ /* Reuse name and udc */
+ to->name = from->name;
+ to->udc = from->udc;
+ /* path is not being copied because it has not been allocated */
+
+ /* If at least one function is not writable
+ we have to copy all of them */
+ for (f = from->functions; f->instance; ++f)
+ if (!f->writable) {
+ to->functions =
+ dup_test_functions(from->functions);
+ break;
+ }
+
+ if (!f->name && !to->functions)
+ to->functions = from->functions;
+
+
+ /* If at least one config is not writable
+ we have to copy all of them */
+ for (c = from->configs; c->label; ++c)
+ if (!c->writable) {
+ to->configs = dup_test_configs(from->configs);
+ break;
+ }
+
+ if (!c->name && !to->configs)
+ to->configs = from->configs;
+
+ to->writable = 1;
+}
+
+static struct test_gadget *dup_test_gadgets(struct test_gadget *gadgets)
+{
+ struct test_gadget *g, *ng, *new_gadgets;
+ int count = 0;
+
+ for (g = gadgets; g->name; ++g)
+ ++count;
+
+ new_gadgets = safe_calloc(count + 1, sizeof(*g));
+
+ for (g = gadgets, ng = new_gadgets; g->name; ++g, ++ng)
+ cpy_test_gadget(ng, g);
+
+ return new_gadgets;
+}
+
+static struct test_state *dup_test_state(struct test_state *state)
+{
+ struct test_state *new_state;
+ struct test_gadget *g;
+
+ new_state = safe_calloc(1, sizeof(*new_state));
+
+ /* We don't copy configfs path because it is never changed
+ if you would like to free it before test end replace
+ this code with strdup */
+ new_state->configfs_path = state->configfs_path;
+
+ /* path is not being copied because it has not been allocated */
+
+ /* If at least one gadget is not writable we have to copy all of them */
+ for (g = state->gadgets; g->name; ++g)
+ if (!g->writable) {
+ new_state->gadgets =
+ dup_test_gadgets(state->gadgets);
+ break;
+ }
+
+ if (!g->name && !new_state->gadgets)
+ new_state->gadgets = state->gadgets;
+
+ /* udcs are also never changed so leave them as they are */
+ new_state->udcs = state->udcs;
+
+ new_state->writable = 1;
+
+ return new_state;
+}
+
+struct test_state *prepare_state(struct test_state *state)
+{
+ struct test_gadget *g;
+ struct test_state *new_state;
+ int count = 0;
+
+ if (!state->writable)
+ new_state = dup_test_state(state);
+ else
+ new_state = state;
+
+ safe_asprintf(&(new_state->path), "%s/usb_gadget",
+ new_state->configfs_path);
+
+ for (g = new_state->gadgets; g->name; g++) {
+ prepare_gadget(new_state, g);
+ count++;
+ }
+
+ qsort(new_state->gadgets, count, sizeof(*new_state->gadgets),
+ (int (*)(const void *, const void *))test_gadget_cmp);
+
+ return new_state;
+}
+
+struct test_state *build_empty_gadget_state(struct test_state *ts)
+{
+ struct test_state *ret;
+ struct test_gadget *tg;
+ int count = 0;
+
+ ret = safe_malloc(sizeof(*ret));
+ ret->udcs = ts->udcs;
+ ret->configfs_path = ts->configfs_path;
+
+ for (tg = ts->gadgets; tg->name; ++tg)
+ count++;
+
+ ret->gadgets = safe_calloc(count+1, sizeof(*ts->gadgets));
+ memcpy(ret->gadgets, ts->gadgets, count*sizeof(*ts->gadgets));
+
+ for (tg = ret->gadgets; tg->name; ++tg) {
+ tg->configs = safe_calloc(1, sizeof(*tg->configs));
+ tg->functions = safe_calloc(1, sizeof(*tg->functions));
+ }
+
+ return prepare_state(ret);
+}
+
+/* Simulation of configfs for init */
+
+static void push_binding(struct test_config *conf, struct test_binding *binding)
+{
+ char *s_path;
+ char *d_path;
+
+ safe_asprintf(&s_path, "%s/%s/%s", conf->path, conf->name, binding->name);
+ safe_asprintf(&d_path, "%s/%s", binding->target->path, binding->target->name);
+
+ PUSH_LINK(s_path, d_path, USBG_MAX_PATH_LENGTH - 1);
+}
+
+static void push_config(struct test_config *c)
+{
+ struct test_binding *b;
+ int count = 0;
+ char *path;
+
+ safe_asprintf(&path, "%s/%s", c->path, c->name);
+
+ for (b = c->bindings; b->name; b++)
+ count++;
+
+ PUSH_DIR(path, count);
+ for (b = c->bindings; b->name; b++) {
+ PUSH_DIR_ENTRY(b->name, DT_LNK);
+ push_binding(c, b);
+ }
+}
+
+static void push_gadget(struct test_gadget *g)
+{
+ int count;
+ struct test_config *c;
+ struct test_function *f;
+ char *path;
+
+ safe_asprintf(&path, "%s/%s/UDC", g->path, g->name);
+ PUSH_FILE(path, g->udc);
+
+ count = 0;
+ for (f = g->functions; f->instance; f++)
+ count++;
+
+ PUSH_DIR(f->path, count);
+ for (f = g->functions; f->instance; f++)
+ PUSH_DIR_ENTRY(f->name, DT_DIR);
+
+ count = 0;
+ for (c = g->configs; c->label; c++)
+ count++;
+
+ PUSH_DIR(c->path, count);
+ for (c = g->configs; c->label; c++)
+ PUSH_DIR_ENTRY(c->name, DT_DIR);
+
+ for (c = g->configs; c->label; c++)
+ push_config(c);
+}
+
+void push_init(struct test_state *state)
+{
+ char **udc;
+ struct test_gadget *g;
+ int count = 0;
+
+ EXPECT_OPENDIR(state->path);
+
+ for (udc = state->udcs; *udc; udc++)
+ count++;
+
+ PUSH_DIR("/sys/class/udc", count);
+ for (udc = state->udcs; *udc; udc++)
+ PUSH_DIR_ENTRY(*udc, DT_REG);
+
+ count = 0;
+ for (g = state->gadgets; g->name; g++)
+ count++;
+
+ PUSH_DIR(state->path, count);
+ for (g = state->gadgets; g->name; g++) {
+ PUSH_DIR_ENTRY(g->name, DT_DIR);
+ }
+
+ for (g = state->gadgets; g->name; g++)
+ push_gadget(g);
+}
+
+int get_gadget_attr(usbg_gadget_attrs *attrs, usbg_gadget_attr attr)
+{
+ int ret = -1;
+
+ switch (attr) {
+ case BCD_USB:
+ ret = attrs->bcdUSB;
+ break;
+ case B_DEVICE_CLASS:
+ ret = attrs->bDeviceClass;
+ break;
+ case B_DEVICE_SUB_CLASS:
+ ret = attrs->bDeviceSubClass;
+ break;
+ case B_DEVICE_PROTOCOL:
+ ret = attrs->bDeviceProtocol;
+ break;
+ case B_MAX_PACKET_SIZE_0:
+ ret = attrs->bMaxPacketSize0;
+ break;
+ case ID_VENDOR:
+ ret = attrs->idVendor;
+ break;
+ case ID_PRODUCT:
+ ret = attrs->idProduct;
+ break;
+ case BCD_DEVICE:
+ ret = attrs->bcdDevice;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+void pull_gadget_attribute(struct test_gadget *gadget,
+ usbg_gadget_attr attr, int value)
+{
+ char *path;
+ char *content;
+
+ safe_asprintf(&path, "%s/%s/%s",
+ gadget->path, gadget->name, usbg_get_gadget_attr_str(attr));
+
+ safe_asprintf(&content, "0x%x\n", value);
+
+ EXPECT_HEX_WRITE(path, content);
+}
+
+void push_gadget_attribute(struct test_gadget *gadget,
+ usbg_gadget_attr attr, int value)
+{
+ char *path;
+ char *content;
+
+ safe_asprintf(&path, "%s/%s/%s",
+ gadget->path, gadget->name, usbg_get_gadget_attr_str(attr));
+ safe_asprintf(&content, "0x%x\n", value);
+
+ PUSH_FILE(path, content);
+}
+
+void push_gadget_attrs(struct test_gadget *gadget, usbg_gadget_attrs *attrs)
+{
+ int i;
+
+ for (i = USBG_GADGET_ATTR_MIN; i < USBG_GADGET_ATTR_MAX; i++)
+ push_gadget_attribute(gadget, i, get_gadget_attr(attrs, i));
+}
+
+void pull_gadget_attrs(struct test_gadget *gadget, usbg_gadget_attrs *attrs)
+{
+ int i;
+
+ for (i = USBG_GADGET_ATTR_MIN; i < USBG_GADGET_ATTR_MAX; i++)
+ pull_gadget_attribute(gadget, i, get_gadget_attr(attrs, i));
+}
+
+void init_with_state(struct test_state *in, usbg_state **out)
+{
+ int usbg_ret;
+
+ push_init(in);
+ usbg_ret = usbg_init(in->configfs_path, out);
+ assert_int_equal(usbg_ret, USBG_SUCCESS);
+}
+
+void safe_init_with_state(void **state, struct test_state **ts, usbg_state **s)
+{
+ *ts = (struct test_state *)(*state);
+ *state = NULL;
+
+ init_with_state(*ts, s);
+ *state = *s;
+}
+
+static int get_config_attr(usbg_config_attrs *attrs, config_attr attr)
+{
+ int ret;
+
+ switch (attr) {
+ case MAX_POWER:
+ ret = attrs->bMaxPower;
+ break;
+ case BM_ATTRIBUTES:
+ ret = attrs->bmAttributes;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+void push_config_attribute(struct test_config *config, config_attr attr,
+ int value)
+{
+ char *path;
+ char *content;
+
+ safe_asprintf(&path, "%s/%s/%s", config->path, config->name, config_attr_names[attr]);
+
+ switch (config_attr_format[attr]) {
+ case FORMAT_HEX:
+ safe_asprintf(&content, "0x%x\n", value);
+ break;
+ case FORMAT_DEC:
+ safe_asprintf(&content, "%d\n", value);
+ break;
+ }
+
+ PUSH_FILE(path, content);
+}
+
+
+void push_config_attrs(struct test_config *config, usbg_config_attrs *attrs)
+{
+ int i;
+
+ for (i = 0; i < CONFIG_ATTR_MAX; ++i)
+ push_config_attribute(config, i, get_config_attr(attrs, i));
+}
+
+void pull_config_attribute(struct test_config *config, config_attr attr,
+ int value)
+{
+ char *path;
+ char *content;
+
+ safe_asprintf(&path, "%s/%s/%s", config->path, config->name, config_attr_names[attr]);
+
+ switch (config_attr_format[attr]) {
+ case FORMAT_HEX:
+ safe_asprintf(&content, "0x%x\n", value);
+ break;
+ case FORMAT_DEC:
+ safe_asprintf(&content, "%d\n", value);
+ break;
+ }
+
+ switch (config_attr_format[attr]) {
+ case FORMAT_HEX:
+ EXPECT_HEX_WRITE(path, content);
+ break;
+ case FORMAT_DEC:
+ EXPECT_WRITE(path, content);
+ break;
+ }
+}
+
+void pull_config_attrs(struct test_config *config, usbg_config_attrs *attrs)
+{
+ int i;
+
+ for (i = 0; i < CONFIG_ATTR_MAX; ++i)
+ pull_config_attribute(config, i, get_config_attr(attrs, i));
+}
+
+const char *get_gadget_str(usbg_gadget_strs *strs, gadget_str str)
+{
+ const char *ret = NULL;
+
+ switch (str) {
+ case STR_SER:
+ ret = strs->str_ser;
+ break;
+ case STR_MNF:
+ ret = strs->str_mnf;
+ break;
+ case STR_PRD:
+ ret = strs->str_prd;
+ break;
+ default:
+ ret = NULL;
+ break;
+ }
+
+ return ret;
+}
+
+static void pull_gadget_str_dir(struct test_gadget *gadget, int lang)
+{
+ char *dir;
+ int tmp;
+
+ safe_asprintf(&dir, "%s/%s/strings/0x%x",
+ gadget->path, gadget->name, lang);
+
+ srand(time(NULL));
+ tmp = rand() % 2;
+
+ if (tmp) {
+ EXPECT_OPENDIR(dir);
+ } else {
+ EXPECT_OPENDIR_ERROR(dir, ENOENT);
+ EXPECT_MKDIR(dir);
+ }
+}
+
+static void pull_gadget_str(struct test_gadget *gadget, const char *attr_name,
+ int lang, const char *content)
+{
+ char *path;
+
+ safe_asprintf(&path, "%s/%s/strings/0x%x/%s",
+ gadget->path, gadget->name, lang, attr_name);
+ EXPECT_WRITE(path, content);
+}
+
+void pull_gadget_string(struct test_gadget *gadget, int lang,
+ gadget_str str, const char *content)
+{
+ pull_gadget_str_dir(gadget, lang);
+ pull_gadget_str(gadget, gadget_str_names[str], lang, content);
+}
+
+void pull_gadget_strs(struct test_gadget *gadget, int lang, usbg_gadget_strs *strs)
+{
+ int i;
+
+ pull_gadget_str_dir(gadget, lang);
+ for (i = 0; i < GADGET_STR_MAX; i++)
+ pull_gadget_str(gadget, gadget_str_names[i], lang, get_gadget_str(strs, i));
+}
+
+static void push_gadget_str_dir(struct test_gadget *gadget, int lang)
+{
+ char *dir;
+
+ safe_asprintf(&dir, "%s/%s/strings/0x%x",
+ gadget->path, gadget->name, lang);
+
+ EXPECT_OPENDIR(dir);
+}
+
+static void push_gadget_str(struct test_gadget *gadget, const char *attr_name,
+ int lang, const char *content)
+{
+ char *path;
+
+ safe_asprintf(&path, "%s/%s/strings/0x%x/%s",
+ gadget->path, gadget->name, lang, attr_name);
+ PUSH_FILE(path, content);
+}
+
+void push_gadget_strs(struct test_gadget *gadget, int lang, usbg_gadget_strs *strs)
+{
+ int i;
+
+ push_gadget_str_dir(gadget, lang);
+ for (i = 0; i < GADGET_STR_MAX; i++)
+ push_gadget_str(gadget, gadget_str_names[i], lang, get_gadget_str(strs, i));
+}
+
+void pull_config_string(struct test_config *config, int lang, const char *str)
+{
+ char *path;
+ int tmp;
+
+
+ safe_asprintf(&path, "%s/%s/strings/0x%x",
+ config->path, config->name, lang);
+
+ srand(time(NULL));
+ tmp = rand() % 2;
+
+ if (tmp) {
+ EXPECT_OPENDIR(path);
+ } else {
+ EXPECT_OPENDIR_ERROR(path, ENOENT);
+ EXPECT_MKDIR(path);
+ }
+
+ safe_asprintf(&path, "%s/configuration", path);
+
+ EXPECT_WRITE(path, str);
+}
+
+void pull_config_strs(struct test_config *config, int lang, usbg_config_strs *strs)
+{
+ pull_config_string(config, lang, strs->configuration);
+}
+
+void push_config_string(struct test_config *config, int lang, const char *str)
+{
+ char *path;
+
+ safe_asprintf(&path, "%s/%s/strings/0x%x",
+ config->path, config->name, lang);
+
+ EXPECT_OPENDIR(path);
+
+ safe_asprintf(&path, "%s/configuration", path);
+
+ PUSH_FILE(path, str);
+}
+
+void push_config_strs(struct test_config *config, int lang, usbg_config_strs *strs)
+{
+ push_config_string(config, lang, strs->configuration);
+}
+
+void assert_config_attrs_equal(usbg_config_attrs *actual, usbg_config_attrs *expected)
+{
+ assert_int_equal(actual->bmAttributes, expected->bmAttributes);
+ assert_int_equal(actual->bMaxPower, expected->bMaxPower);
+}
+
+void pull_create_config(struct test_config *tc)
+{
+ char *path;
+
+ safe_asprintf(&path, "%s/%s", tc->path, tc->name);
+ EXPECT_MKDIR(path);
+
+ if (tc->attrs)
+ pull_config_attrs(tc, tc->attrs);
+ if (tc->strs)
+ pull_config_strs(tc, LANG_US_ENG, tc->strs);
+}
+
+#define ETHER_ADDR_STR_LEN 19
+
+static void push_serial_attrs(struct test_function *func,
+ usbg_f_serial_attrs *attrs)
+{
+ char *path;
+ char *content;
+
+ safe_asprintf(&path, "%s/%s/port_num", func->path, func->name);
+ safe_asprintf(&content, "%d\n", attrs->port_num);
+ PUSH_FILE(path, content);
+}
+
+static void push_net_attrs(struct test_function *func,
+ usbg_f_net_attrs *attrs)
+{
+ char *path;
+ char *content;
+
+ safe_asprintf(&path, "%s/%s/dev_addr", func->path, func->name);
+
+ content = safe_malloc(ETHER_ADDR_STR_LEN * sizeof(char));
+ ether_ntoa_r(&attrs->dev_addr, content);
+
+ PUSH_FILE(path, content);
+
+ path = safe_malloc(USBG_MAX_PATH_LENGTH * sizeof(char));
+ sprintf(path, "%s/%s/host_addr",
+ func->path, func->name);
+
+ content = safe_malloc(ETHER_ADDR_STR_LEN * sizeof(char));
+ ether_ntoa_r(&attrs->host_addr, content);
+
+ PUSH_FILE(path, content);
+
+ safe_asprintf(&path, "%s/%s/qmult", func->path, func->name);
+ safe_asprintf(&content, "%d\n", attrs->qmult);
+ PUSH_FILE(path, content);
+
+ safe_asprintf(&path, "%s/%s/ifname", func->path, func->name);
+ safe_asprintf(&content, "%s\n", attrs->ifname);
+ PUSH_FILE(path, content);
+}
+
+static void push_phonet_attrs(struct test_function *func,
+ usbg_f_phonet_attrs *attrs)
+{
+ char *path;
+ char *content;
+
+ safe_asprintf(&path, "%s/%s/ifname", func->path, func->name);
+ safe_asprintf(&content, "%s\n", attrs->ifname);
+ PUSH_FILE(path, content);
+}
+
+void push_function_attrs(struct test_function *func, usbg_function_attrs *function_attrs)
+{
+ int attrs_type;
+ usbg_f_attrs *attrs = &function_attrs->attrs;
+
+ attrs_type = usbg_lookup_function_attrs_type(func->type);
+
+ switch (attrs_type) {
+ case USBG_F_ATTRS_SERIAL:
+ push_serial_attrs(func, &attrs->serial);
+ break;
+ case USBG_F_ATTRS_NET:
+ push_net_attrs(func, &attrs->net);
+ break;
+ case USBG_F_ATTRS_PHONET:
+ push_phonet_attrs(func, &attrs->phonet);
+ break;
+ case USBG_F_ATTRS_FFS:
+ // ffs does not exist in filesystem
+ default:
+ break;
+ }
+}
+
+static void pull_function_net_attrs(struct test_function *func, usbg_f_net_attrs *attrs)
+{
+ char *path;
+ char *content;
+
+ safe_asprintf(&path, "%s/%s/dev_addr", func->path, func->name);
+
+ content = safe_malloc(ETHER_ADDR_STR_LEN * sizeof(char));
+ usbg_ether_ntoa_r(&attrs->dev_addr, content);
+
+ EXPECT_WRITE(path, content);
+
+ safe_asprintf(&path, "%s/%s/host_addr", func->path, func->name);
+
+ content = safe_malloc(ETHER_ADDR_STR_LEN * sizeof(char));
+ usbg_ether_ntoa_r(&attrs->host_addr, content);
+
+ EXPECT_WRITE(path, content);
+
+ safe_asprintf(&path, "%s/%s/qmult", func->path, func->name);
+ safe_asprintf(&content, "%d\n", attrs->qmult);
+ EXPECT_WRITE(path, content);
+}
+
+void pull_function_attrs(struct test_function *func, usbg_function_attrs *attrs)
+{
+ /* only net attributes are writtable */
+ if (attrs->header.attrs_type == USBG_F_ATTRS_NET)
+ pull_function_net_attrs(func, &attrs->attrs.net);
+}
+
+void pull_create_function(struct test_function *tf)
+{
+ char *path;
+ int tmp;
+
+ tmp = asprintf(&path, "%s/%s", tf->path, tf->name);
+ if (tmp < 0)
+ fail();
+ free_later(path);
+
+ EXPECT_MKDIR(path);
+ if (tf->attrs)
+ pull_function_attrs(tf, tf->attrs);
+}
+
+void assert_func_equal(usbg_function *f, struct test_function *expected)
+{
+ assert_string_equal(f->instance, expected->instance);
+ assert_int_equal(f->type, expected->type);
+ assert_path_equal(f->path, expected->path);
+}
+
+void assert_binding_equal(usbg_binding *b, struct test_binding *expected)
+{
+ assert_string_equal(b->name, expected->name);
+ assert_func_equal(b->target, expected->target);
+}
+
+void assert_config_equal(usbg_config *c, struct test_config *expected)
+{
+ int i = 0;
+ usbg_binding *b;
+
+ assert_int_equal(c->id, expected->id);
+ assert_string_equal(c->label, expected->label);
+ assert_path_equal(c->path, expected->path);
+ usbg_for_each_binding(b, c)
+ assert_binding_equal(b, &expected->bindings[i++]);
+}
+
+void assert_gadget_equal(usbg_gadget *g, struct test_gadget *expected)
+{
+ usbg_config *c;
+ usbg_function *f;
+ int i;
+
+ assert_string_equal(g->name, expected->name);
+ assert_path_equal(g->path, expected->path);
+
+ i = 0;
+ usbg_for_each_function(f, g)
+ assert_func_equal(f, &expected->functions[i++]);
+
+ i = 0;
+ usbg_for_each_config(c, g)
+ assert_config_equal(c, &expected->configs[i++]);
+}
+
+void assert_state_equal(usbg_state *s, struct test_state *expected)
+{
+ usbg_gadget *g;
+ int i = 0;
+
+ assert_path_equal(s->path, expected->path);
+ assert_path_equal(s->configfs_path, expected->configfs_path);
+
+ usbg_for_each_gadget(g, s)
+ assert_gadget_equal(g, &expected->gadgets[i++]);
+}
+
+#define SIGNUM(x) (((x) > 0) - ((x) < 0))
+
+int path_cmp(const char *actual, const char *expected)
+{
+ const char *a = actual;
+ const char *b = expected;
+
+ while (*a != '\0' && *b != '\0') {
+ if (*a != *b)
+ break;
+ do
+ ++a;
+ while (*a == '/');
+
+ do
+ ++b;
+ while (*b == '/');
+ }
+
+ return SIGNUM(*a - *b);
+}
+
+int path_equal_display_error(const LargestIntegralType actual, const LargestIntegralType expected)
+{
+ if (path_cmp((const char *)actual, (const char *)expected) == 0) {
+ return 1;
+ }
+
+ fprintf(stderr, "%s != %s\n", (const char *)actual, (const char *)expected);
+ return 0;
+}
+
+void assert_path_equal(const char *actual, const char *expected)
+{
+ if (path_equal_display_error(
+ cast_to_largest_integral_type(actual),
+ cast_to_largest_integral_type(expected)) == 0)
+ fail();
+}
+
+int hex_str_cmp(const char *actual, const char *expected)
+{
+ int a, b;
+
+ sscanf(actual, "%x", &a);
+ sscanf(expected, "%x", &b);
+
+ return SIGNUM(a - b);
+}
+
+int hex_str_equal_display_error(const LargestIntegralType actual, const LargestIntegralType expected)
+{
+ if (hex_str_cmp((const char *)actual, (const char *)expected) == 0) {
+ return 1;
+ }
+
+ fprintf(stderr, "%s != %s\n", (const char *)actual, (const char *)expected);
+ return 0;
+}
+
+void assert_gadget_attrs_equal(usbg_gadget_attrs *actual,
+ usbg_gadget_attrs *expected)
+{
+ int i;
+
+ for (i = USBG_GADGET_ATTR_MIN; i < USBG_GADGET_ATTR_MAX; i++)
+ assert_int_equal(get_gadget_attr(actual, i), get_gadget_attr(expected, i));
+}
+
+void assert_gadget_strs_equal(usbg_gadget_strs *actual, usbg_gadget_strs *expected)
+{
+ int i;
+ for (i = 0; i < GADGET_STR_MAX; i++)
+ assert_string_equal(get_gadget_str(actual, i), get_gadget_str(expected, i));
+}
+
+void assert_f_serial_attrs_equal(usbg_f_serial_attrs *actual,
+ usbg_f_serial_attrs *expected)
+{
+ assert_int_equal(actual->port_num, expected->port_num);
+}
+
+static void assert_ether_addrs_equal(const struct ether_addr *ea1,
+ const struct ether_addr *ea2)
+{
+ assert_memory_equal(ea1->ether_addr_octet, ea2->ether_addr_octet,
+ ETHER_ADDR_LEN);
+}
+
+void assert_f_net_attrs_equal(usbg_f_net_attrs *actual, usbg_f_net_attrs *expected)
+{
+ assert_ether_addrs_equal(&actual->dev_addr, &expected->dev_addr);
+ assert_ether_addrs_equal(&actual->host_addr, &expected->host_addr);
+ assert_string_equal(actual->ifname, expected->ifname);
+ assert_int_equal(actual->qmult, expected->qmult);
+}
+
+void assert_f_phonet_attrs_equal(usbg_f_phonet_attrs *actual,
+ usbg_f_phonet_attrs *expected)
+{
+ assert_string_equal(actual->ifname, expected->ifname);
+}
+
+void assert_f_ffs_attrs_equal(usbg_f_ffs_attrs *actual, usbg_f_ffs_attrs *expected)
+{
+ assert_string_equal(actual->dev_name, expected->dev_name);
+}
+
+void assert_function_attrs_equal(usbg_function_attrs *actual,
+ usbg_function_attrs *expected, usbg_f_attrs_type type)
+{
+ switch (type) {
+ case USBG_F_ATTRS_SERIAL:
+ assert_f_serial_attrs_equal(&actual->attrs.serial, &expected->attrs.serial);
+ break;
+ case USBG_F_ATTRS_NET:
+ assert_f_net_attrs_equal(&actual->attrs.net, &expected->attrs.net);
+ break;
+ case USBG_F_ATTRS_PHONET:
+ assert_f_phonet_attrs_equal(&actual->attrs.phonet, &expected->attrs.phonet);
+ break;
+ case USBG_F_ATTRS_FFS:
+ assert_f_ffs_attrs_equal(&actual->attrs.ffs, &expected->attrs.ffs);
+ break;
+ default:
+ fail();
+ }
+}
+
+
+void for_each_test_function(struct test_state *ts, usbg_state *s, FunctionTest fun)
+{
+ struct test_gadget *tg;
+ struct test_function *tf;
+ usbg_gadget *g = NULL;
+ usbg_function *f = NULL;
+
+ for (tg = ts->gadgets; tg->name; ++tg) {
+ g = usbg_get_gadget(s, tg->name);
+ assert_non_null(g);
+ for (tf = tg->functions; tf->instance; ++tf) {
+ f = usbg_get_function(g, tf->type, tf->instance);
+ fun(f, tf);
+ }
+ }
+}
+
+void for_each_test_config(struct test_state *ts, usbg_state *s, ConfigTest fun)
+{
+ usbg_gadget *g = NULL;
+ usbg_config *c = NULL;
+ struct test_gadget *tg;
+ struct test_config *tc;
+
+ for (tg = ts->gadgets; tg->name; tg++) {
+ g = usbg_get_gadget(s, tg->name);
+ assert_non_null(g);
+ for (tc = tg->configs; tc->label; tc++) {
+ c = usbg_get_config(g, tc->id, tc->label);
+ fun(c, tc);
+ }
+ }
+}
+
+void for_each_binding(struct test_state *ts, usbg_state *s, BindingTestFunc fun)
+{
+ struct test_gadget *tg;
+ struct test_config *tc;
+ struct test_binding *tb;
+ usbg_gadget *g = NULL;
+ usbg_config *c = NULL;
+ usbg_binding *b = NULL;
+
+ for (tg = ts->gadgets; tg->name; tg++) {
+ g = usbg_get_gadget(s, tg->name);
+ assert_non_null(g);
+ for (tc = tg->configs; tc->label; tc++) {
+ c = usbg_get_config(g, tc->id, tc->label);
+ assert_non_null(c);
+
+ b = usbg_get_first_binding(c);
+ for (tb = tc->bindings; tb->name; ++tb) {
+ assert_non_null(b);
+ fun(tb, b);
+ b = usbg_get_next_binding(b);
+ }
+ }
+ }
+}
+
+void for_each_test_gadget(struct test_state *ts, usbg_state *s, GadgetTestFunc fun)
+{
+ struct test_gadget *tg;
+ usbg_gadget *g = NULL;
+
+ for (tg = ts->gadgets; tg->name; ++tg) {
+ g = usbg_get_gadget(s, tg->name);
+ assert_non_null(g);
+ fun(g, tg);
+ }
+}
diff --git a/tests/usbg-test.h b/tests/usbg-test.h
new file mode 100644
index 0000000..127b90e
--- /dev/null
+++ b/tests/usbg-test.h
@@ -0,0 +1,549 @@
+#ifndef USBG_TEST_H
+#define USBG_TEST_H
+
+#include <usbg/usbg.h>
+#include <sys/queue.h>
+#include "usbg/usbg_internal.h"
+
+/* Simple structures for defining gadgets. All arrays should be null-terminated.*/
+
+/**
+ * @file tests/usbg-test.h
+ */
+
+struct test_function
+{
+ usbg_function_type type;
+ char *instance;
+
+ char *path;
+ char *name;
+ usbg_function_attrs *attrs;
+ int writable;
+};
+
+struct test_binding
+{
+ struct test_function *target;
+ char *name;
+ int writable;
+};
+
+struct test_config
+{
+ char *label;
+ int id;
+ struct test_function *bound_funcs;
+
+ struct test_binding *bindings;
+ char *path;
+ char *name;
+ int writable;
+ usbg_config_strs *strs;
+ usbg_config_attrs *attrs;
+};
+
+struct test_gadget
+{
+ char *name;
+ char *udc;
+ struct test_config *configs;
+ struct test_function *functions;
+
+ char *path;
+ int writable;
+};
+
+struct test_state
+{
+ char *configfs_path;
+ /* filled by prepare_state() */
+ char *path;
+ struct test_gadget *gadgets;
+ char **udcs;
+ int writable;
+};
+
+typedef enum {
+ STR_SER = 0,
+ STR_MNF,
+ STR_PRD,
+ GADGET_STR_MAX
+} gadget_str;
+
+typedef enum {
+ MAX_POWER = 0,
+ BM_ATTRIBUTES,
+ CONFIG_ATTR_MAX
+} config_attr;
+
+typedef enum {
+ FORMAT_HEX,
+ FORMAT_DEC
+} attr_format;
+
+#define TEST_FUNCTION_LIST_END { \
+ .instance = NULL, \
+ }
+
+#define TEST_CONFIG_LIST_END { \
+ .label = NULL, \
+ .bindings = NULL, \
+ }
+
+#define TEST_GADGET_LIST_END { \
+ .name = NULL, \
+ .udc = NULL, \
+ .configs = NULL, \
+ .functions = NULL, \
+ }
+
+#define expect_path(function, param, data) \
+ expect_check(function, param, \
+ (CheckParameterValue)(path_equal_display_error), data)
+
+/**
+ * @brief Prepare given state for using in tests
+ * @details Generate full pathes to state elements and sort state's content.
+ * Must be called before pasing state to push_* and pull_* functions.
+ * @param[in] state State schema used to genrate test state
+ * @return Pointer to state which can be used for testing. Returned value is
+ * equal to #state if writable attribute has been set to 1 or pointer
+ * to newly allocated test_state filled with suitable values. All memory
+ * allocated in this function is scheduled to free using free_later().
+ */
+struct test_state *prepare_state(struct test_state *state);
+
+/**
+ * @brief Prepare given config for using in tests
+ * @details Generate required pathes for given config and sort content
+ * (i.e. binding list)
+ * @param[in] c Config to be filled out
+ * @param[in] cpath Path to configs directory
+ * @param[in] fpath Path to functions directory
+ */
+void prepare_config(struct test_config *c, char *cpath, char *fpath);
+
+/**
+ * @brief Prepare given function for using in tests
+ * @details Generate required pathes for given function
+ * @param[in] f Function to be filled out
+ * @param[in] path Path to functions directory
+ */
+void prepare_function(struct test_function *f, char *path);
+
+/**
+ * @brief Prepare given gadget for using in tests
+ * @details Generate required paths for given gadget and sort it's content
+ * (i.e. functions list and config list)
+ * @param[in] state Pointer to gadget's parent state
+ * @param[in] g Gadget to be filled out
+ */
+void prepare_gadget(struct test_state *state, struct test_gadget *g);
+
+/**
+ * @brief Fill given binding with required values
+ * @details Make given binding point to a function
+ * @param[in] b Test binding to be prepared
+ * @param[in] f Function to which binding will point
+ * @param[in] fpath Path to functions directory
+ */
+void prepare_binding(struct test_binding *b, struct test_function *f, char *fpath);
+
+/**
+ * @brief Prepare fake filesystem to init usbg with given test state
+ * @details Use wrapped i/o functions to simulate configfs state for usbg.
+ * Calling usbg_init without preparation and with mocked i/o functions
+ * may fail.
+ * @param[in] state Fake state of configfs defined in test
+ */
+void push_init(struct test_state *state);
+
+/**
+ * Prepare specific attributes writting/reading
+ **/
+
+/**
+ * @brief Prepare for getting config attributes
+ * @param[in] config Configuration from which attributes will be get
+ * @param[in] attrs Attributes which will be present in virtual filesystem
+ */
+void push_config_attrs(struct test_config *config, usbg_config_attrs *attrs);
+
+/**
+ * @brief Preapre for setting config attributes
+ * @param[in] config Configuration on which attributes will be set
+ * @param[in] attrs Attributes which will be set on given config
+ */
+void pull_config_attrs(struct test_config *config, usbg_config_attrs *attrs);
+
+/**
+ * @brief Get gadget attribute
+ * @param[in] attrs
+ * @param[in] attr
+ */
+int get_gadget_attr(usbg_gadget_attrs *attrs, usbg_gadget_attr attr);
+
+/**
+ * @brief Prepare to write given attribute by libusbg
+ * @param[in] gadget Test gadget related to given attribute
+ * @param[in] attr Attribute
+ * @param[in] value Attributes value
+ **/
+void push_gadget_attribute(struct test_gadget *gadget,
+ usbg_gadget_attr attr, int value);
+
+/**
+ * @brief Prepare to read given attribute by libusbg
+ * @param[in] gadget Test gadget related to given attribute
+ * @param[in] attr Attribute
+ * @param[in] value Attributes value
+ **/
+void pull_gadget_attribute(struct test_gadget *gadget,
+ usbg_gadget_attr attr, int value);
+
+/**
+ * @brief Prepare fake filesystem to get given gadget attributes
+ * @details Prepare queue of values passed to wrapped i/o functions,
+ * all values got from given attributes structure.
+ * @param[in] gadget Pointer to gadget
+ * @param[in] attrs Pointer to attributes which gadget should have
+ * @warning Calling usbg_get_gadget_attrs function whithout this
+ * preparation and with wrapped i/o may fail.
+ */
+void push_gadget_attrs(struct test_gadget *gadget, usbg_gadget_attrs *attrs);
+
+/**
+ * @brief Prepare fake filesystem for attributes setting attempt.
+ * @details Prepare queue of values passed to wrapped i/o functions,
+ * corresponding to functions called on attributes setting
+ * @param[in] gadget Pointer to gadget
+ * @param[in] attrs Pointer to expected attributes
+ * @warning Calling usbg_get_gadget_attrs function whithout this
+ * preparation and with wrapped i/o may fail.
+ */
+void pull_gadget_attrs(struct test_gadget *gadget, usbg_gadget_attrs *attrs);
+
+/**
+ * @brief Prepare fake filesystem to get given function attributes
+ * @details Prepare queue of values passed to wrapped i/o functions,
+ * all values got from given attributes structure.
+ * @warning Calling usbg_get_function_attrs function whithout this
+ * preparation and with wrapped i/o may fail.
+ */
+void push_function_attrs(struct test_function *func, usbg_function_attrs *attrs);
+
+/**
+ * @brief Prepare fake filesystem to set given function attributes
+ * @details Prepare queue of values passed to wrapped i/o functions,
+ * all values got from given attributes structure.
+ * @warning Calling usbg_set_function_attrs function whithout this
+ * preparation and with wrapped i/o may fail.
+ */
+void pull_function_attrs(struct test_function *func, usbg_function_attrs *attrs);
+
+/**
+ * @brief Get gadget string
+ * @param[in] strs Set of gadget strings
+ * @param[in] str Identifier of string which should be returned
+ * @return Selected string from given set of strings
+ */
+const char *get_gadget_str(usbg_gadget_strs *strs, gadget_str str);
+
+/**
+ * @brief Prepare filesystem to set selected gadget string
+ * @param[in] gadget Gadget on which str will be set
+ * @param[in] lang Language of string
+ * @param[in] str String identifier
+ * @param[in] content String expected to be set
+ */
+void pull_gadget_string(struct test_gadget *gadget, int lang,
+ gadget_str str, const char *content);
+
+/**
+ * @brief Prepare filesystem to set given gadget strings
+ * @param[in] gadget Gadget on which strings will be set
+ * @param[in] lang Language of strings
+ * @param[in] strs Strings expected to be set
+ */
+void pull_gadget_strs(struct test_gadget *gadget, int lang, usbg_gadget_strs *strs);
+
+/**
+ * @brief prepare for reading gadget's strings
+ */
+void push_gadget_strs(struct test_gadget *gadget, int lang, usbg_gadget_strs *strs);
+
+/**
+ * @brief Prepare for /ref usbg_set_config_string calling
+ * @details Expect setting the same string as given one
+ * @param[in] config on which strings will be set
+ * @param[in] lang Language of strings
+ * @param[in] str string to be set as configuration string
+ */
+void pull_config_string(struct test_config *config, int lang, const char *str);
+
+/**
+ * @brief Prepare for writting given config strings
+ * @param[in] config on which strings will be set
+ * @param[in] lang Language of strings
+ * @param[in] strs Strings expected to be set
+ */
+void pull_config_strs(struct test_config *config, int lang, usbg_config_strs *strs);
+
+/**
+ * @brief Prepare for /ref usbg_get_config_string calling
+ * @details Expect setting the same string as given one
+ * @param[in] config from which strings will be get
+ * @param[in] lang Language of strings
+ * @param[in] str string which should be returned as configuration string
+ */
+void push_config_string(struct test_config *config, int lang, const char *str);
+
+/**
+ * @brief Prepare for reading config strings
+ * @param[in] config from which strings will be get
+ * @param[in] lang Language of strings
+ * @param[in] strs Strings which should be returned
+ */
+void push_config_strs(struct test_config *config, int lang, usbg_config_strs *strs);
+
+/**
+ * @brief Prepare for creating config
+ * @param[in] tc Test config to be created
+ */
+void pull_create_config(struct test_config *tc);
+
+/**
+ * @brief Prepare for creating function
+ * @param[in] tf Test function to be created
+ */
+void pull_create_function(struct test_function *tf);
+
+/**
+ * @brief Copy state without configs and functions
+ * @param[in] ts State to bo copied
+ * @return State with empty gadgets
+ */
+struct test_state *build_empty_gadget_state(struct test_state *ts);
+
+/**
+ * @brief Store given pointer on cleanup stack
+ * @details All stacked pointers will be freed by calling cleanup_queue.
+ * This can be used to manage memory needed for single test casees.
+ */
+void free_later(void *ptr);
+
+/**
+ * @brief Cleans up memory no longer needed
+ * @details Frees all pointer stored on cleanup stack by calling free_later
+ * @warning Calling this function before end of single test usually make test state
+ * unusable. Use it only when you no longer need allocated data (at the end of
+ * test case, in most cases)
+ */
+void cleanup_stack();
+
+/**
+ * @brief init usbg with given test state
+ */
+void init_with_state(struct test_state *in, usbg_state **out);
+
+/**
+ * @brief Safely initialize usbg state from pointer given to test
+ * @param[in] state Pointer given to test function
+ * @param[out] ts Pointer to be filled with test state
+ * @param[out] s Pointer to be filled with usbg state
+ */
+void safe_init_with_state(void **state, struct test_state **ts, usbg_state **s);
+
+/**
+ * @brief Assert that given config attributes are equal
+ */
+void assert_config_attrs_equal(usbg_config_attrs *actual, usbg_config_attrs *expected);
+
+/**
+ * @brief Assert that given usbg binding matches given test binding
+ * @param[in] f Pointer to usbg binding struct
+ * @param[in] expected Pointer to test binding struct with expected values
+ */
+void assert_binding_equal(usbg_binding *b, struct test_binding *expected);
+
+/**
+ * @brief Assert that given usbg function matches given test function
+ * @param[in] f Pointer to usbg function struct
+ * @param[in] expected Pointer to test function struct with expected values
+ */
+void assert_func_equal(usbg_function *f, struct test_function *expected);
+
+/**
+ * @brief Assert that given usbg config matches given test config
+ * @param[in] c Pointer to usbg config struct
+ * @param[in] expected Pointer to test config struct with expected values
+ */
+void assert_config_equal(usbg_config *c, struct test_config *expected);
+
+/**
+ * @brief Assert that given usbg gadget matches given test gadget
+ * @param[in] g Pointer to usbg gadget struct
+ * @param[in] expected Pointer to test gadget struct with expected values
+ */
+void assert_gadget_equal(usbg_gadget *g, struct test_gadget *expected);
+
+/**
+ * @brief Assert that given usbg state matches given test state
+ * @param[in] s Pointer to usbg state struct
+ * @param[in] expected Pointer to test state struct with expected values
+ */
+void assert_state_equal(usbg_state *s, struct test_state *expected);
+
+/**
+ * @brief Compare path names
+ * @details Given pathes don't need to exist
+ * @return Integer less than, equal to, or greater than zero if a is (respectively)
+ * less than, equal to, or greater than b.
+ */
+int path_cmp(const char *a, const char *b);
+
+/**
+ * @brief Print error when given paths are not equal
+ * @return 1 if paths are equal, 0 otherwise
+ * @note Argument type is defined by cmocka. This specific function type is defined
+ * as custom comparing function in cmocka framework.
+ */
+int path_equal_display_error(const LargestIntegralType actual, const LargestIntegralType expected);
+
+/**
+ * @brief Compare attributes (as strings)
+ * @return Integer less than, equal to, or greater than zero if a is (respectively)
+ * less than, equal to, or greater than b.
+ */
+int hex_str_cmp(const char *actual, const char *expected);
+
+/**
+ * @brief Print error when given attributes are not equal
+ * @return 1 if attributes are equal, 0 otherwise
+ * @note Argument type is defined by cmocka. This specific function type is defined
+ * as custom comparing function in cmocka framework.
+ */
+int hex_str_equal_display_error(const LargestIntegralType actual, const LargestIntegralType expected);
+
+/**
+ * @brief Assert that given path strings are equal
+ * @details Given pathes don't need to exist
+ */
+void assert_path_equal(const char *actual, const char *expected);
+
+/**
+ * @brief Assert that given usbg gadget attributes sets are equal
+ * @param[in] actual Pointer to actual gadget attributes structure
+ * @param[in] expected Pointer to expeced gadget attributes structure
+ */
+void assert_gadget_attrs_equal(usbg_gadget_attrs *actual,
+ usbg_gadget_attrs *expected);
+
+/**
+ * @brief Assert that given function attributes are the same.
+ * @param[in] actual Pointer to actual attributes object
+ * @param[in] expected Pointer to expected attributes obejct
+ * @param[in] type Type of function, which attributes are checked
+ */
+void assert_function_attrs_equal(usbg_function_attrs *actual,
+ usbg_function_attrs *expected, usbg_f_attrs_type type);
+
+/**
+ * @brief Assert that given gadget strings are equal
+ */
+void assert_gadget_strs_equal(usbg_gadget_strs *actual, usbg_gadget_strs *expected);
+
+/**
+ * @brief Function that performs some test on given usbg function
+*/
+typedef void (*FunctionTest)(usbg_function *f, struct test_function *tf);
+
+/**
+ * @brief Call given function for all usb functions present in given state
+ * @param[in] ts Test state to be tested
+ * @param[in] s Properly prepared usbg state to be tested
+ * @param[in] fun Function to be called on each usb function in state
+ */
+void for_each_test_function(struct test_state *ts, usbg_state *s, FunctionTest fun);
+
+/**
+ * @brief Function that performs some test on given usbg config
+*/
+typedef void (*ConfigTest)(usbg_config *c, struct test_config *tc);
+
+/**
+ * @brief Call given function for all usb configs present in given state
+ * @param[in] ts Test state to be tested
+ * @param[in] s Properly prepared usbg state to be tested
+ * @param[in] fun Function to be called on each usb function in state
+ */
+void for_each_test_config(struct test_state *ts, usbg_state *s, ConfigTest fun);
+
+/**
+ * @brief Function that performs test on given usbg binding
+ */
+typedef void (*BindingTestFunc)(struct test_binding *tb, usbg_binding *b);
+
+/**
+ * @brief Call given function for all usb bindings present in given state
+ * @param[in] ts Test state to be tested
+ * @param[in] s Properly prepared usbg state to be tested
+ * @param[in] fun Function to be called on each usb binding in state
+ */
+void for_each_binding(struct test_state *ts, usbg_state *s, BindingTestFunc fun);
+
+/**
+ * @brief Function that performs test on given usbg gadget
+ */
+typedef void (*GadgetTestFunc)(usbg_gadget *g, struct test_gadget *tg);
+
+/**
+ * @brief Call given function for all usb gadgets present in given state
+ * @param[in] ts Test state to be tested
+ * @param[in] s Properly prepared usbg state to be tested
+ * @param[in] fun Function to be called on each usb gadget in state
+ */
+void for_each_test_gadget(struct test_state *ts, usbg_state *s, GadgetTestFunc fun);
+
+static inline void *safe_calloc(int count, size_t size)
+{
+ void *ptr;
+
+ ptr = calloc(count, size);
+ if (ptr == NULL)
+ fail();
+
+ free_later(ptr);
+ return ptr;
+}
+
+static inline void *safe_malloc(size_t size)
+{
+ void *ptr;
+
+ ptr = malloc(size);
+ if (ptr == NULL)
+ fail();
+
+ free_later(ptr);
+ return ptr;
+}
+
+static inline int safe_asprintf(char **ptr, const char *fmt, ...)
+{
+ va_list args;
+ int ret;
+
+ va_start(args, fmt);
+ ret = vasprintf(ptr, fmt, args);
+ va_end(args);
+
+ if (ret < 0)
+ fail();
+
+ free_later(*ptr);
+ return ret;
+}
+
+#endif /* USBG_TEST_H */