diff --git a/rmutil/strings.c b/rmutil/strings.c index 3933013..db20852 100644 --- a/rmutil/strings.c +++ b/rmutil/strings.c @@ -2,7 +2,6 @@ #include #include #include "strings.h" -#include "alloc.h" #include "sds.h" @@ -69,13 +68,3 @@ void RMUtil_StringToUpper(RedisModuleString *s) { ++c; } } - -void RMUtil_StringConvert(RedisModuleString **rs, const char **ss, size_t n, int options) { - for (size_t ii = 0; ii < n; ++ii) { - const char *p = RedisModule_StringPtrLen(rs[ii], NULL); - if (options & RMUTIL_STRINGCONVERT_COPY) { - p = strdup(p); - } - ss[ii] = p; - } -} \ No newline at end of file diff --git a/rmutil/strings.h b/rmutil/strings.h index eaef71e..c447957 100644 --- a/rmutil/strings.h +++ b/rmutil/strings.h @@ -25,14 +25,4 @@ void RMUtil_StringToLower(RedisModuleString *s); /* Converts a redis string to uppercase in place without reallocating anything */ void RMUtil_StringToUpper(RedisModuleString *s); - -// If set, copy the strings using strdup rather than simply storing pointers. -#define RMUTIL_STRINGCONVERT_COPY 1 - -/** - * Convert one or more RedisModuleString objects into `const char*`. - * Both rs and ss are arrays, and should be of length. - * Options may be 0 or `RMUTIL_STRINGCONVERT_COPY` - */ -void RMUtil_StringConvert(RedisModuleString **rs, const char **ss, size_t n, int options); #endif diff --git a/rmutil/test_periodic.c b/rmutil/test_periodic.c index 030a021..88d6b0b 100644 --- a/rmutil/test_periodic.c +++ b/rmutil/test_periodic.c @@ -3,7 +3,7 @@ #include #include "periodic.h" #include "assert.h" -#include "test.h" +#include "test_util.h" void timerCb(RedisModuleCtx *ctx, void *p) { int *x = p; @@ -24,4 +24,4 @@ int testPeriodic() { return 0; } -TEST_MAIN({ TESTFUNC(testPeriodic); }); +TEST_MAIN({ TESTFUNC(testPeriodic); }); \ No newline at end of file diff --git a/rmutil/test_util.h b/rmutil/test_util.h index 5a6273d..a15864a 100644 --- a/rmutil/test_util.h +++ b/rmutil/test_util.h @@ -1,67 +1,69 @@ -#ifndef __TEST_UTIL_H__ -#define __TEST_UTIL_H__ +#ifndef __TESTUTIL_H__ +#define __TESTUTIL_H__ -#include "util.h" -#include +#include +#include #include -#include +static int numTests = 0; +static int numAsserts = 0; -#define RMUtil_Test(f) \ - if (argc < 2 || RMUtil_ArgExists(__STRING(f), argv, argc, 1)) { \ - int rc = f(ctx); \ - if (rc != REDISMODULE_OK) { \ - RedisModule_ReplyWithError(ctx, "Test " __STRING(f) " FAILED"); \ - return REDISMODULE_ERR;\ - }\ - } - - -#define RMUtil_Assert(expr) if (!(expr)) { fprintf (stderr, "Assertion '%s' Failed\n", __STRING(expr)); return REDISMODULE_ERR; } +#define TESTFUNC(f) \ + printf(" Testing %s\t\t", __STRING(f)); \ + numTests++; \ + fflush(stdout); \ + if (f()) { \ + printf(" %s FAILED!\n", __STRING(f)); \ + exit(1); \ + } else \ + printf("[PASS]\n"); -#define RMUtil_AssertReplyEquals(rep, cstr) RMUtil_Assert( \ - RMUtil_StringEquals(RedisModule_CreateStringFromCallReply(rep), RedisModule_CreateString(ctx, cstr, strlen(cstr))) \ - ) -# +#define ASSERTM(expr, ...) \ + if (!(expr)) { \ + fprintf(stderr, "%s:%d: Assertion '%s' Failed: " __VA_ARGS__ "\n", __FILE__, __LINE__, \ + __STRING(expr)); \ + return -1; \ + } \ + numAsserts++; -/** -* Create an arg list to pass to a redis command handler manually, based on the format in fmt. -* The accepted format specifiers are: -* c - for null terminated c strings -* s - for RedisModuleString* objects -* l - for longs -* -* Example: RMUtil_MakeArgs(ctx, &argc, "clc", "hello", 1337, "world"); -* -* Returns an array of RedisModuleString pointers. The size of the array is store in argcp -*/ -RedisModuleString **RMUtil_MakeArgs(RedisModuleCtx *ctx, int *argcp, const char *fmt, ...) { - - va_list ap; - va_start(ap, fmt); - RedisModuleString **argv = calloc(strlen(fmt), sizeof(RedisModuleString*)); - int argc = 0; - const char *p = fmt; - while(*p) { - if (*p == 'c') { - char *cstr = va_arg(ap,char*); - argv[argc++] = RedisModule_CreateString(ctx, cstr, strlen(cstr)); - } else if (*p == 's') { - argv[argc++] = va_arg(ap,void*);; - } else if (*p == 'l') { - long ll = va_arg(ap,long long); - argv[argc++] = RedisModule_CreateStringFromLongLong(ctx, ll); - } else { - goto fmterr; - } - p++; - } - *argcp = argc; - - return argv; -fmterr: - free(argv); - return NULL; -} +#define ASSERT(expr) \ + if (!(expr)) { \ + fprintf(stderr, "%s:%d Assertion '%s' Failed\n", __FILE__, __LINE__, __STRING(expr)); \ + return -1; \ + } \ + numAsserts++; +#define ASSERT_STRING_EQ(s1, s2) ASSERT(!strcmp(s1, s2)); + +#define ASSERT_EQUAL(x, y, ...) \ + if (x != y) { \ + fprintf(stderr, "%s:%d: ", __FILE__, __LINE__); \ + fprintf(stderr, "%g != %g: " __VA_ARGS__ "\n", (double)x, (double)y); \ + return -1; \ + } \ + numAsserts++; + +#define FAIL(fmt, ...) \ + { \ + fprintf(stderr, "%s:%d: FAIL: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ + return -1; \ + } + +#define RETURN_TEST_SUCCESS return 0; +#define TEST_CASE(x, block) \ + int x { \ + block; \ + return 0 \ + } + +#define PRINT_TEST_SUMMARY printf("\nTotal: %d tests and %d assertions OK\n", numTests, numAsserts); + +#define TEST_MAIN(body) \ + int main(int argc, char **argv) { \ + printf("Starting Test '%s'...\n", argv[0]); \ + body; \ + PRINT_TEST_SUMMARY; \ + printf("\n--------------------\n\n"); \ + return 0; \ + } #endif \ No newline at end of file diff --git a/rmutil/test_vector.c b/rmutil/test_vector.c index c5737b2..e45a156 100644 --- a/rmutil/test_vector.c +++ b/rmutil/test_vector.c @@ -1,6 +1,6 @@ #include "vector.h" #include -#include "test.h" +#include "test_util.h" int testVector() { diff --git a/rmutil/util.c b/rmutil/util.c index 8307e59..b0b7856 100644 --- a/rmutil/util.c +++ b/rmutil/util.c @@ -275,3 +275,18 @@ RedisModuleString **RMUtil_ParseVarArgs(RedisModuleString **argv, int argc, int *nargs = n; return argv + 1; } + +void RMUtil_DefaultAofRewrite(RedisModuleIO *aof, RedisModuleString *key, void *value) { + RedisModuleCallReply *rep = + RedisModule_Call(RedisModule_GetContextFromIO(aof), "DUMP", "%s", key); + if (rep != NULL && RedisModule_CallReplyType(rep) == REDISMODULE_REPLY_STRING) { + size_t n; + const char *s = RedisModule_CallReplyStringPtr(rep, &n); + RedisModule_EmitAOF(aof, "RESTORE", "%sb", key, s, n); + } else { + RedisModule_Log(RedisModule_GetContextFromIO(aof), "warning", "Failed to emit AOF"); + } + if (rep != NULL) { + RedisModule_FreeCallReply(rep); + } +} diff --git a/rmutil/util.h b/rmutil/util.h index a51c8ca..4dae477 100644 --- a/rmutil/util.h +++ b/rmutil/util.h @@ -72,6 +72,13 @@ int rmutil_vparseArgs(RedisModuleString **argv, int argc, int offset, const char RedisModuleString **RMUtil_ParseVarArgs(RedisModuleString **argv, int argc, int offset, const char *keyword, size_t *nargs); +/** + * Default implementation of an AoF rewrite function that simply calls DUMP/RESTORE + * internally. To use this function, pass it as the .aof_rewrite value in + * RedisModuleTypeMethods + */ +void RMUtil_DefaultAofRewrite(RedisModuleIO *aof, RedisModuleString *key, void *value); + // A single key/value entry in a redis info map typedef struct { const char *key; diff --git a/rmutil/vector.h b/rmutil/vector.h index a3b606f..0bff2c2 100644 --- a/rmutil/vector.h +++ b/rmutil/vector.h @@ -2,7 +2,6 @@ #define __VECTOR_H__ #include #include -#include /* * Generic resizable vector that can be used if you just want to store stuff @@ -10,10 +9,10 @@ * Works like C++ std::vector with an underlying resizable buffer */ typedef struct { - char *data; - size_t elemSize; - size_t cap; - size_t top; + char *data; + size_t elemSize; + size_t cap; + size_t top; } Vector;