| <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> |
| <html><head> |
| <title>cmocka</title> |
| </head> |
| <body> |
| <h1>cmocka Unit Testing Framework</h1> |
| <p>cmocka is a lightweight library that is used to author C unit tests.</p> |
| |
| <ul>Contents |
| <li><a href="#Motivation">Motivation</a></li> |
| <li><a href="#Overview">Overview</a></li> |
| <li><a href="#Test_Execution">Test Execution</a> |
| <li><a href="#Exception_Handling">Exception Handling</a></li> |
| <li><a href="#Failure_Conditions">Failure Conditions</a></li> |
| <li><a href="#Assertions">Assertions</a></li> |
| <ul> |
| <li><a href="#Assert_Macros">Assert Macros</a></li> |
| </ul> |
| <li><a href="#Dynamic_Memory_Allocation">Dynamic Memory Allocation</a></li> |
| <li><a href="#Mock_Functions">Mock functions</a></li> |
| <ul> |
| <li><a href="#Return_Values">Return Values</a></li> |
| <li><a href="#Checking_Parameters">Checking Parameters</a></li> |
| </ul> |
| <li><a href="#Test_State">Test State</a></li> |
| <li><a href="#Example">Example</a></li> |
| </ul> |
| |
| <a name="Motivation"><h2>Motivation</h2></a> |
| <p>There are a variety of C unit testing frameworks available however many of |
| them are fairly complex and require the latest compiler technology. Some |
| development requires the use of old compilers which makes it difficult to |
| use some unit testing frameworks. In addition many unit testing frameworks |
| assume the code being tested is an application or module that is targeted to |
| the same platform that will ultimately execute the test. Because of this |
| assumption many frameworks require the inclusion of standard C library headers |
| in the code module being tested which may collide with the custom or |
| incomplete implementation of the C library utilized by the code under test.</p> |
| |
| <p>cmocka only requires a test application is linked with the standard C |
| library which minimizes conflicts with standard C library headers. Also, |
| cmocka tries avoid the use of some of the newer features of C compilers.</p> |
| |
| <p>This results in cmocka being a relatively small library that can be used |
| to test a variety of exotic code. If a developer wishes to simply test an |
| application with the latest compiler then other unit testing frameworks maybe |
| preferable.</p> |
| |
| <a name="Overview"><h2>Overview</h2></a> |
| <p>cmocka tests are compiled into stand-alone executables and linked with |
| the cmocka library, the standard C library and module being tested. Any |
| symbols external to the module being tested should be mocked - replaced with |
| functions that return values determined by the test - within the test |
| application. Even though significant differences may exist between the target |
| execution environment of a code module and the environment used to test the |
| code the unit testing is still valid since its goal is to test the logic of a |
| code modules at a functional level and not necessarily all of its interactions |
| with the target execution environment.</p> |
| |
| <p>It may not be possible to compile a module into a test application without |
| some modification, therefore the preprocessor symbol <b>UNIT_TESTING</b> should |
| be defined when cmocka unit test applications are compiled so code within the |
| module can be conditionally compiled for tests.</p> |
| |
| <a name="Test_Execution"><h2>Test Execution</h2></a> |
| <p>cmocka unit test cases are functions with the signature |
| <b>void function(void **state)</b>. cmocka test applications initialize a |
| table with test case function pointers using <b>unit_test*()</b> macros. This |
| table is then passed to the <b>run_tests()</b> macro to execute the tests. |
| |
| <b>run_tests()</b> sets up the appropriate exception / signal handlers and |
| other data structures prior to running each test function. When a unit test |
| is complete <b>run_tests()</b> performs various checks to determine whether |
| the test succeeded.</p> |
| |
| <h4>Using run_tests()</h4> |
| <a href="../example/run_tests.c">run_tests.c</a> |
| <listing> |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include <setjmp.h> |
| #include <cmocka.h> |
| |
| // A test case that does nothing and succeeds. |
| void null_test_success(void **state) { |
| } |
| |
| int main(int argc, char* argv[]) { |
| const UnitTest tests[] = { |
| unit_test(null_test_success), |
| }; |
| return run_tests(tests); |
| } |
| </listing> |
| |
| <a name="Exception_Handling"><h2>Exception Handling</h2></a> |
| <p>Before a test function is executed by <b>run_tests()</b>, |
| exception / signal handlers are overridden with a handler that simply |
| displays an error and exits a test function if an exception occurs. If an |
| exception occurs outside of a test function, for example in cmocka itself, |
| the application aborts execution and returns an error code.</p> |
| |
| <a name="Failure_Conditions"><h2>Failure Conditions</h2></a> |
| <p>If a failure occurs during a test function that's executed via |
| <b>run_tests()</b>, the test function is aborted and the application's |
| execution resumes with the next test function. |
| |
| Test failures are ultimately signalled via the cmocka function <b>fail()</b>. |
| The following events will result in the cmocka library signalling a test |
| failure... |
| |
| <ul> |
| <li><a href="#Assertions">Assertions</a></li> |
| <li><a href="#Exception_Handling">Exceptions</a></li> |
| <li><a href="#Dynamic_Memory_Allocation">Memory leaks</a></li> |
| <li><a href="#Test_State">Mismatched setup and tear down functions</a></li> |
| <li><a href="#Return_Values">Missing mock return values</a></li> |
| <li><a href="#Return_Values">Unused mock return values</a></li> |
| <li><a href="#Checking_Parameters">Missing expected parameter values</a></li> |
| <li><a href="#Checking_Parameters">Unused expected parameter values</a></li> |
| </ul> |
| </p> |
| |
| <a name="Assertions"><h2>Assertions</h2></a> |
| <p>Runtime assert macros like the standard C library's <b>assert()</b> should |
| be redefined in modules being tested to use cmocka's <b>mock_assert()</b> |
| function. Normally <b>mock_assert()</b> signals a |
| <a href="#Failure_Conditions">test failure</a>. If a function is called using |
| the <b>expect_assert_failure()</b> macro, any calls to <b>mock_assert()</b> |
| within the function will result in the execution of the test. If no |
| calls to <b>mock_assert()</b> occur during the function called via |
| <b>expect_assert_failure()</b> a test failure is signalled.</p> |
| |
| <h4>Using mock_assert()</h4> |
| <a href="../example/assert_module.c">assert_module.c</a> |
| <listing> |
| #include <assert.h> |
| |
| // If unit testing is enabled override assert with mock_assert(). |
| #if UNIT_TESTING |
| extern void mock_assert(const int result, const char* const expression, |
| const char * const file, const int line); |
| #undef assert |
| #define assert(expression) \ |
| mock_assert((int)(expression), #expression, __FILE__, __LINE__); |
| #endif // UNIT_TESTING |
| |
| void increment_value(int * const value) { |
| assert(value); |
| (*value) ++; |
| } |
| |
| void decrement_value(int * const value) { |
| if (value) { |
| *value --; |
| } |
| } |
| </listing> |
| <a href="../example/assert_module_test.c">assert_module_test.c</a> |
| <listing> |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include <setjmp.h> |
| #include <cmocka.h> |
| |
| extern void increment_value(int * const value); |
| |
| /* This test case will fail but the assert is caught by run_tests() and the |
| * next test is executed. */ |
| void increment_value_fail(void **state) { |
| increment_value(NULL); |
| } |
| |
| // This test case succeeds since increment_value() asserts on the NULL pointer. |
| void increment_value_assert(void **state) { |
| expect_assert_failure(increment_value(NULL)); |
| } |
| |
| /* This test case fails since decrement_value() doesn't assert on a NULL |
| * pointer. */ |
| void decrement_value_fail(void **state) { |
| expect_assert_failure(decrement_value(NULL)); |
| } |
| |
| int main(int argc, char *argv[]) { |
| const UnitTest tests[] = { |
| unit_test(increment_value_fail), |
| unit_test(increment_value_assert), |
| unit_test(decrement_value_fail), |
| }; |
| return run_tests(tests); |
| } |
| </listing> |
| |
| <h3><a name="Assert_Macros">Assert Macros</a></h3> |
| |
| <p>cmocka provides an assortment of assert macros that tests applications |
| should use use in preference to the C standard library's assert macro. On an |
| assertion failure a cmocka assert macro will write the failure to the |
| standard error stream and signal a test failure. Due to limitations of the |
| C language the general C standard library assert() and cmocka's |
| assert_true() and assert_false() macros can only display the expression that |
| caused the assert failure. cmocka's type specific assert macros, |
| assert_{type}_equal() and assert_{type}_not_equal(), display the data that |
| caused the assertion failure which increases data visibility aiding |
| debugging of failing test cases.</p> |
| |
| <h4>Using assert_{type}_equal() macros</h4> |
| <a href="../example/assert_macro.c">assert_macro.c</a> |
| <listing> |
| #include <string.h> |
| |
| static const char* status_code_strings[] = { |
| "Address not found", |
| "Connection dropped", |
| "Connection timed out", |
| }; |
| |
| const char* get_status_code_string(const unsigned int status_code) { |
| return status_code_strings[status_code]; |
| }; |
| |
| unsigned int string_to_status_code(const char* const status_code_string) { |
| unsigned int i; |
| for (i = 0; i < sizeof(status_code_strings) / |
| sizeof(status_code_strings[0]); i++) { |
| if (strcmp(status_code_strings[i], status_code_string) == 0) { |
| return i; |
| } |
| } |
| return ~0U; |
| } |
| </listing> |
| <a href="../example/assert_macro_test.c">assert_macro_test.c</a> |
| <listing> |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include <setjmp.h> |
| #include <cmocka.h> |
| |
| extern const char* get_status_code_string(const unsigned int status_code); |
| extern unsigned int string_to_status_code( |
| const char* const status_code_string); |
| |
| /* This test will fail since the string returned by get_status_code_string(0) |
| * doesn't match "Connection timed out". */ |
| void get_status_code_string_test(void **state) { |
| assert_string_equal(get_status_code_string(0), "Address not found"); |
| assert_string_equal(get_status_code_string(1), "Connection timed out"); |
| } |
| |
| // This test will fail since the status code of "Connection timed out" isn't 1 |
| void string_to_status_code_test(void **state) { |
| assert_int_equal(string_to_status_code("Address not found"), 0); |
| assert_int_equal(string_to_status_code("Connection timed out"), 1); |
| } |
| |
| int main(int argc, char *argv[]) { |
| const UnitTest tests[] = { |
| unit_test(get_status_code_string_test), |
| unit_test(string_to_status_code_test), |
| }; |
| return run_tests(tests); |
| } |
| </listing> |
| |
| <a name="Dynamic_Memory_Allocation"><h2>Dynamic Memory Allocation</h2></a> |
| |
| <p>To test for memory leaks, buffer overflows and underflows a module being |
| tested by cmocka should replace calls to <b>malloc()</b>, <b>calloc()</b> and |
| <b>free()</b> to <b>test_malloc()</b>, <b>test_calloc()</b> and |
| <b>test_free()</b> respectively. Each time a block is deallocated using |
| <b>test_free()</b> it is checked for corruption, if a corrupt block is found |
| a <a href="#Failure_Conditions">test failure</a> is signalled. All blocks |
| allocated using the <b>test_*()</b> allocation functions are tracked by the |
| cmocka library. When a test completes if any allocated blocks (memory leaks) |
| remain they are reported and a test failure is signalled.</p> |
| <p>For simplicity cmocka currently executes all tests in one process. |
| Therefore all test cases in a test application share a single address space |
| which means memory corruption from a single test case could potentially cause |
| the test application to exit prematurely.</p> |
| |
| <h4>Using cmocka's Allocators</h4> |
| <a href="../example/allocate_module.c">allocate_module.c</a> |
| <listing> |
| #include <malloc.h> |
| |
| #if UNIT_TESTING |
| extern void* _test_malloc(const size_t size, const char* file, const int line); |
| extern void* _test_calloc(const size_t number_of_elements, const size_t size, |
| const char* file, const int line); |
| extern void _test_free(void* const ptr, const char* file, const int line); |
| |
| #define malloc(size) _test_malloc(size, __FILE__, __LINE__) |
| #define calloc(num, size) _test_calloc(num, size, __FILE__, __LINE__) |
| #define free(ptr) _test_free(ptr, __FILE__, __LINE__) |
| #endif // UNIT_TESTING |
| |
| void leak_memory() { |
| int * const temporary = (int*)malloc(sizeof(int)); |
| *temporary = 0; |
| } |
| |
| void buffer_overflow() { |
| char * const memory = (char*)malloc(sizeof(int)); |
| memory[sizeof(int)] = '!'; |
| free(memory); |
| } |
| |
| void buffer_underflow() { |
| char * const memory = (char*)malloc(sizeof(int)); |
| memory[-1] = '!'; |
| free(memory); |
| } |
| </listing> |
| <a href="../example/allocate_module_test.c">allocate_module_test.c</a> |
| <listing> |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include <setjmp.h> |
| #include <cmocka.h> |
| |
| extern void leak_memory(); |
| extern void buffer_overflow(); |
| extern void buffer_underflow(); |
| |
| // Test case that fails as leak_memory() leaks a dynamically allocated block. |
| void leak_memory_test(void **state) { |
| leak_memory(); |
| } |
| |
| // Test case that fails as buffer_overflow() corrupts an allocated block. |
| void buffer_overflow_test(void **state) { |
| buffer_overflow(); |
| } |
| |
| // Test case that fails as buffer_underflow() corrupts an allocated block. |
| void buffer_underflow_test(void **state) { |
| buffer_underflow(); |
| } |
| |
| int main(int argc, char* argv[]) { |
| const UnitTest tests[] = { |
| unit_test(leak_memory_test), |
| unit_test(buffer_overflow_test), |
| unit_test(buffer_underflow_test), |
| }; |
| return run_tests(tests); |
| } |
| </listing> |
| |
| <a name="Mock_Functions"><h2>Mock Functions</h2></a> |
| |
| <p>A unit test should ideally isolate the function or module being tested |
| from any external dependencies. This can be performed using mock functions |
| that are either statically or dynamically linked with the module being tested. |
| Mock functions must be statically linked when the code being tested directly |
| references external functions. Dynamic linking is simply the process of |
| setting a function pointer in a table used by the tested module to reference |
| a mock function defined in the unit test.</p> |
| |
| <a name="Return_Values"><h3>Return Values</h3></a> |
| |
| <p>In order to simplify the implementation of mock functions cmocka provides |
| functionality which stores return values for mock functions in each test |
| case using <b>will_return()</b>. These values are then returned by each mock |
| function using calls to <b>mock()</b>. |
| |
| Values passed to <b>will_return()</b> are added to a queue for each function |
| specified. Each successive call to <b>mock()</b> from a function removes a |
| return value from the queue. This makes it possible for a mock function to use |
| multiple calls to <b>mock()</b> to return output parameters in addition to a |
| return value. In addition this allows the specification of return values for |
| multiple calls to a mock function.</p> |
| |
| <h4>Using will_return()</h4> |
| <a href="../example/database.h">database.h</a> |
| <listing> |
| typedef struct DatabaseConnection DatabaseConnection; |
| |
| /* Function that takes an SQL query string and sets results to an array of |
| * pointers with the result of the query. The value returned specifies the |
| * number of items in the returned array of results. The returned array of |
| * results are statically allocated and should not be deallocated using free() |
| */ |
| typedef unsigned int (*QueryDatabase)( |
| DatabaseConnection* const connection, const char * const query_string, |
| void *** const results); |
| |
| // Connection to a database. |
| struct DatabaseConnection { |
| const char *url; |
| unsigned int port; |
| QueryDatabase query_database; |
| }; |
| |
| // Connect to a database. |
| DatabaseConnection* connect_to_database(const char * const url, |
| const unsigned int port); |
| </listing> |
| <a href="../example/customer_database.c">customer_database.c</a> |
| <listing> |
| #include <stddef.h> |
| #include <stdio.h> |
| #include <database.h> |
| #ifdef _WIN32 |
| #define snprintf _snprintf |
| #endif // _WIN32 |
| |
| // Connect to the database containing customer information. |
| DatabaseConnection* connect_to_customer_database() { |
| return connect_to_database("customers.abcd.org", 321); |
| } |
| |
| /* Find the ID of a customer by his/her name returning a value > 0 if |
| * successful, 0 otherwise. */ |
| unsigned int get_customer_id_by_name( |
| DatabaseConnection * const connection, |
| const char * const customer_name) { |
| char query_string[256]; |
| int number_of_results; |
| void **results; |
| snprintf(query_string, sizeof(query_string), |
| "SELECT ID FROM CUSTOMERS WHERE NAME = %s", customer_name); |
| number_of_results = connection->query_database(connection, query_string, |
| &results); |
| if (number_of_results != 1) { |
| return -1; |
| } |
| return (unsigned int)results[0]; |
| } |
| </listing> |
| <a href="../example/customer_database_test.c">customer_database_test.c</a> |
| <listing> |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include <setjmp.h> |
| #include <cmocka.h> |
| #include <database.h> |
| |
| |
| extern DatabaseConnection* connect_to_customer_database(); |
| extern unsigned int get_customer_id_by_name( |
| DatabaseConnection * const connection, const char * const customer_name); |
| |
| // Mock query database function. |
| unsigned int mock_query_database( |
| DatabaseConnection* const connection, const char * const query_string, |
| void *** const results) { |
| *results = (void**)mock(); |
| return (unsigned int)mock(); |
| } |
| |
| // Mock of the connect to database function. |
| DatabaseConnection* connect_to_database(const char * const database_url, |
| const unsigned int port) { |
| return (DatabaseConnection*)mock(); |
| } |
| |
| void test_connect_to_customer_database(void **state) { |
| will_return(connect_to_database, 0x0DA7ABA53); |
| assert_true(connect_to_customer_database() == |
| (DatabaseConnection*)0x0DA7ABA53); |
| } |
| |
| /* This test fails as the mock function connect_to_database() will have no |
| * value to return. */ |
| void fail_connect_to_customer_database(void **state) { |
| will_return(connect_to_database, 0x0DA7ABA53); |
| assert_true(connect_to_customer_database() == |
| (DatabaseConnection*)0x0DA7ABA53); |
| } |
| |
| void test_get_customer_id_by_name(void **state) { |
| DatabaseConnection connection = { |
| "somedatabase.somewhere.com", 12345678, mock_query_database |
| }; |
| // Return a single customer ID when mock_query_database() is called. |
| int customer_ids = 543; |
| will_return(mock_query_database, &customer_ids); |
| will_return(mock_query_database, 1); |
| assert_int_equal(get_customer_id_by_name(&connection, "john doe"), 543); |
| } |
| |
| int main(int argc, char* argv[]) { |
| const UnitTest tests[] = { |
| unit_test(test_connect_to_customer_database), |
| unit_test(fail_connect_to_customer_database), |
| unit_test(test_get_customer_id_by_name), |
| }; |
| return run_tests(tests); |
| } |
| </listing> |
| |
| <a name="Checking_Parameters"><h3>Checking Parameters</h3></a> |
| <p>In addition to storing the return values of mock functions, cmocka |
| provides functionality to store expected values for mock function parameters |
| using the expect_*() functions provided. A mock function parameter can then |
| be validated using the check_expected() macro. |
| |
| <p>Successive calls to expect_*() macros for a parameter queues values to |
| check the specified parameter. check_expected() checks a function parameter |
| against the next value queued using expect_*(), if the parameter check fails a |
| test failure is signalled. In addition if check_expected() is called and |
| no more parameter values are queued a test failure occurs.</p> |
| |
| <h4>Using expect_*()</h4> |
| <a href="../example/product_database.c">product_database.c</a> |
| <listing> |
| #include <database.h> |
| |
| // Connect to the database containing customer information. |
| DatabaseConnection* connect_to_product_database() { |
| return connect_to_database("products.abcd.org", 322); |
| } |
| </listing> |
| <a href="../example/product_database_test.c">product_database_test.c</a> |
| <listing> |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include <setjmp.h> |
| #include <cmocka.h> |
| #include <database.h> |
| |
| extern DatabaseConnection* connect_to_product_database(); |
| |
| /* Mock connect to database function. |
| * NOTE: This mock function is very general could be shared between tests |
| * that use the imaginary database.h module. */ |
| DatabaseConnection* connect_to_database(const char * const url, |
| const unsigned int port) { |
| check_expected(url); |
| check_expected(port); |
| return (DatabaseConnection*)mock(); |
| } |
| |
| void test_connect_to_product_database(void **state) { |
| expect_string(connect_to_database, url, "products.abcd.org"); |
| expect_value(connect_to_database, port, 322); |
| will_return(connect_to_database, 0xDA7ABA53); |
| assert_int_equal(connect_to_product_database(), 0xDA7ABA53); |
| } |
| |
| /* This test will fail since the expected URL is different to the URL that is |
| * passed to connect_to_database() by connect_to_product_database(). */ |
| void test_connect_to_product_database_bad_url(void **state) { |
| expect_string(connect_to_database, url, "products.abcd.com"); |
| expect_value(connect_to_database, port, 322); |
| will_return(connect_to_database, 0xDA7ABA53); |
| assert_int_equal((int)connect_to_product_database(), 0xDA7ABA53); |
| } |
| |
| /* This test will fail since the mock connect_to_database() will attempt to |
| * retrieve a value for the parameter port which isn't specified by this |
| * test function. */ |
| void test_connect_to_product_database_missing_parameter(void **state) { |
| expect_string(connect_to_database, url, "products.abcd.org"); |
| will_return(connect_to_database, 0xDA7ABA53); |
| assert_int_equal((int)connect_to_product_database(), 0xDA7ABA53); |
| } |
| |
| int main(int argc, char* argv[]) { |
| const UnitTest tests[] = { |
| unit_test(test_connect_to_product_database), |
| unit_test(test_connect_to_product_database_bad_url), |
| unit_test(test_connect_to_product_database_missing_parameter), |
| }; |
| return run_tests(tests); |
| } |
| </listing> |
| |
| <a name="Test_State"><h2>Test State</h2></a> |
| |
| <p>cmocka allows the specification of multiple setup and tear down functions |
| for each test case. Setup functions, specified by the <b>unit_test_setup()</b> |
| or <b>unit_test_setup_teardown()</b> macros allow common initialization to be |
| shared between multiple test cases. In addition, tear down functions, |
| specified by the <b>unit_test_teardown()</b> or |
| <b>unit_test_setup_teardown()</b> macros provide a code path that is always |
| executed for a test case even when it fails.</p> |
| |
| <h4>Using unit_test_setup_teardown()</h4> |
| <a href="../example/key_value.c">key_value.c</a> |
| <listing> |
| #include <stddef.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| typedef struct KeyValue { |
| unsigned int key; |
| const char* value; |
| } KeyValue; |
| |
| static KeyValue *key_values = NULL; |
| static unsigned int number_of_key_values = 0; |
| |
| void set_key_values(KeyValue * const new_key_values, |
| const unsigned int new_number_of_key_values) { |
| key_values = new_key_values; |
| number_of_key_values = new_number_of_key_values; |
| } |
| |
| // Compare two key members of KeyValue structures. |
| int key_value_compare_keys(const void *a, const void *b) { |
| return (int)((KeyValue*)a)->key - (int)((KeyValue*)b)->key; |
| } |
| |
| // Search an array of key value pairs for the item with the specified value. |
| KeyValue* find_item_by_value(const char * const value) { |
| unsigned int i; |
| for (i = 0; i < number_of_key_values; i++) { |
| if (strcmp(key_values[i].value, value) == 0) { |
| return &key_values[i]; |
| } |
| } |
| return NULL; |
| } |
| |
| // Sort an array of key value pairs by key. |
| void sort_items_by_key() { |
| qsort(key_values, number_of_key_values, sizeof(*key_values), |
| key_value_compare_keys); |
| } |
| </listing> |
| <a href="../example/key_value_test.c">key_value_test.c</a> |
| <listing> |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include <setjmp.h> |
| #include <string.h> |
| #include <cmocka.h> |
| |
| /* This is duplicated here from the module setup_teardown.c to reduce the |
| * number of files used in this test. */ |
| typedef struct KeyValue { |
| unsigned int key; |
| const char* value; |
| } KeyValue; |
| |
| void set_key_values(KeyValue * const new_key_values, |
| const unsigned int new_number_of_key_values); |
| extern KeyValue* find_item_by_value(const char * const value); |
| extern void sort_items_by_key(); |
| |
| static KeyValue key_values[] = { |
| { 10, "this" }, |
| { 52, "test" }, |
| { 20, "a" }, |
| { 13, "is" }, |
| }; |
| |
| void create_key_values(void **state) { |
| KeyValue * const items = (KeyValue*)test_malloc(sizeof(key_values)); |
| memcpy(items, key_values, sizeof(key_values)); |
| *state = (void*)items; |
| set_key_values(items, sizeof(key_values) / sizeof(key_values[0])); |
| } |
| |
| void destroy_key_values(void **state) { |
| test_free(*state); |
| set_key_values(NULL, 0); |
| } |
| |
| void test_find_item_by_value(void **state) { |
| unsigned int i; |
| for (i = 0; i < sizeof(key_values) / sizeof(key_values[0]); i++) { |
| KeyValue * const found = find_item_by_value(key_values[i].value); |
| assert_true(found); |
| assert_int_equal(found->key, key_values[i].key); |
| assert_string_equal(found->value, key_values[i].value); |
| } |
| } |
| |
| void test_sort_items_by_key(void **state) { |
| unsigned int i; |
| KeyValue * const kv = *state; |
| sort_items_by_key(); |
| for (i = 1; i < sizeof(key_values) / sizeof(key_values[0]); i++) { |
| assert_true(kv[i - 1].key < kv[i].key); |
| } |
| } |
| |
| int main(int argc, char* argv[]) { |
| const UnitTest tests[] = { |
| unit_test_setup_teardown(test_find_item_by_value, create_key_values, |
| destroy_key_values), |
| unit_test_setup_teardown(test_sort_items_by_key, create_key_values, |
| destroy_key_values), |
| }; |
| return run_tests(tests); |
| } |
| </listing> |
| |
| <a name="Example"><h2>Example</h2></a> |
| |
| <p>A small command line calculator |
| <a href="../example/calculator.c">calculator.c</a> application |
| and test application that full exercises the calculator application |
| <a href="../example/calculator_test.c">calculator_test.c</a> |
| are provided as an example of cmocka's features discussed in this document. |
| </p> |
| |
| <hr> |
| <address></address> |
| <!-- hhmts start --> Last modified: Wed Jul 22 12:11:43 PDT 2009 <!-- hhmts end --> |
| </body> </html> |