/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "cmocka.h" #include #ifdef _WIN32 /* Compatibility with the Windows standard C library. */ #define vsnprintf _vsnprintf #endif /* _WIN32 */ #define array_length(x) (sizeof(x) / sizeof((x)[0])) /* To simplify this code, these functions and data structures could have been * separated out from the application example.c into a header shared with * test application. However, this example illustrates how it's possible to * test existing code with little modification. */ typedef int (*BinaryOperator)(int a, int b); typedef struct OperatorFunction { const char* operator; BinaryOperator function; } OperatorFunction; extern int add(int a, int b); extern int subtract(int a, int b); extern int multiply(int a, int b); extern int divide(int a, int b); extern BinaryOperator find_operator_function_by_string( const size_t number_of_operator_functions, const OperatorFunction * const operator_functions, const char* const operator_string); extern int perform_operation( int number_of_arguments, char *arguments[], const size_t number_of_operator_functions, const OperatorFunction * const operator_functions, int * const number_of_intermediate_values, int ** const intermediate_values, int * const error_occurred); extern int example_main(int argc, char *argv[]); int example_test_fprintf(FILE* const file, const char *format, ...) CMOCKA_PRINTF_ATTRIBUTE(2, 3); int example_test_printf(const char *format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); static char temporary_buffer[256]; /* A mock fprintf function that checks the value of strings printed to the * standard error stream. */ int example_test_fprintf(FILE* const file, const char *format, ...) { int return_value; va_list args; assert_true(file == stderr); va_start(args, format); return_value = vsnprintf(temporary_buffer, sizeof(temporary_buffer), format, args); check_expected_ptr(temporary_buffer); va_end(args); return return_value; } /* A mock printf function that checks the value of strings printed to the * standard output stream. */ int example_test_printf(const char *format, ...) { int return_value; va_list args; va_start(args, format); return_value = vsnprintf(temporary_buffer, sizeof(temporary_buffer), format, args); check_expected_ptr(temporary_buffer); va_end(args); return return_value; } /* A mock binary operator function. */ static int binary_operator(int a, int b) { check_expected(a); check_expected(b); return (int)mock(); } /* Ensure add() adds two integers correctly. */ static void test_add(void **state) { (void) state; /* unused */ assert_int_equal(add(3, 3), 6); assert_int_equal(add(3, -3), 0); } /* Ensure subtract() subtracts two integers correctly. */ static void test_subtract(void **state) { (void) state; /* unused */ assert_int_equal(subtract(3, 3), 0); assert_int_equal(subtract(3, -3), 6); } /* Ensure multiple() mulitplies two integers correctly. */ static void test_multiply(void **state) { (void) state; /* unused */ assert_int_equal(multiply(3, 3), 9); assert_int_equal(multiply(3, 0), 0); } /* Ensure divide() divides one integer by another correctly. */ static void test_divide(void **state) { (void) state; /* unused */ assert_int_equal(divide(10, 2), 5); assert_int_equal(divide(2, 10), 0); } /* Ensure divide() asserts when trying to divide by zero. */ static void test_divide_by_zero(void **state) { (void) state; /* unused */ expect_assert_failure(divide(100, 0)); } /* Ensure find_operator_function_by_string() asserts when a NULL pointer is * specified as the table to search. */ static void test_find_operator_function_by_string_null_functions(void **state) { (void) state; /* unused */ expect_assert_failure(find_operator_function_by_string(1, NULL, "test")); } /* Ensure find_operator_function_by_string() asserts when a NULL pointer is * specified as the string to search for. */ static void test_find_operator_function_by_string_null_string(void **state) { const OperatorFunction operator_functions[] = { {"+", binary_operator}, }; (void) state; /* unused */ expect_assert_failure(find_operator_function_by_string( array_length(operator_functions), operator_functions, NULL)); } /* Ensure find_operator_function_by_string() returns NULL when a NULL pointer * is specified as the table to search when the table size is 0. */ static void test_find_operator_function_by_string_valid_null_functions(void **state) { (void) state; /* unused */ assert_null(find_operator_function_by_string(0, NULL, "test")); } /* Ensure find_operator_function_by_string() returns NULL when searching for * an operator string that isn't in the specified table. */ static void test_find_operator_function_by_string_not_found(void **state) { const OperatorFunction operator_functions[] = { {"+", binary_operator}, {"-", binary_operator}, {"/", binary_operator}, }; (void) state; /* unused */ assert_null(find_operator_function_by_string( array_length(operator_functions), operator_functions, "test")); } /* Ensure find_operator_function_by_string() returns the correct function when * searching for an operator string that is in the specified table. */ static void test_find_operator_function_by_string_found(void **state) { const OperatorFunction operator_functions[] = { {"+", (BinaryOperator)0x12345678}, {"-", (BinaryOperator)0xDEADBEEF}, {"/", (BinaryOperator)0xABADCAFE}, }; (void) state; /* unused */ assert_int_equal( cast_ptr_to_largest_integral_type( find_operator_function_by_string(array_length(operator_functions), operator_functions, "-")), 0xDEADBEEF); } /* Ensure perform_operation() asserts when a NULL arguments array is specified. */ static void test_perform_operation_null_args(void **state) { const OperatorFunction operator_functions[] = { {"+", binary_operator}, }; int number_of_intermediate_values; int *intermediate_values; int error_occurred; (void) state; /* unused */ expect_assert_failure(perform_operation( 1, NULL, array_length(operator_functions), operator_functions, &number_of_intermediate_values, &intermediate_values, &error_occurred)); } /* Ensure perform_operation() asserts when a NULL operator_functions array is * specified. */ static void test_perform_operation_null_operator_functions(void **state) { const char *args[] = { "1", "+", "2", "*", "4" }; int number_of_intermediate_values; int *intermediate_values; int error_occurred; (void) state; /* unused */ expect_assert_failure(perform_operation( array_length(args), (char **) args, 1, NULL, &number_of_intermediate_values, &intermediate_values, &error_occurred)); } /* Ensure perform_operation() asserts when a NULL pointer is specified for * number_of_intermediate_values. */ static void test_perform_operation_null_number_of_intermediate_values(void **state) { const OperatorFunction operator_functions[] = { {"+", binary_operator}, }; const char *args[] = { "1", "+", "2", "*", "4" }; int *intermediate_values; int error_occurred; (void) state; /* unused */ expect_assert_failure(perform_operation( array_length(args), (char **) args, 1, operator_functions, NULL, &intermediate_values, &error_occurred)); } /* Ensure perform_operation() asserts when a NULL pointer is specified for * intermediate_values. */ static void test_perform_operation_null_intermediate_values(void **state) { const OperatorFunction operator_functions[] = { {"+", binary_operator}, }; const char *args[] = { "1", "+", "2", "*", "4" }; int number_of_intermediate_values; int error_occurred; (void) state; /* unused */ expect_assert_failure(perform_operation( array_length(args), (char **) args, array_length(operator_functions), operator_functions, &number_of_intermediate_values, NULL, &error_occurred)); } /* Ensure perform_operation() returns 0 when no arguments are specified. */ static void test_perform_operation_no_arguments(void **state) { int number_of_intermediate_values; int *intermediate_values; int error_occurred; (void) state; /* unused */ assert_int_equal(perform_operation( 0, NULL, 0, NULL, &number_of_intermediate_values, &intermediate_values, &error_occurred), 0); assert_int_equal(error_occurred, 0); } /* Ensure perform_operation() returns an error if the first argument isn't * an integer string. */ static void test_perform_operation_first_arg_not_integer(void **state) { const OperatorFunction operator_functions[] = { {"+", binary_operator}, }; const char *args[] = { "test", "+", "2", "*", "4" }; int number_of_intermediate_values; int *intermediate_values; int error_occurred; (void) state; /* unused */ expect_string(example_test_fprintf, temporary_buffer, "Unable to parse integer from argument test\n"); assert_int_equal(perform_operation( array_length(args), (char **) args, array_length(operator_functions), operator_functions, &number_of_intermediate_values, &intermediate_values, &error_occurred), 0); assert_int_equal(error_occurred, 1); } /* Ensure perform_operation() returns an error when parsing an unknown * operator. */ static void test_perform_operation_unknown_operator(void **state) { const OperatorFunction operator_functions[] = { {"+", binary_operator}, }; const char *args[] = { "1", "*", "2", "*", "4" }; int number_of_intermediate_values; int *intermediate_values; int error_occurred; (void) state; /* unused */ expect_string(example_test_fprintf, temporary_buffer, "Unknown operator *, argument 1\n"); assert_int_equal(perform_operation( array_length(args), (char **) args, array_length(operator_functions), operator_functions, &number_of_intermediate_values, &intermediate_values, &error_occurred), 0); assert_int_equal(error_occurred, 1); } /* Ensure perform_operation() returns an error when nothing follows an * operator. */ static void test_perform_operation_missing_argument(void **state) { const OperatorFunction operator_functions[] = { {"+", binary_operator}, }; const char *args[] = { "1", "+", }; int number_of_intermediate_values; int *intermediate_values; int error_occurred; (void) state; /* unused */ expect_string(example_test_fprintf, temporary_buffer, "Binary operator + missing argument\n"); assert_int_equal(perform_operation( array_length(args), (char **) args, array_length(operator_functions), operator_functions, &number_of_intermediate_values, &intermediate_values, &error_occurred), 0); assert_int_equal(error_occurred, 1); } /* Ensure perform_operation() returns an error when an integer doesn't follow * an operator. */ static void test_perform_operation_no_integer_after_operator(void **state) { const OperatorFunction operator_functions[] = { {"+", binary_operator}, }; const char *args[] = { "1", "+", "test", }; int number_of_intermediate_values; int *intermediate_values; int error_occurred; (void) state; /* unused */ expect_string(example_test_fprintf, temporary_buffer, "Unable to parse integer test of argument 2\n"); assert_int_equal(perform_operation( array_length(args), (char **) args, array_length(operator_functions), operator_functions, &number_of_intermediate_values, &intermediate_values, &error_occurred), 0); assert_int_equal(error_occurred, 1); } /* Ensure perform_operation() succeeds given valid input parameters. */ static void test_perform_operation(void **state) { const OperatorFunction operator_functions[] = { {"+", binary_operator}, {"*", binary_operator}, }; const char *args[] = { "1", "+", "3", "*", "10", }; int number_of_intermediate_values; int *intermediate_values = NULL; int error_occurred; (void) state; /* unused */ /* Setup return values of mock operator functions. */ /* Addition. */ expect_value(binary_operator, a, 1); expect_value(binary_operator, b, 3); will_return(binary_operator, 4); /* Multiplication. */ expect_value(binary_operator, a, 4); expect_value(binary_operator, b, 10); will_return(binary_operator, 40); assert_int_equal(perform_operation( array_length(args), (char **) args, array_length(operator_functions), operator_functions, &number_of_intermediate_values, &intermediate_values, &error_occurred), 40); assert_int_equal(error_occurred, 0); assert_non_null(intermediate_values); assert_int_equal(intermediate_values[0], 4); assert_int_equal(intermediate_values[1], 40); test_free(intermediate_values); } /* Ensure main() in example.c succeeds given no arguments. */ static void test_example_main_no_args(void **state) { const char *args[] = { "example", }; (void) state; /* unused */ assert_int_equal(example_main(array_length(args), (char **) args), 0); } /* Ensure main() in example.c succeeds given valid input arguments. */ static void test_example_main(void **state) { const char *args[] = { "example", "1", "+", "3", "*", "10", }; (void) state; /* unused */ expect_string(example_test_printf, temporary_buffer, "1\n"); expect_string(example_test_printf, temporary_buffer, " + 3 = 4\n"); expect_string(example_test_printf, temporary_buffer, " * 10 = 40\n"); expect_string(example_test_printf, temporary_buffer, "= 40\n"); assert_int_equal(example_main(array_length(args), (char **) args), 0); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_add), cmocka_unit_test(test_subtract), cmocka_unit_test(test_multiply), cmocka_unit_test(test_divide), cmocka_unit_test(test_divide_by_zero), cmocka_unit_test(test_find_operator_function_by_string_null_functions), cmocka_unit_test(test_find_operator_function_by_string_null_string), cmocka_unit_test(test_find_operator_function_by_string_valid_null_functions), cmocka_unit_test(test_find_operator_function_by_string_not_found), cmocka_unit_test(test_find_operator_function_by_string_found), cmocka_unit_test(test_perform_operation_null_args), cmocka_unit_test(test_perform_operation_null_operator_functions), cmocka_unit_test(test_perform_operation_null_number_of_intermediate_values), cmocka_unit_test(test_perform_operation_null_intermediate_values), cmocka_unit_test(test_perform_operation_no_arguments), cmocka_unit_test(test_perform_operation_first_arg_not_integer), cmocka_unit_test(test_perform_operation_unknown_operator), cmocka_unit_test(test_perform_operation_missing_argument), cmocka_unit_test(test_perform_operation_no_integer_after_operator), cmocka_unit_test(test_perform_operation), cmocka_unit_test(test_example_main_no_args), cmocka_unit_test(test_example_main), }; return cmocka_run_group_tests(tests, NULL, NULL); }