From a8f40c76a5eccbd5d462a4a221867df93838d932 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Sun, 5 Oct 2014 20:43:24 +0200 Subject: [PATCH] data: Added sdb_data_strcmp(). This function compares the string values of two data points. --- src/core/data.c | 26 ++++- src/include/core/data.h | 14 +++ t/unit/core/data_test.c | 217 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 254 insertions(+), 3 deletions(-) diff --git a/src/core/data.c b/src/core/data.c index 48ca6b0..57326fe 100644 --- a/src/core/data.c +++ b/src/core/data.c @@ -328,12 +328,32 @@ sdb_data_cmp(const sdb_data_t *d1, const sdb_data_t *d2) return diff; } - default: - return -1; } -#undef CMP_NULL + return -1; } /* sdb_data_cmp */ +int +sdb_data_strcmp(const sdb_data_t *d1, const sdb_data_t *d2) +{ + char d1_str[sdb_data_strlen(d1) + 1]; + char d2_str[sdb_data_strlen(d2) + 1]; + + if (sdb_data_isnull(d1)) + d1 = NULL; + if (sdb_data_isnull(d2)) + d2 = NULL; + + CMP_NULL(d1, d2); + + if (sdb_data_format(d1, d1_str, sizeof(d1_str), SDB_UNQUOTED) < 0) + return SDB_CMP(sizeof(d1_str), sizeof(d2_str)); + if (sdb_data_format(d2, d2_str, sizeof(d2_str), SDB_UNQUOTED) < 0) + return SDB_CMP(sizeof(d1_str), sizeof(d2_str)); + + return strcasecmp(d1_str, d2_str); +#undef CMP_NULL +} /* sdb_data_strcmp */ + _Bool sdb_data_isnull(const sdb_data_t *datum) { diff --git a/src/include/core/data.h b/src/include/core/data.h index af4ae5a..1bd0d53 100644 --- a/src/include/core/data.h +++ b/src/include/core/data.h @@ -115,6 +115,20 @@ sdb_data_free_datum(sdb_data_t *datum); int sdb_data_cmp(const sdb_data_t *d1, const sdb_data_t *d2); +/* + * sdb_data_strcmp: + * Compare the string values of two data points. A NULL datum is considered + * less than any non-NULL. This function works for arbitrary combination of + * data-types. + * + * Returns: + * - a value less than zero if d1 compares less than d2 + * - zero if d1 compares equal to d2 + * - a value greater than zero if d1 compares greater than d2 + */ +int +sdb_data_strcmp(const sdb_data_t *d1, const sdb_data_t *d2); + /* * sdb_data_isnull: * Determine whether a datum is NULL. A datum is considered to be NULL if diff --git a/t/unit/core/data_test.c b/t/unit/core/data_test.c index 484d59c..12944fc 100644 --- a/t/unit/core/data_test.c +++ b/t/unit/core/data_test.c @@ -109,6 +109,222 @@ START_TEST(test_data) END_TEST START_TEST(test_cmp) +{ + struct { + sdb_data_t d1; + sdb_data_t d2; + int expected; + } golden_data[] = { + /* same data as for the sdb_data_cmp test; in case the types match, + * both functions should behave the same (except for some loss in + * precision, e.g. when formatting datetime values) */ + { + { SDB_TYPE_INTEGER, { .integer = 47 } }, + { SDB_TYPE_INTEGER, { .integer = 4711 } }, + -1, + }, + { + { SDB_TYPE_INTEGER, { .integer = 4711 } }, + { SDB_TYPE_INTEGER, { .integer = 4711 } }, + 0, + }, + { + { SDB_TYPE_INTEGER, { .integer = 4711 } }, + { SDB_TYPE_INTEGER, { .integer = 47 } }, + 1, + }, + { + { SDB_TYPE_DECIMAL, { .decimal = 65535.9 } }, + { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } }, + -1, + }, + { + { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } }, + { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } }, + 0, + }, + { + { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } }, + { SDB_TYPE_DECIMAL, { .decimal = 65535.9 } }, + 1, + }, + { + { SDB_TYPE_STRING, { .string = NULL } }, + { SDB_TYPE_STRING, { .string = "" } }, + -1, + }, + { + { SDB_TYPE_STRING, { .string = NULL } }, + { SDB_TYPE_STRING, { .string = NULL } }, + 0, + }, + { + { SDB_TYPE_STRING, { .string = "" } }, + { SDB_TYPE_STRING, { .string = NULL } }, + 1, + }, + { + { SDB_TYPE_STRING, { .string = "a" } }, + { SDB_TYPE_STRING, { .string = "b" } }, + -1, + }, + { + { SDB_TYPE_STRING, { .string = "a" } }, + { SDB_TYPE_STRING, { .string = "ab" } }, + -1, + }, + { + { SDB_TYPE_STRING, { .string = "a" } }, + { SDB_TYPE_STRING, { .string = "a" } }, + 0, + }, + { + { SDB_TYPE_STRING, { .string = "b" } }, + { SDB_TYPE_STRING, { .string = "a" } }, + 1, + }, + { + { SDB_TYPE_STRING, { .string = "ab" } }, + { SDB_TYPE_STRING, { .string = "a" } }, + 1, + }, + { + { SDB_TYPE_DATETIME, { .datetime = 471047114711471100 } }, + { SDB_TYPE_DATETIME, { .datetime = 471147114711471100 } }, + -1, + }, + { + { SDB_TYPE_DATETIME, { .datetime = 471147114711471100 } }, + { SDB_TYPE_DATETIME, { .datetime = 471147114711471100 } }, + 0, + }, + { + { SDB_TYPE_DATETIME, { .datetime = 471147114711471100 } }, + { SDB_TYPE_DATETIME, { .datetime = 471047114711471100 } }, + 1, + }, + { + { SDB_TYPE_BINARY, { .binary = { 0, NULL } } }, + { SDB_TYPE_BINARY, { .binary = { 1, (unsigned char *)"a" } } }, + -1, + }, + { + { SDB_TYPE_BINARY, { .binary = { 0, NULL } } }, + { SDB_TYPE_BINARY, { .binary = { 0, NULL } } }, + 0, + }, + { + { SDB_TYPE_BINARY, { .binary = { 1, (unsigned char *)"a" } } }, + { SDB_TYPE_BINARY, { .binary = { 0, NULL } } }, + 1, + }, + { + { + SDB_TYPE_BINARY, + { .binary = { 3, (unsigned char *)"a\0a" } }, + }, + { + SDB_TYPE_BINARY, + { .binary = { 3, (unsigned char *)"a\0b" } }, + }, + -1, + }, + { + { + SDB_TYPE_BINARY, + { .binary = { 1, (unsigned char *)"a" } }, + }, + { + SDB_TYPE_BINARY, + { .binary = { 3, (unsigned char *)"a\0\0" } }, + }, + -1, + }, + { + { + SDB_TYPE_BINARY, + { .binary = { 3, (unsigned char *)"a\0a" } }, + }, + { + SDB_TYPE_BINARY, + { .binary = { 3, (unsigned char *)"a\0a" } }, + }, + 0, + }, + { + { + SDB_TYPE_BINARY, + { .binary = { 3, (unsigned char *)"a\0b" } }, + }, + { + SDB_TYPE_BINARY, + { .binary = { 3, (unsigned char *)"a\0a" } }, + }, + 1, + }, + { + { + SDB_TYPE_BINARY, + { .binary = { 3, (unsigned char *)"a\0\0" } }, + }, + { + SDB_TYPE_BINARY, + { .binary = { 1, (unsigned char *)"a" } }, + }, + 1, + }, + /* type mismatches */ + { + { SDB_TYPE_INTEGER, { .integer = 123 } }, + { SDB_TYPE_STRING, { .string = "123" } }, + 0, + }, + { + { SDB_TYPE_INTEGER, { .integer = 120 } }, + { SDB_TYPE_STRING, { .string = "123" } }, + -1, + }, + { + { SDB_TYPE_STRING, { .string = "123" } }, + { SDB_TYPE_INTEGER, { .integer = 120 } }, + 1, + }, + { + { SDB_TYPE_STRING, { .string = "12.3" } }, + { SDB_TYPE_DECIMAL, { .decimal = 12.3 } }, + 0, + }, + { + { SDB_TYPE_STRING, { .string = "12.0" } }, + { SDB_TYPE_DECIMAL, { .decimal = 12.3 } }, + -1, + }, + { + { SDB_TYPE_DECIMAL, { .decimal = 12.3 } }, + { SDB_TYPE_STRING, { .string = "12.0" } }, + 1, + }, + }; + + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + int check = sdb_data_strcmp(&golden_data[i].d1, &golden_data[i].d2); + check = check < 0 ? -1 : check > 0 ? 1 : 0; + if (check != golden_data[i].expected) { + char d1_str[64] = "", d2_str[64] = ""; + sdb_data_format(&golden_data[i].d1, d1_str, sizeof(d1_str), + SDB_DOUBLE_QUOTED); + sdb_data_format(&golden_data[i].d2, d2_str, sizeof(d2_str), + SDB_DOUBLE_QUOTED); + fail("sdb_data_strcmp(%s, %s) = %d; expected: %d", + d1_str, d2_str, check, golden_data[i].expected); + } + } +} +END_TEST + +START_TEST(test_strcmp) { struct { sdb_data_t d1; @@ -663,6 +879,7 @@ core_data_suite(void) tc = tcase_create("core"); tcase_add_test(tc, test_data); tcase_add_test(tc, test_cmp); + tcase_add_test(tc, test_strcmp); tcase_add_test(tc, test_expr_eval); tcase_add_test(tc, test_format); tcase_add_test(tc, test_parse); -- 2.30.2