0001 #include <cgreen/constraint.h>
0002 #include <cgreen/message_formatting.h>
0003 #include <cgreen/string_comparison.h>
0004 #include <inttypes.h>
0005 #ifndef __cplusplus
0006 #include <stdbool.h>
0007 #endif
0008 #include <stdio.h>
0009 #include <stdlib.h>
0010 #include <string.h>
0011
0012 #ifdef _MSC_VER
0013 #include "wincompat.h"
0014 #endif
0015
0016 #ifdef __cplusplus
0017 namespace cgreen {
0018 #endif
0019
0020 static int find_index_of_difference(char *expected, char *actual, size_t size_to_compare) {
0021 char *expectedp = expected;
0022 char *actualp = actual;
0023
0024 while (size_to_compare--) {
0025 if (*expectedp++ != *actualp++) {
0026 return (int)(actualp - actual);
0027 }
0028 }
0029
0030 return -1;
0031 }
0032
0033 static bool actual_value_not_necessary_for(Constraint *constraint, const char *actual_string, const char *actual_value_string) {
0034 (void)constraint;
0035 return strings_are_equal(actual_string, actual_value_string) ||
0036 strings_are_equal(actual_string, "true") ||
0037 strings_are_equal(actual_string, "false");
0038 }
0039
0040
0041 bool parameters_are_not_valid_for(Constraint *constraint, intptr_t actual) {
0042 char *message = validation_failure_message_for(constraint, actual);
0043
0044 bool not_valid = (strlen(message) > 0);
0045
0046 free(message);
0047
0048 return not_valid;
0049 }
0050
0051 char *validation_failure_message_for(Constraint *constraint, intptr_t actual) {
0052 const char *name_has_incorrect_size_message =
0053 "\t\tWanted to compare contents with [%s], but [%lu] was given for the comparison size.";
0054 const char *null_used_for_compare_message =
0055 "\t\tWanted to compare contents with [%s], but NULL was used for the pointer we wanted to compare to."
0056 "\t\tIf you want to explicitly check for null, use the is_null constraint instead.";
0057 const char *null_used_for_actual_message =
0058 "\t\tWanted to compare contents of [%s] but it had a value of NULL.\n"
0059 "\t\tIf you want to explicitly check for null, use the is_null constraint instead.";
0060
0061
0062
0063 size_t message_size = strlen(name_has_incorrect_size_message) +
0064 strlen(null_used_for_compare_message) +
0065 strlen(null_used_for_actual_message) +
0066 512;
0067
0068 char *message = (char *)malloc(message_size);
0069 memset(message, 0, message_size);
0070
0071 if (is_content_comparing(constraint)) {
0072 const char *compared_to_name;
0073 if (constraint->parameter_name != NULL) {
0074 compared_to_name = constraint->parameter_name;
0075 } else {
0076 compared_to_name = constraint->expected_value_name;
0077 }
0078
0079 if (constraint->size_of_expected_value <= 0) {
0080 snprintf(message + strlen(message), message_size - strlen(message) - 1,
0081 name_has_incorrect_size_message,
0082 compared_to_name,
0083 (unsigned long)constraint->size_of_expected_value);
0084
0085 return message;
0086 }
0087
0088 if ((void *)actual == NULL) {
0089 snprintf(message + strlen(message), message_size - strlen(message) - 1,
0090 null_used_for_compare_message,
0091 compared_to_name);
0092
0093 return message;
0094 }
0095
0096 if ((void *)constraint->expected_value == NULL) {
0097 snprintf(message + strlen(message), message_size - strlen(message) - 1,
0098 null_used_for_actual_message,
0099 compared_to_name);
0100
0101 return message;
0102 }
0103 }
0104
0105 return message;
0106 }
0107
0108
0109 static char *next_percent_sign(const char *s) {
0110 return strchr(s, '%');
0111 }
0112
0113 size_t count_percent_signs(char const *s)
0114 {
0115 size_t count = 0;
0116 char const *p = next_percent_sign(s);
0117 while (p != NULL) {
0118 count++;
0119 p = next_percent_sign(p+1);
0120 }
0121 return count;
0122 }
0123
0124
0125 char *copy_while_doubling_percent_signs(char *string, char const *original)
0126 {
0127 char *destination = string;
0128 const char *source = original;
0129 const char *next = next_percent_sign(source);
0130 for (; next != NULL; next = next_percent_sign(next+1)) {
0131 size_t len = next - source + 1;
0132 memcpy(destination, source, len);
0133 destination += len;
0134 *destination++ = '%';
0135 source = next+1;
0136 }
0137 strcpy(destination, source);
0138
0139 return string;
0140 }
0141
0142
0143 void double_all_percent_signs_in(char **original)
0144 {
0145 size_t percent_count = count_percent_signs(*original);
0146 if (percent_count == 0) {
0147 return;
0148 }
0149 char *new_string = (char *)malloc(strlen(*original) + percent_count + 1);
0150 if (new_string == NULL) {
0151 return;
0152 }
0153 copy_while_doubling_percent_signs(new_string, *original);
0154 free(*original);
0155 *original = new_string;
0156 }
0157
0158
0159 char *failure_message_for(Constraint *constraint, const char *actual_string, intptr_t actual) {
0160 char actual_value_string[32];
0161 const char *actual_value_constraint_name = "Expected [%s] to [%s]";
0162 const char *expected_value_name = "[%s]\n";
0163 const char *actual_value_as_string = "\t\tactual value:\t\t\t[\"%s\"]";
0164 const char *at_offset = "\t\tat offset:\t\t\t[%d]";
0165 const char *actual_value_message = "\t\tactual value:\t\t\t[%" PRIdPTR "]";
0166 char *message;
0167 size_t message_size = strlen(actual_value_constraint_name) +
0168 strlen(expected_value_name) +
0169 strlen(actual_value_as_string) +
0170 strlen(at_offset) +
0171 strlen(actual_value_message) +
0172 strlen(constraint->expected_value_message) +
0173 strlen(constraint->expected_value_name) +
0174 strlen(constraint->name) +
0175 strlen(actual_string) +
0176 512;
0177
0178 snprintf(actual_value_string, sizeof(actual_value_string) - 1, "%" PRIdPTR, actual);
0179
0180 if (values_are_strings_in(constraint)) {
0181 message_size += strlen((char *)constraint->expected_value);
0182 if (actual != (intptr_t)NULL) {
0183 message_size += strlen((char *)actual);
0184 }
0185 }
0186
0187 message = (char *)malloc(message_size);
0188
0189 snprintf(message, message_size - 1,
0190 actual_value_constraint_name,
0191 actual_string,
0192 constraint->name);
0193
0194 if (no_expected_value_in(constraint)) {
0195 return message;
0196 } else
0197 strcat(message, " ");
0198
0199 snprintf(message + strlen(message), message_size - strlen(message) - 1,
0200 expected_value_name,
0201 constraint->expected_value_name);
0202
0203 if (actual_value_not_necessary_for(constraint, actual_string, actual_value_string)) {
0204
0205
0206
0207 return message;
0208 }
0209
0210
0211 if (values_are_strings_in(constraint)) {
0212 snprintf(message + strlen(message), message_size - strlen(message) - 1,
0213 actual_value_as_string,
0214 (const char *)actual);
0215 if (strstr(constraint->name, "not ") == NULL || strstr(constraint->name, "contain ") != NULL) {
0216 strcat(message, "\n");
0217 snprintf(message + strlen(message), message_size - strlen(message) - 1,
0218 constraint->expected_value_message,
0219 (const char *)constraint->expected_value);
0220 }
0221
0222
0223
0224 double_all_percent_signs_in(&message);
0225 return message;
0226 }
0227
0228 if (is_content_comparing(constraint)) {
0229 int difference_index = find_index_of_difference((char *)constraint->expected_value,
0230 (char *)actual, constraint->size_of_expected_value);
0231 snprintf(message + strlen(message), message_size - strlen(message) - 1,
0232 at_offset,
0233 difference_index);
0234 return message;
0235 }
0236
0237 snprintf(message + strlen(message), message_size - strlen(message) - 1,
0238 actual_value_message,
0239 actual);
0240
0241 if (strstr(constraint->name, "not ") == NULL) {
0242 strcat(message, "\n");
0243 snprintf(message + strlen(message), message_size - strlen(message) - 1,
0244 constraint->expected_value_message,
0245 constraint->expected_value);
0246 }
0247
0248 return message;
0249 }
0250
0251 #ifdef __cplusplus
0252 }
0253 #endif