1/* 2 * Copyright 2008 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17// A calculator example used to demonstrate the cmockery testing library. 18 19#include <assert.h> 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23 24// If this is being built for a unit test. 25#if UNIT_TESTING 26 27/* Redirect printf to a function in the test application so it's possible to 28 * test the standard output. */ 29#ifdef printf 30#undef printf 31#endif // printf 32#define printf example_test_printf 33 34extern void print_message(const char *format, ...); 35 36/* Redirect fprintf to a function in the test application so it's possible to 37 * test error messages. */ 38#ifdef fprintf 39#undef fprintf 40#endif // fprintf 41#define fprintf example_test_fprintf 42 43extern int example_test_fprintf(FILE * const file, const char *format, ...); 44 45// Redirect assert to mock_assert() so assertions can be caught by cmockery. 46#ifdef assert 47#undef assert 48#endif // assert 49#define assert(expression) \ 50 mock_assert((int)(expression), #expression, __FILE__, __LINE__) 51void mock_assert(const int result, const char* expression, const char *file, 52 const int line); 53 54/* Redirect calloc and free to test_calloc() and test_free() so cmockery can 55 * check for memory leaks. */ 56#ifdef calloc 57#undef calloc 58#endif // calloc 59#define calloc(num, size) _test_calloc(num, size, __FILE__, __LINE__) 60#ifdef free 61#undef free 62#endif // free 63#define free(ptr) _test_free(ptr, __FILE__, __LINE__) 64void* _test_calloc(const size_t number_of_elements, const size_t size, 65 const char* file, const int line); 66void _test_free(void* const ptr, const char* file, const int line); 67 68/* main is defined in the unit test so redefine name of the the main function 69 * here. */ 70#define main example_main 71 72/* All functions in this object need to be exposed to the test application, 73 * so redefine static to nothing. */ 74#define static 75 76#endif // UNIT_TESTING 77 78 79// A binary arithmetic integer operation (add, subtract etc.) 80typedef int (*BinaryOperator)(int a, int b); 81 82// Structure which maps operator strings to functions. 83typedef struct OperatorFunction { 84 const char* operator; 85 BinaryOperator function; 86} OperatorFunction; 87 88 89static int add(int a, int b); 90static int subtract(int a, int b); 91static int multiply(int a, int b); 92static int divide(int a, int b); 93 94// Associate operator strings to functions. 95static OperatorFunction operator_function_map[] = { 96 {"+", add}, 97 {"-", subtract}, 98 {"*", multiply}, 99 {"/", divide}, 100}; 101 102static int add(int a, int b) { 103 return a + b; 104} 105 106static int subtract(int a, int b) { 107 return a - b; 108} 109 110static int multiply(int a, int b) { 111 return a * b; 112} 113 114static int divide(int a, int b) { 115 assert(b); // Check for divde by zero. 116 return a / b; 117} 118 119/* Searches the specified array of operator_functions for the function 120 * associated with the specified operator_string. This function returns the 121 * function associated with operator_string if successful, NULL otherwise. 122 */ 123static BinaryOperator find_operator_function_by_string( 124 const size_t number_of_operator_functions, 125 const OperatorFunction * const operator_functions, 126 const char* const operator_string) { 127 size_t i; 128 assert(!number_of_operator_functions || operator_functions); 129 assert(operator_string); 130 131 for (i = 0; i < number_of_operator_functions; i++) { 132 const OperatorFunction *const operator_function = 133 &operator_functions[i]; 134 if (strcmp(operator_function->operator, operator_string) == 0) { 135 return operator_function->function; 136 } 137 } 138 return NULL; 139} 140 141/* Perform a series of binary arithmetic integer operations with no operator 142 * precedence. 143 * 144 * The input expression is specified by arguments which is an array of 145 * containing number_of_arguments strings. Operators invoked by the expression 146 * are specified by the array operator_functions containing 147 * number_of_operator_functions, OperatorFunction structures. The value of 148 * each binary operation is stored in a pointer returned to intermediate_values 149 * which is allocated by malloc(). 150 * 151 * If successful, this function returns the integer result of the operations. 152 * If an error occurs while performing the operation error_occurred is set to 153 * 1, the operation is aborted and 0 is returned. 154 */ 155static int perform_operation( 156 int number_of_arguments, char *arguments[], 157 const size_t number_of_operator_functions, 158 const OperatorFunction * const operator_functions, 159 int * const number_of_intermediate_values, 160 int ** const intermediate_values, int * const error_occurred) { 161 char *end_of_integer; 162 int value; 163 unsigned int i; 164 assert(!number_of_arguments || arguments); 165 assert(!number_of_operator_functions || operator_functions); 166 assert(error_occurred); 167 assert(number_of_intermediate_values); 168 assert(intermediate_values); 169 170 *error_occurred = 0; 171 *number_of_intermediate_values = 0; 172 *intermediate_values = NULL; 173 if (!number_of_arguments) 174 return 0; 175 176 // Parse the first value. 177 value = (int)strtol(arguments[0], &end_of_integer, 10); 178 if (end_of_integer == arguments[0]) { 179 // If an error occurred while parsing the integer. 180 fprintf(stderr, "Unable to parse integer from argument %s\n", 181 arguments[0]); 182 *error_occurred = 1; 183 return 0; 184 } 185 186 // Allocate an array for the output values. 187 *intermediate_values = calloc(((number_of_arguments - 1) / 2), 188 sizeof(**intermediate_values)); 189 190 i = 1; 191 while (i < number_of_arguments) { 192 int other_value; 193 const char* const operator_string = arguments[i]; 194 const BinaryOperator function = find_operator_function_by_string( 195 number_of_operator_functions, operator_functions, operator_string); 196 int * const intermediate_value = 197 &((*intermediate_values)[*number_of_intermediate_values]); 198 (*number_of_intermediate_values) ++; 199 200 if (!function) { 201 fprintf(stderr, "Unknown operator %s, argument %d\n", 202 operator_string, i); 203 *error_occurred = 1; 204 break; 205 } 206 i ++; 207 208 if (i == number_of_arguments) { 209 fprintf(stderr, "Binary operator %s missing argument\n", 210 operator_string); 211 *error_occurred = 1; 212 break; 213 } 214 215 other_value = (int)strtol(arguments[i], &end_of_integer, 10); 216 if (end_of_integer == arguments[i]) { 217 // If an error occurred while parsing the integer. 218 fprintf(stderr, "Unable to parse integer %s of argument %d\n", 219 arguments[i], i); 220 *error_occurred = 1; 221 break; 222 } 223 i ++; 224 225 // Perform the operation and store the intermediate value. 226 *intermediate_value = function(value, other_value); 227 value = *intermediate_value; 228 } 229 if (*error_occurred) { 230 free(*intermediate_values); 231 *intermediate_values = NULL; 232 *number_of_intermediate_values = 0; 233 return 0; 234 } 235 return value; 236} 237 238int main(int argc, char *argv[]) { 239 int return_value; 240 int number_of_intermediate_values; 241 int *intermediate_values; 242 // Peform the operation. 243 const int result = perform_operation( 244 argc - 1, &argv[1], 245 sizeof(operator_function_map) / sizeof(operator_function_map[0]), 246 operator_function_map, &number_of_intermediate_values, 247 &intermediate_values, &return_value); 248 249 // If no errors occurred display the result. 250 if (!return_value && argc > 1) { 251 unsigned int i; 252 unsigned int intermediate_value_index = 0; 253 printf("%s\n", argv[1]); 254 for (i = 2; i < argc; i += 2) { 255 assert(intermediate_value_index < number_of_intermediate_values); 256 printf(" %s %s = %d\n", argv[i], argv[i + 1], 257 intermediate_values[intermediate_value_index++]); 258 } 259 printf("= %d\n", result); 260 } 261 if (intermediate_values) { 262 free(intermediate_values); 263 } 264 265 return return_value; 266} 267