Home | History | Annotate | Download | only in example
      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 
     34 extern 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 
     43 extern 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__)
     51 void 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__)
     64 void* _test_calloc(const size_t number_of_elements, const size_t size,
     65                    const char* file, const int line);
     66 void _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.)
     80 typedef int (*BinaryOperator)(int a, int b);
     81 
     82 // Structure which maps operator strings to functions.
     83 typedef struct OperatorFunction {
     84 	const char* operator;
     85 	BinaryOperator function;
     86 } OperatorFunction;
     87 
     88 
     89 static int add(int a, int b);
     90 static int subtract(int a, int b);
     91 static int multiply(int a, int b);
     92 static int divide(int a, int b);
     93 
     94 // Associate operator strings to functions.
     95 static OperatorFunction operator_function_map[] = {
     96 	{"+", add},
     97 	{"-", subtract},
     98 	{"*", multiply},
     99 	{"/", divide},
    100 };
    101 
    102 static int add(int a, int b) {
    103 	return a + b;
    104 }
    105 
    106 static int subtract(int a, int b) {
    107 	return a - b;
    108 }
    109 
    110 static int multiply(int a, int b) {
    111 	return a * b;
    112 }
    113 
    114 static 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  */
    123 static 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  */
    155 static 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 
    238 int 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