| /* |
| * 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. |
| */ |
| |
| /* A calculator example used to demonstrate the cmocka testing library. */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| #include <assert.h> |
| #ifdef HAVE_MALLOC_H |
| #include <malloc.h> |
| #endif |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| /* If this is being built for a unit test. */ |
| #ifdef UNIT_TESTING |
| |
| /* Redirect printf to a function in the test application so it's possible to |
| * test the standard output. */ |
| #ifdef printf |
| #undef printf |
| #endif /* printf */ |
| extern int example_test_printf(const char *format, ...); |
| #define printf example_test_printf |
| |
| extern void print_message(const char *format, ...); |
| |
| /* Redirect fprintf to a function in the test application so it's possible to |
| * test error messages. */ |
| #ifdef fprintf |
| #undef fprintf |
| #endif /* fprintf */ |
| #define fprintf example_test_fprintf |
| |
| extern int example_test_fprintf(FILE * const file, const char *format, ...); |
| |
| /* Redirect assert to mock_assert() so assertions can be caught by cmocka. */ |
| #ifdef assert |
| #undef assert |
| #endif /* assert */ |
| #define assert(expression) \ |
| mock_assert((int)(expression), #expression, __FILE__, __LINE__) |
| void mock_assert(const int result, const char* expression, const char *file, |
| const int line); |
| |
| /* Redirect calloc and free to test_calloc() and test_free() so cmocka can |
| * check for memory leaks. */ |
| #ifdef calloc |
| #undef calloc |
| #endif /* calloc */ |
| #define calloc(num, size) _test_calloc(num, size, __FILE__, __LINE__) |
| #ifdef free |
| #undef free |
| #endif /* free */ |
| #define free(ptr) _test_free(ptr, __FILE__, __LINE__) |
| void* _test_calloc(const size_t number_of_elements, const size_t size, |
| const char* file, const int line); |
| void _test_free(void* const ptr, const char* file, const int line); |
| |
| int example_main(int argc, char *argv[]); |
| /* main is defined in the unit test so redefine name of the the main function |
| * here. */ |
| #define main example_main |
| |
| /* All functions in this object need to be exposed to the test application, |
| * so redefine static to nothing. */ |
| #define static |
| |
| #endif /* UNIT_TESTING */ |
| |
| |
| /* A binary arithmetic integer operation (add, subtract etc.) */ |
| typedef int (*BinaryOperator)(int a, int b); |
| |
| /* Structure which maps operator strings to functions. */ |
| typedef struct OperatorFunction { |
| const char* operator; |
| BinaryOperator function; |
| } OperatorFunction; |
| |
| |
| BinaryOperator find_operator_function_by_string( |
| const size_t number_of_operator_functions, |
| const OperatorFunction * const operator_functions, |
| const char* const operator_string); |
| |
| 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); |
| |
| static int add(int a, int b); |
| static int subtract(int a, int b); |
| static int multiply(int a, int b); |
| static int divide(int a, int b); |
| |
| /* Associate operator strings to functions. */ |
| static OperatorFunction operator_function_map[] = { |
| {"+", add}, |
| {"-", subtract}, |
| {"*", multiply}, |
| {"/", divide}, |
| }; |
| |
| static int add(int a, int b) { |
| return a + b; |
| } |
| |
| static int subtract(int a, int b) { |
| return a - b; |
| } |
| |
| static int multiply(int a, int b) { |
| return a * b; |
| } |
| |
| static int divide(int a, int b) { |
| assert(b); /* Check for divide by zero. */ |
| return a / b; |
| } |
| |
| /* Searches the specified array of operator_functions for the function |
| * associated with the specified operator_string. This function returns the |
| * function associated with operator_string if successful, NULL otherwise. |
| */ |
| BinaryOperator find_operator_function_by_string( |
| const size_t number_of_operator_functions, |
| const OperatorFunction * const operator_functions, |
| const char* const operator_string) { |
| size_t i; |
| assert(!number_of_operator_functions || operator_functions); |
| assert(operator_string != NULL); |
| |
| for (i = 0; i < number_of_operator_functions; i++) { |
| const OperatorFunction *const operator_function = |
| &operator_functions[i]; |
| if (strcmp(operator_function->operator, operator_string) == 0) { |
| return operator_function->function; |
| } |
| } |
| return NULL; |
| } |
| |
| /* Perform a series of binary arithmetic integer operations with no operator |
| * precedence. |
| * |
| * The input expression is specified by arguments which is an array of |
| * containing number_of_arguments strings. Operators invoked by the expression |
| * are specified by the array operator_functions containing |
| * number_of_operator_functions, OperatorFunction structures. The value of |
| * each binary operation is stored in a pointer returned to intermediate_values |
| * which is allocated by malloc(). |
| * |
| * If successful, this function returns the integer result of the operations. |
| * If an error occurs while performing the operation error_occurred is set to |
| * 1, the operation is aborted and 0 is returned. |
| */ |
| 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) { |
| char *end_of_integer; |
| int value; |
| int i; |
| assert(!number_of_arguments || arguments); |
| assert(!number_of_operator_functions || operator_functions); |
| assert(error_occurred != NULL); |
| assert(number_of_intermediate_values != NULL); |
| assert(intermediate_values != NULL); |
| |
| *error_occurred = 0; |
| *number_of_intermediate_values = 0; |
| *intermediate_values = NULL; |
| if (!number_of_arguments) |
| return 0; |
| |
| /* Parse the first value. */ |
| value = (int)strtol(arguments[0], &end_of_integer, 10); |
| if (end_of_integer == arguments[0]) { |
| /* If an error occurred while parsing the integer. */ |
| fprintf(stderr, "Unable to parse integer from argument %s\n", |
| arguments[0]); |
| *error_occurred = 1; |
| return 0; |
| } |
| |
| /* Allocate an array for the output values. */ |
| *intermediate_values = calloc(((number_of_arguments - 1) / 2), |
| sizeof(**intermediate_values)); |
| |
| i = 1; |
| while (i < number_of_arguments) { |
| int other_value; |
| const char* const operator_string = arguments[i]; |
| const BinaryOperator function = find_operator_function_by_string( |
| number_of_operator_functions, operator_functions, operator_string); |
| int * const intermediate_value = |
| &((*intermediate_values)[*number_of_intermediate_values]); |
| (*number_of_intermediate_values) ++; |
| |
| if (!function) { |
| fprintf(stderr, "Unknown operator %s, argument %d\n", |
| operator_string, i); |
| *error_occurred = 1; |
| break; |
| } |
| i ++; |
| |
| if (i == number_of_arguments) { |
| fprintf(stderr, "Binary operator %s missing argument\n", |
| operator_string); |
| *error_occurred = 1; |
| break; |
| } |
| |
| other_value = (int)strtol(arguments[i], &end_of_integer, 10); |
| if (end_of_integer == arguments[i]) { |
| /* If an error occurred while parsing the integer. */ |
| fprintf(stderr, "Unable to parse integer %s of argument %d\n", |
| arguments[i], i); |
| *error_occurred = 1; |
| break; |
| } |
| i ++; |
| |
| /* Perform the operation and store the intermediate value. */ |
| *intermediate_value = function(value, other_value); |
| value = *intermediate_value; |
| } |
| if (*error_occurred) { |
| free(*intermediate_values); |
| *intermediate_values = NULL; |
| *number_of_intermediate_values = 0; |
| return 0; |
| } |
| return value; |
| } |
| |
| int main(int argc, char *argv[]) { |
| int return_value; |
| int number_of_intermediate_values; |
| int *intermediate_values; |
| /* Peform the operation. */ |
| const int result = perform_operation( |
| argc - 1, &argv[1], |
| sizeof(operator_function_map) / sizeof(operator_function_map[0]), |
| operator_function_map, &number_of_intermediate_values, |
| &intermediate_values, &return_value); |
| |
| /* If no errors occurred display the result. */ |
| if (!return_value && argc > 1) { |
| int i; |
| int intermediate_value_index = 0; |
| printf("%s\n", argv[1]); |
| for (i = 2; i < argc; i += 2) { |
| assert(intermediate_value_index < number_of_intermediate_values); |
| printf(" %s %s = %d\n", argv[i], argv[i + 1], |
| intermediate_values[intermediate_value_index++]); |
| } |
| printf("= %d\n", result); |
| } |
| if (intermediate_values) { |
| free(intermediate_values); |
| } |
| |
| return return_value; |
| } |