diff options
author | Joseph Hunkeler <jhunkeler@users.noreply.github.com> | 2020-05-24 13:25:01 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-24 13:25:01 -0400 |
commit | c205840e737b23614a686a9675b896106cee5c64 (patch) | |
tree | f2eb9d93edb1540221daea3682bf13254d28128c | |
parent | 03e39ae5dcd4002ac9657a550c48b8e9f85c449c (diff) | |
parent | a38fbb5766b48a9695ea139f79634fc746642bdd (diff) | |
download | spmc-c205840e737b23614a686a9675b896106cee5c64.tar.gz |
Merge pull request #37 from jhunkeler/version-fixups
Version fixups
-rw-r--r-- | include/str.h | 2 | ||||
-rw-r--r-- | include/version_spec.h | 24 | ||||
-rw-r--r-- | lib/str.c | 27 | ||||
-rw-r--r-- | lib/version_spec.c | 422 | ||||
-rw-r--r-- | src/CMakeLists.txt | 8 | ||||
-rw-r--r-- | tests/framework.h | 4 | ||||
-rw-r--r-- | tests/test_str_isdigit_s.c | 21 | ||||
-rw-r--r-- | tests/test_str_tolower_s.c | 25 | ||||
-rw-r--r-- | tests/test_version.c | 95 |
9 files changed, 306 insertions, 322 deletions
diff --git a/include/str.h b/include/str.h index 468f674..ae54997 100644 --- a/include/str.h +++ b/include/str.h @@ -34,5 +34,7 @@ int isquoted(char *sptr); char *normalize_space(char *s); char **strdup_array(char **array); int strcmp_array(const char **a, const char **b); +int isdigit_s(char *s); +char *tolower_s(char *s); #endif //SPM_STR_H diff --git a/include/version_spec.h b/include/version_spec.h index aab6540..b8d3260 100644 --- a/include/version_spec.h +++ b/include/version_spec.h @@ -4,10 +4,11 @@ #ifndef SPM_VERSION_SPEC_H #define SPM_VERSION_SPEC_H -#define VERSION_BASE 16 -#define VERSION_ADDENDUM_BITS 16 +#define VERSION_MAX 8 +#define VERSION_BASE 10 #define VERSION_DELIM "." -#define VERSION_LOCAL "=" +#define VERSION_DELIM_LOCAL "+" +#define VERSION_LOCAL_MAX 255 #define VERSION_OPERATORS " ~!=<>" #define VERSION_NOOP 1 << 0 #define VERSION_EQ 1 << 1 @@ -16,13 +17,18 @@ #define VERSION_LT 1 << 4 #define VERSION_COMPAT 1 << 5 -// version_spec.c -char *version_suffix_get_alpha(char *str); -char *version_suffix_get_modifier(char *str); -int64_t version_suffix_modifier_calc(char *str); -int version_suffix_alpha_calc(char *str); +struct Version { + char *local; + uint64_t asInt; + uint32_t part[VERSION_MAX]; +}; + +struct Version *version_init(); +int version_read(struct Version **version, char *s); +void version_info(struct Version *version); + uint64_t version_from(const char *str); -int version_spec_from(const char *op); +unsigned int version_spec_from(const char *op); ManifestPackage **find_by_spec(const Manifest *manifest, const char *name, const char *op, const char *version_str); int pep440_match(const char *version); struct PEP440 *pep440_version(const char *version); @@ -817,3 +817,30 @@ int strcmp_array(const char **a, const char **b) { } return result; } + +/** + * Determine whether a string is comprised of digits + * @param s + * @return 0=no, 1=yes + */ +int isdigit_s(char *s) { + for (size_t i = 0; s[i] != '\0'; i++) { + if (isdigit(s[i]) == 0) { + return 0; // non-digit found, fail + } + } + return 1; // all digits, succeed +} + +/** + * Convert input string to lowercase + * @param s + * @return pointer to input string + */ +char *tolower_s(char *s) { + for (size_t i = 0; s[i] != '\0'; i++) { + s[i] = (char)tolower(s[i]); + } + return s; +} + diff --git a/lib/version_spec.c b/lib/version_spec.c index 928fc0f..54f814c 100644 --- a/lib/version_spec.c +++ b/lib/version_spec.c @@ -4,358 +4,158 @@ #include "spm.h" /** - * - * @param str - * @return - */ -char *version_suffix_get_alpha(char *str) { - size_t i; - size_t len = strlen(str); - for (i = 0; i < len; i++) { - // return pointer to the first alphabetic character we find - if (isalpha(str[i])) { - return &str[i]; - } - } - return NULL; -} - -/** - * - * @param str + * Get the ASCII index of a character from '0' + * @param c * @return */ -char *version_suffix_get_modifier(char *str) { - size_t i; - char *modifiers[] = { - "r", // VCS revision - "rc", // Release Candidate - "pre", // Pre-Release - "dev", // Development - "post", // Post-Release - NULL, - }; - for (i = 0; i < strlen(str); i++) { - for (int m = 0; modifiers[m] != NULL; m++) { - if (strncasecmp(&str[i], modifiers[m], strlen(modifiers[m])) == 0) { - return &str[i]; - } - } - } - return NULL; -} - -/** - * - * @param str - * @return - */ -int64_t version_suffix_modifier_calc(char *str) { - int64_t result = 0; - char *tmp_s = str; - - if (strncasecmp(str, "rc", 2) == 0) { - // do rc - tmp_s += strlen("rc"); - if (isdigit(*tmp_s)) { - result -= atoi(tmp_s); - } - else { - result -= 1; - } - } - else if (strncasecmp(str, "pre", 3) == 0) { - // do pre - tmp_s += strlen("pre"); - if (isdigit(*tmp_s)) { - result -= atoi(tmp_s); - } - else { - result -= 1; - } - } - else if (strncasecmp(str, "dev", 3) == 0) { - // do dev - tmp_s += strlen("dev"); - if (isdigit(*tmp_s)) { - result -= atoi(tmp_s); - } - else { - result -= 1; - } - } - else if (strncasecmp(str, "post", 4) == 0) { - // do post - tmp_s += strlen("post"); - if (isdigit(*tmp_s)) { - result += atoi(tmp_s); - } - else { - result += 1; - } - } - +static int version_reindex(char c) { + int result; + result = c - '0'; return result; } /** - * - * @param str - * @return + * Initialize `struct Version` for use by other `version_` functions + * @return pointer to `struct Version` */ -int version_suffix_alpha_calc(char *str) { - int x = 0; - char chs[255]; - char *ch = chs; - memset(chs, '\0', sizeof(chs)); - strncpy(chs, str, strlen(str)); - - // Handle cases where the two suffixes are not delimited by anything - // Start scanning one character ahead of the alphabetic suffix and terminate the string - // when/if we reach another alphabetic character (presumably a version modifer) - for (int i = 1; chs[i] != '\0'; i++) { - if (isalpha(chs[i])) { - chs[i] = '\0'; - } - } - - // Convert character to hex-ish - x = (*ch - 'a') + 0xa; - - // Ensure the string ends with a digit - if (strlen(str) == 1) { - strcat(ch, "0"); - } - - // Convert trailing numerical value to an integer - while (*ch != '\0') { - if (!isdigit(*ch)) { - ch++; - continue; - } - x += (int)strtol(ch, NULL, 10); - break; - } +struct Version *version_init() { + struct Version *result; - return x; -} + result = calloc(1, sizeof(struct Version)); + result->local = calloc(VERSION_LOCAL_MAX, sizeof(char)); -static int isdigits(char *s) { - for (size_t i = 0; s[i] != '\0'; i++) { - if (isdigit(s[i]) == 0) { - return 0; // non-digit found, fail - } + for (size_t i = 0; i < VERSION_MAX; i++) { + result->part[i] = 0; } - return 1; // all digits, succeed -} -static int reindex(char c) { - int result = c - '0'; return result; } -static char *tolower_s(char *s) { - for (size_t i = 0; s[i] != '\0'; i++) { - s[i] = tolower(s[i]); - } - return s; -} - /** - * Convert a string (`x.y.z.nnnn` or `1abcdefg2` - doesn't matter) to an integer - * @param s - * @return + * Populate `Version` struct with information derived from input string `s` + * @param version `struct Version` + * @param s version string + * @return 0=success, <0=error */ -uint64_t version_from(const char *str) { - uint64_t result; - uint64_t addendum; - char *vstr; - char *result_tmp; +int version_read(struct Version **version, char *s) { + char *str; char **part; - StrList *vconv; - - // Check input string isn't NULL - if (str == NULL) { - return 0; - } + char *local_version = NULL; + size_t num_parts; - // Make a copy of the input string - vstr = strdup(str); - if (vstr == NULL) { - spmerrno = errno; - return 0; + if (s == NULL) { + return -1; } - // Initialize StrList - vconv = strlist_init(); - if (vconv == NULL) { - spmerrno = errno; - return 0; + str = strdup(s); + if (str == NULL) { + return -1; } - // Convert any uppercase letters to lowercase - vstr = tolower_s(vstr); + str = tolower_s(str); - // Pop local version suffix - char *local_version = strstr(vstr, VERSION_LOCAL); - if (local_version != NULL) { + // Store any local version data stored in the input string (unused) + if ((local_version = strstr(str, VERSION_DELIM_LOCAL)) != NULL) { + strncpy((*version)->local, local_version + 1, VERSION_LOCAL_MAX - 1); *local_version = '\0'; } - // Split version string on periods, if any - part = split(vstr, VERSION_DELIM); - if (part == NULL) { - spmerrno = errno; - return 0; - } + // Split the input string + part = split(str, VERSION_DELIM); - // Populate our StrList with version information - for (size_t i = 0; part[i] != NULL; i++) { - char tmp[255] = {0}; - memset(tmp, '\0', sizeof(tmp)); + // Count records split from the input string + for (num_parts = 0; part[num_parts] != NULL; num_parts++); - if (isdigits(part[i])) { - // Every character in the string is a digit, so append it as-is - strlist_append(vconv, part[i]); + // Last record of version->part is reserved for additional information + uint32_t *addendum = &(*version)->part[VERSION_MAX - 1]; + + // Turn those numbers into... numbers + for (size_t i = 0; i < num_parts; i++) { + uint32_t value = 0; + + if (isdigit_s(part[i])) { + // Store the value as-is + value = strtoul(part[i], NULL, VERSION_BASE); } else { - // Not all characters were digits - char *data = part[i]; - int digit = isdigit(*data); - - // The first character is a digit. Try to consume the whole value - if (digit > 0) { - for (size_t ch = 0; *data != '\0' && isdigit(*data) > 0; ch++, data++) { - tmp[ch] = *data; + char tmp[255] = {0}; + char *other = part[i]; + if (isdigit(part[i][0])) { + for (size_t c = 0; isdigit(part[i][c]); c++) { + tmp[c] = part[i][c]; + other++; } - strlist_append(vconv, tmp); + value = strtoul(tmp, NULL, VERSION_BASE); } - - while (*data != '\0') { - // The "+" prefix below indicates the value shall be added to the addendum - // Not a digit so subtract its ASCII value from '0' with reindex - // Calculate character index + 1 (i.e. a=1, b=2, ..., z=25) - sprintf(tmp, "+%d", reindex(*data) + 1); - - strlist_append(vconv, tmp); - data++; + // Reindex all alphanumeric characters from ASCII '0'. Ignore everything else. + for (size_t c = 0; c < strlen(other); c++) { + if (isalnum(other[c])) { + // Assign version addendum field + *addendum += version_reindex(other[c]); + } } } + // Assign part with integer value + (*version)->part[i] = value; } - split_free(part); - // Construct the suffix portion of the version. This value is added to the result to maximize - // the resolution between different versions (making (1.1.0a > 1.1.0 && 1.1.1 > 1.1.0a) possible) - addendum = 0L; - for (size_t i = 0; i < strlist_count(vconv); i++) { - char *item = strlist_item(vconv, i); - if (*item == '+') { - addendum += strtoull(&item[1], NULL, VERSION_BASE); - // Purge this record from the StrList now that it has fulfilled its purpose - strlist_remove(vconv, i); - i--; - } + // Convert all of the individual parts into a single integer + for (size_t i = 0; i < VERSION_MAX; i++) { + (*version)->asInt = (*version)->asInt << 8 | (*version)->part[i]; } - result_tmp = join(vconv->data, ""); - - result = strtoull(result_tmp, NULL, VERSION_BASE); - result <<= VERSION_ADDENDUM_BITS; - result += addendum + strlen(result_tmp); - - free(vstr); - strlist_free(vconv); - return result; + split_free(part); + free(str); + return 0; } + /** - * - * @param version_str - * @return + * Free `struct Version` populated by `version_init` + * @param version */ -int64_t version_from_old(const char *version_str) { - const char *delim = "."; - int64_t result = 0; - if (version_str == NULL) { - return 0; - } - - int seen_alpha = 0; // Does the tail contain a single character, but not a modifier? - int seen_modifier = 0; // Does the tail contain "rc", "dev", "pre", and so forth? - char head[255]; // digits of the string - char tail[255]; // alphabetic characters of the string - char *suffix_alpha = NULL; // pointer to location of the first character after the version - char *suffix_modifier = NULL; // pointer to location of the modifier after the version - char *x = NULL; // pointer to each string delimited by "." - char *vstr = strdup(version_str); - if (!vstr) { - perror("Version string copy"); - return -1; +void version_free(struct Version *version) { + if (version == NULL) { + return; } - memset(head, '\0', sizeof(head)); - memset(tail, '\0', sizeof(tail)); - - // Split the version into parts - while ((x = strsep(&vstr, delim)) != NULL) { - int64_t tmp = 0; - - // populate the head (numeric characters) - int has_digit = isdigit(*x); - int has_alpha = isalpha(*x); - - strncpy(head, x, strlen(x)); - for (size_t i = 0; i < strlen(head); i++) { - if (isalpha(head[i])) { - // populate the tail (alphabetic characters) - strncpy(tail, &head[i], strlen(&head[i])); - head[i] = '\0'; - break; - } - } - - // Detect alphabetic suffix - if (!seen_alpha) { - if ((suffix_alpha = version_suffix_get_alpha(x)) != NULL) { - seen_alpha = 1; - } - } - - // Detect modifier suffix - if (!seen_modifier) { - if ((suffix_modifier = version_suffix_get_modifier(x)) != NULL) { - seen_modifier = 1; - } - } + free(version->local); + free(version); +} - // Stop processing if the head starts with something other than numbers - if (!isdigit(head[0])) { - break; - } +/** + * Print information about a version (stdout) + * @param version `struct Version` + */ +void version_info(struct Version *version) { + printf("major: %d, ", version->part[0]); + printf("minor: %d, ", version->part[1]); + printf("patch: %d, ", version->part[2]); + for (size_t i = 3; i < VERSION_MAX; i++) { + printf("other[%zu]: %d, ", i, version->part[i]); + } + printf("local: '%s', ", version->local); + printf("int : %#llx (%llu)\n", version->asInt, version->asInt); +} - // Convert the head to an integer - tmp = strtoul(head, NULL, 10); - // Update result. Each portion of the numeric version is its own byte - // Version PARTS are limited to 255 - result = result << 8 | tmp; +/** + * Convert version string to an integer + * @param str version string + * @return version as integer + */ +uint64_t version_from(const char *str) { + // Accept NULL as version "zero" + if (str == NULL) { + return 0; } - if (suffix_alpha != NULL) { - // Convert the alphabetic suffix to an integer - int64_t sac = version_suffix_alpha_calc(suffix_alpha); - result += sac; - } + uint64_t result = 0LL; + char *v = strdup(str); + struct Version *version = version_init(); - if (suffix_modifier != NULL) { - // Convert the modifier string to an integer - int64_t smc = version_suffix_modifier_calc(suffix_modifier); - if (smc < 0) { - result -= ~smc + 1; - } - else { - result += smc; - } - } + version_read(&version, v); + result = version->asInt; - free(vstr); + free(v); + version_free(version); return result; } @@ -364,8 +164,8 @@ int64_t version_from_old(const char *version_str) { * @param op * @return */ -int version_spec_from(const char *op) { - int flags = VERSION_NOOP; +unsigned int version_spec_from(const char *op) { + unsigned int flags = VERSION_NOOP; size_t len = strlen(op); for (size_t i = 0; i < len; i++) { if (op[i] == '>') { @@ -396,8 +196,8 @@ int version_spec_from(const char *op) { static int _find_by_spec_compare(const void *a, const void *b) { const ManifestPackage *aa = *(const ManifestPackage**)a; const ManifestPackage *bb = *(const ManifestPackage**)b; - int64_t version_a = version_from(aa->version); - int64_t version_b = version_from(bb->version); + uint64_t version_a = version_from(aa->version); + uint64_t version_b = version_from(bb->version); return version_a > version_b; } @@ -420,9 +220,9 @@ ManifestPackage **find_by_spec(const Manifest *manifest, const char *name, const for (size_t i = 0; i < manifest->records; i++) { if (strcmp(manifest->packages[i]->name, name) == 0) { - int64_t version_a = version_from(manifest->packages[i]->version); - int64_t version_b = version_from(version_str); - int spec = version_spec_from(op); + uint64_t version_a = version_from(manifest->packages[i]->version); + uint64_t version_b = version_from(version_str); + unsigned int spec = version_spec_from(op); int res = 0; if (spec & VERSION_GT && spec & VERSION_EQ) { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6d27935..623ea68 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,6 +12,14 @@ add_executable(spm target_link_directories(spm PUBLIC ${OpenSSL_LIBRARY_DIRS} ${CURL_LIBRARY_DIRS}) target_link_libraries(spm libspm ${OpenSSL_LIBRARIES} ${CURL_LIBRARIES}) +## Uncomment to build a scratch executable (i.e. for quick library development / verification) +#add_executable(spm_scratch +# scratch.c +#) +# +#target_link_directories(spm_scratch PUBLIC ${OpenSSL_LIBRARY_DIRS} ${CURL_LIBRARY_DIRS}) +#target_link_libraries(spm_scratch libspm ${OpenSSL_LIBRARIES} ${CURL_LIBRARIES}) + if (LINUX) target_link_libraries(spm libspm rt) endif() diff --git a/tests/framework.h b/tests/framework.h index aefdef2..c9170b6 100644 --- a/tests/framework.h +++ b/tests/framework.h @@ -153,8 +153,8 @@ char *mock_size(size_t size, const char *fill_byte) { char *mock_image(int img_type, const char *img_name, char **_extra_compiler_args, int *exit_code) { char libsuffix[10] = {0,}; char code[255] = {0,}; - char code_filename[FILENAME_MAX] = {0,}; - char img_filename[FILENAME_MAX] = {0,}; + char code_filename[255] = {0,}; + char img_filename[255] = {0,}; char cmd[PATH_MAX] = {0,}; char *extra_compiler_args = NULL; Process *proc = NULL; diff --git a/tests/test_str_isdigit_s.c b/tests/test_str_isdigit_s.c new file mode 100644 index 0000000..5dd729c --- /dev/null +++ b/tests/test_str_isdigit_s.c @@ -0,0 +1,21 @@ +#include "spm.h" +#include "framework.h" + +const char *testFmt = "case '%s': returned '%d', expected '%d'\n"; +struct TestCase testCase[] = { + {.caseValue.str = "1234", .truthValue.signed_int = 1}, + {.caseValue.str = "1234000000000", .truthValue.signed_int = 1}, + {.caseValue.str = "1234aa", .truthValue.signed_int = 0}, + {.caseValue.str = "z1234a", .truthValue.signed_int = 0}, + {.caseValue.str = "gabcde", .truthValue.signed_int = 0}, +}; +size_t numCases = sizeof(testCase) / sizeof(struct TestCase); + +int main(int argc, char *argv[]) { + for (size_t i = 0; i < numCases; i++) { + int result = isdigit_s(testCase[i].caseValue.str); + int truth = testCase[i].truthValue.signed_int; + myassert(result == truth, testFmt, testCase[i].caseValue.str, result, truth); + } + return 0; +}
\ No newline at end of file diff --git a/tests/test_str_tolower_s.c b/tests/test_str_tolower_s.c new file mode 100644 index 0000000..f36b23d --- /dev/null +++ b/tests/test_str_tolower_s.c @@ -0,0 +1,25 @@ +#include "spm.h" +#include "framework.h" + +const char *testFmt = "case '%s': returned '%d', expected '%d'\n"; +struct TestCase testCase[] = { + {.caseValue.str = "ThE", .truthValue.sptr = "the"}, + {.caseValue.str = "KIdS", .truthValue.sptr = "kids"}, + {.caseValue.str = "AREn'T", .truthValue.sptr= "aren't"}, + {.caseValue.str = "aLL", .truthValue.sptr = "all"}, + {.caseValue.str = "RiGHt", .truthValue.sptr = "right"}, + {.caseValue.str = "By", .truthValue.sptr = "by"}, + {.caseValue.str = "THe oFfSpRiNg", .truthValue.sptr = "the offspring"}, +}; +size_t numCases = sizeof(testCase) / sizeof(struct TestCase); + +int main(int argc, char *argv[]) { + for (size_t i = 0; i < numCases; i++) { + char *orig = strdup(testCase[i].caseValue.str); + char *result = tolower_s(testCase[i].caseValue.str); + const char *truth = testCase[i].truthValue.sptr; + myassert(strcmp(result, truth) == 0, testFmt, orig, result, truth); + free(orig); + } + return 0; +}
\ No newline at end of file diff --git a/tests/test_version.c b/tests/test_version.c new file mode 100644 index 0000000..79c02d0 --- /dev/null +++ b/tests/test_version.c @@ -0,0 +1,95 @@ +#include "spm.h" +#include "framework.h" + + +const char *testFmt = "case %s: returned %llu (0x%llX), expected >%llu (0x%llX)\n"; +struct TestCase testCase[] = { + {}, +}; +size_t numCases = sizeof(testCase) / sizeof(struct TestCase); + +char *versions[] = { + "0.0.1", "0.0.2", "0.0.3", "0.0.4", "0.0.5", "0.0.6", "0.0.7", "0.0.8", "0.0.9", "0.0.10", + "0.1", "0.1.1", "0.1.2", "0.1.3", "0.1.4", "0.1.5", "0.1.6", "0.1.7", "0.1.8", "0.1.9", "0.1.10", + "0.2", "0.2.1", "0.2.2", "0.2.3", "0.2.4", "0.2.5", "0.2.6", "0.2.7", "0.2.8", "0.2.9", "0.2.10", + "0.9", "0.9.1", "0.9.2", "0.9.3", "0.9.4", "0.9.5", "0.9.6", "0.9.7", "0.9.8", "0.9.9", "0.9.10", + "0.10.0", "0.10.1", "0.10.2", "0.10.3", "0.10.4", "0.10.5", "0.10.6", "0.10.7", "0.10.8", "0.10.9", + "0.10.10", + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "100.1a", "100.1a2", "100.3a10", "101", "101.1", + "2019.1", "2019.2a", "2019.3", + "2020.1", "2020.2a", "2020.3", "2020.4.1", +}; +char *nonsense[] = { + "big_fat_sausage_waffles+glass_of_juice", + "big_fat_sausage_waffles.1+cup_of_fresh_broken_glass", +}; + +int main(int argc, char *argv[]) { + struct Version *prev = NULL; + + for (size_t i = 0; i < (sizeof(versions) / sizeof(char *)); i++) { + struct Version *version = version_init(); + version_read(&version, versions[i]); + + myassert(spmerrno == 0, "Unexpected error: %s\n", spm_strerror(spmerrno)); + + if (prev != NULL) { + myassert(version->asInt > prev->asInt, + testFmt, versions[i], + version->asInt, version->asInt, + prev->asInt, prev->asInt); + } + + prev = version; + } + + prev = NULL; + for (size_t i = 0; i < (sizeof(nonsense) / sizeof(char *)); i++) { + struct Version *version = version_init(); + version_read(&version, nonsense[i]); + + myassert(spmerrno == 0, "Unexpected error: %s\n", spm_strerror(spmerrno)); + + if (prev != NULL) { + myassert(version->asInt > prev->asInt, + testFmt, nonsense[i], + version->asInt, version->asInt, + prev->asInt, prev->asInt); + } + + prev = version; + } + + // Check the wrapper, version_from(), produces the same results as "the long way" above + uint64_t prev_i = 0; + for (size_t i = 0; i < (sizeof(versions) / sizeof(char *)); i++) { + myassert(spmerrno == 0, "Unexpected error: %s\n", spm_strerror(spmerrno)); + + uint64_t result = version_from(versions[i]); + if (prev_i > 0) { + myassert(result > prev_i, + testFmt, versions[i], + result, result, + prev_i, prev_i); + } + + prev_i = result; + } + + prev_i = 0; + for (size_t i = 0; i < (sizeof(nonsense) / sizeof(char *)); i++) { + myassert(spmerrno == 0, "Unexpected error: %s\n", spm_strerror(spmerrno)); + + uint64_t result = version_from(nonsense[i]); + if (prev_i > 0) { + myassert(result > prev_i, + testFmt, nonsense[i], + result, result, + prev_i, prev_i); + } + + prev_i = result; + } + return 0; +} |