From: Fletcher T. Penney Date: Mon, 15 Jan 2018 16:44:11 +0000 (-0500) Subject: UPDATED: Add test suite to d_string X-Git-Tag: 6.3.0^2~8 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f527946e36d6e10e05fbd5d19a4baed4bb5cf1e2;p=multimarkdown UPDATED: Add test suite to d_string --- diff --git a/Sources/libMultiMarkdown/d_string.c b/Sources/libMultiMarkdown/d_string.c index 697fab2..b6896e1 100644 --- a/Sources/libMultiMarkdown/d_string.c +++ b/Sources/libMultiMarkdown/d_string.c @@ -64,6 +64,10 @@ #include "d_string.h" +#ifdef TEST + #include "CuTest.h" +#endif + /* * The following section came from: @@ -145,6 +149,31 @@ DString* d_string_new(const char * startingString) { } +#ifdef TEST +void Test_d_string_new(CuTest* tc) { + char * test = "foo"; + + DString * result = d_string_new(test); + + CuAssertIntEquals(tc, 3, result->currentStringLength); + CuAssertIntEquals(tc, kStringBufferStartingSize, result->currentStringBufferSize); + CuAssertStrEquals(tc, test, result->str); + CuAssertIntEquals(tc, '\0', result->str[strlen(test)]); + + d_string_free(result, true); + + result = d_string_new(NULL); + + CuAssertIntEquals(tc, 0, result->currentStringLength); + CuAssertIntEquals(tc, kStringBufferStartingSize, result->currentStringBufferSize); + CuAssertStrEquals(tc, "", result->str); + CuAssertIntEquals(tc, '\0', 0); + + d_string_free(result, true); +} +#endif + + /// Free dynamic string char* d_string_free(DString * ripString, bool freeCharacterData) { if (ripString == NULL) { @@ -169,234 +198,584 @@ char* d_string_free(DString * ripString, bool freeCharacterData) { /// Ensure that dynamic string has specified capacity static void ensureStringBufferCanHold(DString * baseString, size_t newStringSize) { - size_t newBufferSizeNeeded = newStringSize + 1; + if (baseString) { + size_t newBufferSizeNeeded = newStringSize + 1; + + if (newBufferSizeNeeded > baseString->currentStringBufferSize) { + size_t newBufferSize = baseString->currentStringBufferSize; + + while (newBufferSizeNeeded > newBufferSize) { + if (newBufferSize > kStringBufferMaxIncrement) { + newBufferSize += kStringBufferMaxIncrement; + } else { + newBufferSize *= kStringBufferGrowthMultiplier; + } + } + + char *temp; + temp = realloc(baseString->str, newBufferSize); - if (newBufferSizeNeeded > baseString->currentStringBufferSize) { - size_t newBufferSize = baseString->currentStringBufferSize; + if (temp == NULL) { + /* realloc failed */ + fprintf(stderr, "Error reallocating memory for d_string. Current buffer size %lu.\n", baseString->currentStringBufferSize); - while (newBufferSizeNeeded > newBufferSize) { - if (newBufferSize > kStringBufferMaxIncrement) { - newBufferSize += kStringBufferMaxIncrement; - } else { - newBufferSize *= kStringBufferGrowthMultiplier; + exit(1); } + + baseString->str = temp; + baseString->currentStringBufferSize = newBufferSize; } + } +} - char *temp; - temp = realloc(baseString->str, newBufferSize); - if (temp == NULL) { - /* realloc failed */ - fprintf(stderr, "Error reallocating memory for d_string. Current buffer size %lu.\n", baseString->currentStringBufferSize); +#ifdef TEST +void Test_ensureStringBufferCanHold(CuTest* tc) { + char * test = "foo"; - exit(1); - } + DString * result = d_string_new(test); - baseString->str = temp; - baseString->currentStringBufferSize = newBufferSize; - } + ensureStringBufferCanHold(result, 1024); + CuAssertIntEquals(tc, 2048, result->currentStringBufferSize); + + ensureStringBufferCanHold(result, 1024); + CuAssertIntEquals(tc, 2048, result->currentStringBufferSize); + + /* This becomes 0 after we add 1 for the '\0' */ + ensureStringBufferCanHold(result, -1); + CuAssertIntEquals(tc, 2048, result->currentStringBufferSize); + + ensureStringBufferCanHold(result, 1024 * 1024 - 1); + CuAssertIntEquals(tc, 1024 * 1024, result->currentStringBufferSize); + + ensureStringBufferCanHold(result, 1024 * 1024 - 1); + CuAssertIntEquals(tc, 1024 * 1024, result->currentStringBufferSize); + + ensureStringBufferCanHold(NULL, 1024); + + d_string_free(result, true); } +#endif /// Append null-terminated string to end of dynamic string void d_string_append(DString * baseString, const char * appendedString) { - size_t appendedStringLength = strlen(appendedString); + if (baseString && appendedString) { + size_t appendedStringLength = strlen(appendedString); - if ((appendedString != NULL) && (appendedStringLength > 0)) { - size_t newStringLength = baseString->currentStringLength + appendedStringLength; - ensureStringBufferCanHold(baseString, newStringLength); + if (appendedStringLength > 0) { + size_t newStringLength = baseString->currentStringLength + appendedStringLength; + ensureStringBufferCanHold(baseString, newStringLength); - /* We already know where the current string ends, so pass that as the starting address for strncat */ - strncat(baseString->str + baseString->currentStringLength, appendedString, appendedStringLength); - baseString->currentStringLength = newStringLength; + /* We already know where the current string ends, so pass that as the starting address for strncat */ + strncat(baseString->str + baseString->currentStringLength, appendedString, appendedStringLength); + baseString->currentStringLength = newStringLength; + } } } +#ifdef TEST +void Test_d_string_append(CuTest* tc) { + char * test = "foo"; + + DString * result = d_string_new(test); + + d_string_append(result, "bar"); + CuAssertStrEquals(tc, "foobar", result->str); + + d_string_append(result, ""); + CuAssertStrEquals(tc, "foobar", result->str); + + d_string_append(result, NULL); + CuAssertStrEquals(tc, "foobar", result->str); + + d_string_append(NULL, "foo"); + + d_string_free(result, true); +} +#endif + + /// Append single character to end of dynamic string void d_string_append_c(DString * baseString, char appendedCharacter) { - size_t newSizeNeeded = baseString->currentStringLength + 1; - ensureStringBufferCanHold(baseString, newSizeNeeded); + if (baseString && appendedCharacter) { + size_t newSizeNeeded = baseString->currentStringLength + 1; + ensureStringBufferCanHold(baseString, newSizeNeeded); + + baseString->str[baseString->currentStringLength] = appendedCharacter; + baseString->currentStringLength++; + baseString->str[baseString->currentStringLength] = '\0'; + } +} + + +#ifdef TEST +void Test_d_string_append_c(CuTest* tc) { + char * test = "foo"; - baseString->str[baseString->currentStringLength] = appendedCharacter; - baseString->currentStringLength++; - baseString->str[baseString->currentStringLength] = '\0'; + DString * result = d_string_new(test); + + d_string_append_c(result, 'z'); + CuAssertStrEquals(tc, "fooz", result->str); + CuAssertIntEquals(tc, 4, result->currentStringLength); + + d_string_append_c(result, 0); + CuAssertStrEquals(tc, "fooz", result->str); + CuAssertIntEquals(tc, 4, result->currentStringLength); + + d_string_append_c(NULL, 'f'); + + d_string_free(result, true); } +#endif /// Append array of characters to end of dynamic string void d_string_append_c_array(DString * baseString, const char * appendedChars, size_t bytes) { - size_t newSizeNeeded = baseString->currentStringLength + bytes; - ensureStringBufferCanHold(baseString, newSizeNeeded); + if (baseString && appendedChars) { + if (bytes == -1) { + // This is the same as regular append + d_string_append(baseString, appendedChars); + } else { + if (appendedChars) { + size_t newSizeNeeded = baseString->currentStringLength + bytes; + ensureStringBufferCanHold(baseString, newSizeNeeded); + + memcpy(baseString->str + baseString->currentStringLength, appendedChars, bytes); + + baseString->currentStringLength = newSizeNeeded; + baseString->str[baseString->currentStringLength] = '\0'; + } + } + } +} + + +#ifdef TEST +void Test_d_string_append_c_array(CuTest* tc) { + char * test = "foo"; - memcpy(baseString->str + baseString->currentStringLength, appendedChars, bytes); + DString * result = d_string_new(test); - baseString->currentStringLength = newSizeNeeded; - baseString->str[baseString->currentStringLength] = '\0'; + d_string_append_c_array(result, "bar", 3); + CuAssertStrEquals(tc, "foobar", result->str); + CuAssertIntEquals(tc, 6, result->currentStringLength); + + d_string_append_c_array(result, "baz", -1); + CuAssertStrEquals(tc, "foobarbaz", result->str); + CuAssertIntEquals(tc, 9, result->currentStringLength); + + d_string_append_c_array(result, NULL, 0); + CuAssertStrEquals(tc, "foobarbaz", result->str); + CuAssertIntEquals(tc, 9, result->currentStringLength); + + d_string_append_c_array(result, NULL, -1); + CuAssertStrEquals(tc, "foobarbaz", result->str); + CuAssertIntEquals(tc, 9, result->currentStringLength); + + d_string_append_c_array(NULL, "foo", -1); + + d_string_free(result, true); } +#endif /// Append to end of dynamic string using format specifier void d_string_append_printf(DString * baseString, const char * format, ...) { - va_list args; - va_start(args, format); + if (baseString && format) { + va_list args; + va_start(args, format); - char* formattedString = NULL; - vasprintf(&formattedString, format, args); + char* formattedString = NULL; + vasprintf(&formattedString, format, args); - if (formattedString != NULL) { - d_string_append(baseString, formattedString); - free(formattedString); + if (formattedString != NULL) { + d_string_append(baseString, formattedString); + free(formattedString); + } + + va_end(args); } +} + + +#ifdef TEST +void Test_d_string_append_printf(CuTest* tc) { + char * test = "foo"; - va_end(args); + DString * result = d_string_new(test); + + d_string_append_printf(result, "%dbar%d", 5, 7); + CuAssertStrEquals(tc, "foo5bar7", result->str); + CuAssertIntEquals(tc, 8, result->currentStringLength); + + d_string_append_printf(result, NULL); + CuAssertStrEquals(tc, "foo5bar7", result->str); + CuAssertIntEquals(tc, 8, result->currentStringLength); + + d_string_append_printf(result, NULL, 5, 7); + CuAssertStrEquals(tc, "foo5bar7", result->str); + CuAssertIntEquals(tc, 8, result->currentStringLength); + + d_string_append_printf(NULL, "foo"); + + d_string_free(result, true); } +#endif /// Prepend null-terminated string to end of dynamic string void d_string_prepend(DString * baseString, const char * prependedString) { - size_t prependedStringLength = strlen(prependedString); + if (baseString && prependedString) { + size_t prependedStringLength = strlen(prependedString); - if ((prependedString != NULL) && (prependedStringLength > 0)) { - size_t newStringLength = baseString->currentStringLength + prependedStringLength; - ensureStringBufferCanHold(baseString, newStringLength); + if (prependedStringLength > 0) { + size_t newStringLength = baseString->currentStringLength + prependedStringLength; + ensureStringBufferCanHold(baseString, newStringLength); - memmove(baseString->str + prependedStringLength, baseString->str, baseString->currentStringLength); - strncpy(baseString->str, prependedString, prependedStringLength); - baseString->currentStringLength = newStringLength; - baseString->str[baseString->currentStringLength] = '\0'; + memmove(baseString->str + prependedStringLength, baseString->str, baseString->currentStringLength); + strncpy(baseString->str, prependedString, prependedStringLength); + baseString->currentStringLength = newStringLength; + baseString->str[baseString->currentStringLength] = '\0'; + } } } +#ifdef TEST +void Test_d_string_prepend(CuTest* tc) { + char * test = "foo"; + + DString * result = d_string_new(test); + + d_string_prepend(result, "bar"); + CuAssertStrEquals(tc, "barfoo", result->str); + CuAssertIntEquals(tc, 6, result->currentStringLength); + + d_string_prepend(result, NULL); + CuAssertStrEquals(tc, "barfoo", result->str); + CuAssertIntEquals(tc, 6, result->currentStringLength); + + d_string_prepend(NULL, "bar"); + + d_string_free(result, true); +} +#endif + + /// Insert null-terminated string inside dynamic string void d_string_insert(DString * baseString, size_t pos, const char * insertedString) { - size_t insertedStringLength = strlen(insertedString); + if (baseString && insertedString) { + size_t insertedStringLength = strlen(insertedString); + + if (insertedStringLength > 0) { + if (pos > baseString->currentStringLength) { + pos = baseString->currentStringLength; + } + + size_t newStringLength = baseString->currentStringLength + insertedStringLength; + ensureStringBufferCanHold(baseString, newStringLength); + + /* Shift following string to 'right' */ + memmove(baseString->str + pos + insertedStringLength, baseString->str + pos, baseString->currentStringLength - pos); + strncpy(baseString->str + pos, insertedString, insertedStringLength); + baseString->currentStringLength = newStringLength; + baseString->str[baseString->currentStringLength] = '\0'; + } + } +} + + +#ifdef TEST +void Test_d_string_insert(CuTest* tc) { + char * test = "foo"; + + DString * result = d_string_new(test); + + d_string_insert(result, 2, "bar"); + CuAssertStrEquals(tc, "fobaro", result->str); + CuAssertIntEquals(tc, 6, result->currentStringLength); + + d_string_insert(result, -1, "bar"); + CuAssertStrEquals(tc, "fobarobar", result->str); + CuAssertIntEquals(tc, 9, result->currentStringLength); + + d_string_insert(result, -1, NULL); + CuAssertStrEquals(tc, "fobarobar", result->str); + CuAssertIntEquals(tc, 9, result->currentStringLength); + + d_string_insert(NULL, 0, NULL); - if ((insertedString != NULL) && (insertedStringLength > 0)) { + d_string_free(result, true); +} +#endif + + +/// Insert single character inside dynamic string +void d_string_insert_c(DString * baseString, size_t pos, char insertedCharacter) { + if (baseString && insertedCharacter) { if (pos > baseString->currentStringLength) { pos = baseString->currentStringLength; } - size_t newStringLength = baseString->currentStringLength + insertedStringLength; - ensureStringBufferCanHold(baseString, newStringLength); + size_t newSizeNeeded = baseString->currentStringLength + 1; + ensureStringBufferCanHold(baseString, newSizeNeeded); /* Shift following string to 'right' */ - memmove(baseString->str + pos + insertedStringLength, baseString->str + pos, baseString->currentStringLength - pos); - strncpy(baseString->str + pos, insertedString, insertedStringLength); - baseString->currentStringLength = newStringLength; + memmove(baseString->str + pos + 1, baseString->str + pos, baseString->currentStringLength - pos); + + baseString->str[pos] = insertedCharacter; + baseString->currentStringLength++; baseString->str[baseString->currentStringLength] = '\0'; } } -/// Insert single character inside dynamic string -void d_string_insert_c(DString * baseString, size_t pos, char insertedCharacter) { - if (pos > baseString->currentStringLength) { - pos = baseString->currentStringLength; - } +#ifdef TEST +void Test_d_string_insert_c(CuTest* tc) { + char * test = "foo"; + + DString * result = d_string_new(test); - size_t newSizeNeeded = baseString->currentStringLength + 1; - ensureStringBufferCanHold(baseString, newSizeNeeded); + d_string_insert_c(result, 2, 'b'); + CuAssertStrEquals(tc, "fobo", result->str); + CuAssertIntEquals(tc, 4, result->currentStringLength); - /* Shift following string to 'right' */ - memmove(baseString->str + pos + 1, baseString->str + pos, baseString->currentStringLength - pos); + d_string_insert_c(result, -1, 'z'); + CuAssertStrEquals(tc, "foboz", result->str); + CuAssertIntEquals(tc, 5, result->currentStringLength); - baseString->str[pos] = insertedCharacter; - baseString->currentStringLength++; - baseString->str[baseString->currentStringLength] = '\0'; + d_string_insert_c(result, 3, 0); + CuAssertStrEquals(tc, "foboz", result->str); + CuAssertIntEquals(tc, 5, result->currentStringLength); + + d_string_insert_c(NULL, 0, 0); + + d_string_free(result, true); } +#endif /// Insert inside dynamic string using format specifier void d_string_insert_printf(DString * baseString, size_t pos, const char * format, ...) { - va_list args; - va_start(args, format); + if (baseString && format) { + va_list args; + va_start(args, format); - char* formattedString = NULL; - vasprintf(&formattedString, format, args); + char* formattedString = NULL; + vasprintf(&formattedString, format, args); - if (formattedString != NULL) { - d_string_insert(baseString, pos, formattedString); - free(formattedString); + if (formattedString != NULL) { + d_string_insert(baseString, pos, formattedString); + free(formattedString); + } + + va_end(args); } +} + + +#ifdef TEST +void Test_d_string_insert_printf(CuTest* tc) { + char * test = "foo"; + + DString * result = d_string_new(test); + + d_string_insert_printf(result, 2, "%dbar%d", 5, 7); + CuAssertStrEquals(tc, "fo5bar7o", result->str); + CuAssertIntEquals(tc, 8, result->currentStringLength); + + d_string_insert_printf(result, -1, "z", 5, 7); + CuAssertStrEquals(tc, "fo5bar7oz", result->str); + CuAssertIntEquals(tc, 9, result->currentStringLength); - va_end(args); + d_string_insert_printf(NULL, 0, NULL); + + d_string_free(result, true); } +#endif /// Erase portion of dynamic string void d_string_erase(DString * baseString, size_t pos, size_t len) { - if ((pos > baseString->currentStringLength) || (len <= 0)) { - return; - } + if (baseString) { + if ((pos > baseString->currentStringLength) || (len <= 0)) { + return; + } - if ((pos + len) >= baseString->currentStringLength) { - len = -1; - } + if ((pos + len) >= baseString->currentStringLength) { + len = -1; + } - if (len == -1) { - baseString->currentStringLength = pos; - } else { - memmove(baseString->str + pos, baseString->str + pos + len, baseString->currentStringLength - pos - len); - baseString->currentStringLength -= len; + if (len == -1) { + baseString->currentStringLength = pos; + } else { + memmove(baseString->str + pos, baseString->str + pos + len, baseString->currentStringLength - pos - len); + baseString->currentStringLength -= len; + } + + baseString->str[baseString->currentStringLength] = '\0'; } +} + + +#ifdef TEST +void Test_d_string_erase(CuTest* tc) { + char * test = "foobar"; + + DString * result = d_string_new(test); + + d_string_erase(result, 2, 1); + CuAssertStrEquals(tc, "fobar", result->str); + CuAssertIntEquals(tc, 5, result->currentStringLength); - baseString->str[baseString->currentStringLength] = '\0'; + d_string_erase(result, -1, -1); + CuAssertStrEquals(tc, "fobar", result->str); + CuAssertIntEquals(tc, 5, result->currentStringLength); + + d_string_erase(result, 2, -1); + CuAssertStrEquals(tc, "fo", result->str); + CuAssertIntEquals(tc, 2, result->currentStringLength); + + d_string_erase(NULL, 0, 0); + + d_string_free(result, true); } +#endif + /// Copy a portion of dynamic string char * d_string_copy_substring(DString * d, size_t start, size_t len) { - char * result; + if (d) { + char * result; + + if ((len == -1) && (start < d->currentStringLength)) { + len = d->currentStringLength - start; + } else { + if (start + len > d->currentStringLength) { + fprintf(stderr, "d_string: Asked to copy invalid substring range.\n"); + fprintf(stderr, "start: %lu len: %lu string: %lu\n", start, len, + d->currentStringLength); + return NULL; + } + } + + result = malloc(len + 1); + strncpy(result, &d->str[start], len); + result[len] = '\0'; - if (len == -1) { - len = d->currentStringLength - start; + return result; } else { - if (start + len > d->currentStringLength) { - fprintf(stderr, "d_string: Asked to copy invalid substring range.\n"); - fprintf(stderr, "start: %lu len: %lu string: %lu\n", start, len, - d->currentStringLength); - return NULL; - } + return NULL; } +} + + +#ifdef TEST +void Test_d_string_copy_substring(CuTest* tc) { + char * test = "foobar"; + + DString * result = d_string_new(test); + + test = d_string_copy_substring(result, 0, -1); + CuAssertStrEquals(tc, "foobar", test); + free(test); + + test = d_string_copy_substring(result, 2, 3); + CuAssertStrEquals(tc, "oba", test); + free(test); - result = malloc(len + 1); - strncpy(result, &d->str[start], len); - result[len] = '\0'; + test = d_string_copy_substring(result, 8, 2); + CuAssertStrEquals(tc, NULL, test); + free(test); - return result; + test = d_string_copy_substring(result, -1, -1); + CuAssertStrEquals(tc, NULL, test); + free(test); + + test = d_string_copy_substring(NULL, -1, -1); + CuAssertStrEquals(tc, NULL, test); + + d_string_free(result, true); } +#endif /// Replace occurences of "original" with "replace" inside the specified range /// Returns the change in overall length long d_string_replace_text_in_range(DString * d, size_t pos, size_t len, const char * original, const char * replace) { - long delta = 0; // Overall change in length + if (d && original && replace) { + long delta = 0; // Overall change in length + + long len_o = strlen(original); + long len_r = strlen(replace); + long change = len_r - len_o; // Change in length for each replacement + + size_t stop; + + if (len == -1) { + stop = d->currentStringLength; + } else { + stop = pos + len; - long len_o = strlen(original); - long len_r = strlen(replace); - long change = len_r - len_o; // Change in length for each replacement + if (stop > d->currentStringLength) { + stop = d->currentStringLength; + } + } + + char * match = strstr(&(d->str[pos]), original); - size_t stop; + while (match && (match - d->str < stop)) { + pos = match - d->str; + d_string_erase(d, match - d->str, len_o); + d_string_insert(d, match - d->str, replace); + + delta += change; + stop += change; + match = strstr(d->str + pos + len_r, original); + } - if (len == -1) { - stop = d->currentStringLength; + return delta; } else { - stop = pos + len; + return 0; } +} - char * match = strstr(&(d->str[pos]), original); - while (match && (match - d->str < stop)) { - pos = match - d->str; - d_string_erase(d, match - d->str, len_o); - d_string_insert(d, match - d->str, replace); +#ifdef TEST +void Test_d_string_replace_text_in_range(CuTest* tc) { + char * test = "foobarfoobarfoo"; + long delta = 0; - delta += change; - stop += change; - match = strstr(d->str + pos + len_r, original); - } + DString * result = d_string_new(test); - return delta; -} + delta = d_string_replace_text_in_range(result, 100, 3, "foo", "zapz"); + CuAssertIntEquals(tc, 15, result->currentStringLength); + CuAssertStrEquals(tc, "foobarfoobarfoo", result->str); + CuAssertIntEquals(tc, delta, 0); + + delta = d_string_replace_text_in_range(result, 0, 3, "foo", "zapz"); + CuAssertIntEquals(tc, 16, result->currentStringLength); + CuAssertStrEquals(tc, "zapzbarfoobarfoo", result->str); + CuAssertIntEquals(tc, delta, 1); + + delta = d_string_replace_text_in_range(result, 0, 100, "foo", "zapz"); + CuAssertIntEquals(tc, 18, result->currentStringLength); + CuAssertStrEquals(tc, "zapzbarzapzbarzapz", result->str); + CuAssertIntEquals(tc, delta, 2); + delta = d_string_replace_text_in_range(result, 0, -1, NULL, "zap"); + CuAssertIntEquals(tc, 18, result->currentStringLength); + CuAssertStrEquals(tc, "zapzbarzapzbarzapz", result->str); + CuAssertIntEquals(tc, delta, 0); + + d_string_replace_text_in_range(result, 0, -1, "foo", NULL); + CuAssertIntEquals(tc, 18, result->currentStringLength); + CuAssertStrEquals(tc, "zapzbarzapzbarzapz", result->str); + + d_string_replace_text_in_range(NULL, 0, -1, "foo", NULL); + + d_string_free(result, true); +} +#endif