/* * 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 cmockery testing library. #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> // If this is being built for a unit test. #if 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 #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 cmockery. #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 cmockery 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); /* 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; 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 divde 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. */ static 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); 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. */ static 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; unsigned int i; assert(!number_of_arguments || arguments); assert(!number_of_operator_functions || operator_functions); assert(error_occurred); assert(number_of_intermediate_values); assert(intermediate_values); *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) { unsigned int i; unsigned 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; }