dm: Add basic tests
Add some tests of driver model functionality. Coverage includes: - basic init - binding of drivers to devices using platform_data - automatic probing of devices when referenced - availability of platform data to devices - lifecycle from bind to probe to remove to unbind - renumbering within a uclass when devices are probed/removed - calling driver-defined operations - deactivation of drivers when removed - memory leak across creation and destruction of drivers/uclasses - uclass init/destroy methods - automatic probe/remove of children/parents when needed This function is enabled for sandbox, using CONFIG_DM_TEST. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#define CONFIG_BOOTSTAGE
|
||||
#define CONFIG_BOOTSTAGE_REPORT
|
||||
#define CONFIG_DM
|
||||
#define CONFIG_DM_TEST
|
||||
|
||||
/* Number of bits in a C 'long' on this architecture */
|
||||
#define CONFIG_SANDBOX_BITS_PER_LONG 64
|
||||
|
||||
167
include/dm/test.h
Normal file
167
include/dm/test.h
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 2013 Google, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __DM_TEST_H
|
||||
#define __DM_TEST_H
|
||||
|
||||
#include <dm.h>
|
||||
|
||||
/**
|
||||
* struct dm_test_cdata - configuration data for test instance
|
||||
*
|
||||
* @ping_add: Amonut to add each time we get a ping
|
||||
* @base: Base address of this device
|
||||
*/
|
||||
struct dm_test_pdata {
|
||||
int ping_add;
|
||||
uint32_t base;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct test_ops - Operations supported by the test device
|
||||
*
|
||||
* @ping: Ping operation
|
||||
* @dev: Device to operate on
|
||||
* @pingval: Value to ping the device with
|
||||
* @pingret: Returns resulting value from driver
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
struct test_ops {
|
||||
int (*ping)(struct device *dev, int pingval, int *pingret);
|
||||
};
|
||||
|
||||
/* Operations that our test driver supports */
|
||||
enum {
|
||||
DM_TEST_OP_BIND = 0,
|
||||
DM_TEST_OP_UNBIND,
|
||||
DM_TEST_OP_PROBE,
|
||||
DM_TEST_OP_REMOVE,
|
||||
|
||||
/* For uclass */
|
||||
DM_TEST_OP_POST_BIND,
|
||||
DM_TEST_OP_PRE_UNBIND,
|
||||
DM_TEST_OP_POST_PROBE,
|
||||
DM_TEST_OP_PRE_REMOVE,
|
||||
DM_TEST_OP_INIT,
|
||||
DM_TEST_OP_DESTROY,
|
||||
|
||||
DM_TEST_OP_COUNT,
|
||||
};
|
||||
|
||||
/* Test driver types */
|
||||
enum {
|
||||
DM_TEST_TYPE_FIRST = 0,
|
||||
DM_TEST_TYPE_SECOND,
|
||||
};
|
||||
|
||||
/* The number added to the ping total on each probe */
|
||||
#define DM_TEST_START_TOTAL 5
|
||||
|
||||
/**
|
||||
* struct dm_test_priv - private data for the test devices
|
||||
*/
|
||||
struct dm_test_priv {
|
||||
int ping_total;
|
||||
int op_count[DM_TEST_OP_COUNT];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dm_test_perdev_class_priv - private per-device data for test uclass
|
||||
*/
|
||||
struct dm_test_uclass_perdev_priv {
|
||||
int base_add;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dm_test_uclass_priv - private data for test uclass
|
||||
*/
|
||||
struct dm_test_uclass_priv {
|
||||
int total_add;
|
||||
};
|
||||
|
||||
/*
|
||||
* Operation counts for the test driver, used to check that each method is
|
||||
* called correctly
|
||||
*/
|
||||
extern int dm_testdrv_op_count[DM_TEST_OP_COUNT];
|
||||
|
||||
extern struct dm_test_state global_test_state;
|
||||
|
||||
/*
|
||||
* struct dm_test_state - Entire state of dm test system
|
||||
*
|
||||
* This is often abreviated to dms.
|
||||
*
|
||||
* @root: Root device
|
||||
* @testdev: Test device
|
||||
* @fail_count: Number of tests that failed
|
||||
* @force_fail_alloc: Force all memory allocs to fail
|
||||
* @skip_post_probe: Skip uclass post-probe processing
|
||||
*/
|
||||
struct dm_test_state {
|
||||
struct device *root;
|
||||
struct device *testdev;
|
||||
int fail_count;
|
||||
int force_fail_alloc;
|
||||
int skip_post_probe;
|
||||
};
|
||||
|
||||
/* Test flags for each test */
|
||||
enum {
|
||||
DM_TESTF_SCAN_PDATA = 1 << 0, /* test needs platform data */
|
||||
DM_TESTF_PROBE_TEST = 1 << 1, /* probe test uclass */
|
||||
DM_TESTF_SCAN_FDT = 1 << 2, /* scan device tree */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dm_test - Information about a driver model test
|
||||
*
|
||||
* @name: Name of test
|
||||
* @func: Function to call to perform test
|
||||
* @flags: Flags indicated pre-conditions for test
|
||||
*/
|
||||
struct dm_test {
|
||||
const char *name;
|
||||
int (*func)(struct dm_test_state *dms);
|
||||
int flags;
|
||||
};
|
||||
|
||||
/* Declare a new driver model test */
|
||||
#define DM_TEST(_name, _flags) \
|
||||
ll_entry_declare(struct dm_test, _name, dm_test) = { \
|
||||
.name = #_name, \
|
||||
.flags = _flags, \
|
||||
.func = _name, \
|
||||
}
|
||||
|
||||
/* Declare ping methods for the drivers */
|
||||
int test_ping(struct device *dev, int pingval, int *pingret);
|
||||
int testfdt_ping(struct device *dev, int pingval, int *pingret);
|
||||
|
||||
/**
|
||||
* dm_check_operations() - Check that we can perform ping operations
|
||||
*
|
||||
* This checks that the ping operations work as expected for a device
|
||||
*
|
||||
* @dms: Overall test state
|
||||
* @dev: Device to test
|
||||
* @base: Base address, used to check ping return value
|
||||
* @priv: Pointer to private test information
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int dm_check_operations(struct dm_test_state *dms, struct device *dev,
|
||||
uint32_t base, struct dm_test_priv *priv);
|
||||
|
||||
/**
|
||||
* dm_test_main() - Run all the tests
|
||||
*
|
||||
* This runs all available driver model tests
|
||||
*
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int dm_test_main(void);
|
||||
|
||||
#endif
|
||||
95
include/dm/ut.h
Normal file
95
include/dm/ut.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Simple unit test library for driver model
|
||||
*
|
||||
* Copyright (c) 2013 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __DM_UT_H
|
||||
#define __DM_UT_H
|
||||
|
||||
struct dm_test_state;
|
||||
|
||||
/**
|
||||
* ut_fail() - Record failure of a unit test
|
||||
*
|
||||
* @dms: Test state
|
||||
* @fname: Filename where the error occured
|
||||
* @line: Line number where the error occured
|
||||
* @func: Function name where the error occured
|
||||
* @cond: The condition that failed
|
||||
*/
|
||||
void ut_fail(struct dm_test_state *dms, const char *fname, int line,
|
||||
const char *func, const char *cond);
|
||||
|
||||
/**
|
||||
* ut_failf() - Record failure of a unit test
|
||||
*
|
||||
* @dms: Test state
|
||||
* @fname: Filename where the error occured
|
||||
* @line: Line number where the error occured
|
||||
* @func: Function name where the error occured
|
||||
* @cond: The condition that failed
|
||||
* @fmt: printf() format string for the error, followed by args
|
||||
*/
|
||||
void ut_failf(struct dm_test_state *dms, const char *fname, int line,
|
||||
const char *func, const char *cond, const char *fmt, ...)
|
||||
__attribute__ ((format (__printf__, 6, 7)));
|
||||
|
||||
|
||||
/* Assert that a condition is non-zero */
|
||||
#define ut_assert(cond) \
|
||||
if (!(cond)) { \
|
||||
ut_fail(dms, __FILE__, __LINE__, __func__, #cond); \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
/* Assert that a condition is non-zero, with printf() string */
|
||||
#define ut_assertf(cond, fmt, args...) \
|
||||
if (!(cond)) { \
|
||||
ut_failf(dms, __FILE__, __LINE__, __func__, #cond, \
|
||||
fmt, ##args); \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
/* Assert that two int expressions are equal */
|
||||
#define ut_asserteq(expr1, expr2) { \
|
||||
unsigned int val1 = (expr1), val2 = (expr2); \
|
||||
\
|
||||
if (val1 != val2) { \
|
||||
ut_failf(dms, __FILE__, __LINE__, __func__, \
|
||||
#expr1 " == " #expr2, \
|
||||
"Expected %d, got %d", val1, val2); \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Assert that two string expressions are equal */
|
||||
#define ut_asserteq_str(expr1, expr2) { \
|
||||
const char *val1 = (expr1), *val2 = (expr2); \
|
||||
\
|
||||
if (strcmp(val1, val2)) { \
|
||||
ut_failf(dms, __FILE__, __LINE__, __func__, \
|
||||
#expr1 " = " #expr2, \
|
||||
"Expected \"%s\", got \"%s\"", val1, val2); \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Assert that two pointers are equal */
|
||||
#define ut_asserteq_ptr(expr1, expr2) { \
|
||||
const void *val1 = (expr1), *val2 = (expr2); \
|
||||
\
|
||||
if (val1 != val2) { \
|
||||
ut_failf(dms, __FILE__, __LINE__, __func__, \
|
||||
#expr1 " = " #expr2, \
|
||||
"Expected %p, got %p", val1, val2); \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Assert that an operation succeeds (returns 0) */
|
||||
#define ut_assertok(cond) ut_asserteq(0, cond)
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user