FROM ubuntu:latest
# Install redis
-RUN apt-get update && \
+RUN apt update && \
apt install -y redis-server && \
- apt-get clean
+ apt clean
+
+# Install Redis modules
+RUN apt install -y build-essential && \
+ apt install -y automake && \
+ apt install -y libtool && \
+ apt clean
+COPY ./redismodule ./redismodule
+WORKDIR /redismodule
+RUN ./autogen.sh && \
+ ./configure && \
+ make install -j
# Create suitable configuration file
RUN sed -i 's/^\(bind .*\)$/# \1/' /etc/redis/redis.conf && \
sed -i 's/^\(daemonize .*\)$/# \1/' /etc/redis/redis.conf && \
sed 's/^protected-mode yes/protected-mode no/' -i /etc/redis/redis.conf && \
+ echo 'loadmodule /usr/local/libexec/redismodule/libredismodule.so' >> /etc/redis/redis.conf && \
sed -i 's/^\(save .*\)$/# \1/' /etc/redis/redis.conf && \
echo 'save ""' >> /etc/redis/redis.conf
--- /dev/null
+ACLOCAL_AMFLAGS = -I m4
+
+redismoduledir = @libexecdir@/$(PACKAGE)
+redismodule_LTLIBRARIES = libredismodule.la
+#lib_LTLIBRARIES = libredismodule.la
+
+BASE_LDFLAGS =
+
+libredismodule_la_SOURCES = \
+ include/redismodule.h\
+ src/exstrings.c
+
+libredismodule_la_CFLAGS = \
+ -std=c11 -fPIC -g \
+ -I${includedir} -I${top_srcdir}/include
+
+
+libredismodule_la_LDFLAGS = $(BASE_LDFLAGS) -avoid-version -module -shared
+
+#pkgincludedir = ${includedir}
+#pkginclude_HEADERS = include/redismodule.h
+
+clean-local:
+ rm -rf ${builddir}/libredismodule.pc
+
+# UT
+CPP_U_TEST=$(CPP_U_TEST_LATEST)
+check_PROGRAMS = redismodule_ut
+#TESTS = ${check_PROGRAMS}
+redismodule_ut_SOURCES = \
+ tst/mock/include/redismodule.h \
+ tst/mock/include/exstringsStub.h \
+ src/exstrings.c \
+ tst/mock/src/redismoduleStub.cpp \
+ tst/src/main.cpp \
+ tst/src/exstrings_test.cpp
+
+
+redismodule_ut_CFLAGS = \
+ -std=c11 -g -Wall \
+ -fprofile-arcs -ftest-coverage \
+ -D__UT__ \
+ -I${top_srcdir}/tst/mock/include \
+ -I${includedir} \
+ -I${top_srcdir}/include \
+ -I${CPP_U_TEST_LATEST}/include
+
+redismodule_ut_CXXFLAGS = \
+ -std=c++11 -g -Wall \
+ -fprofile-arcs -ftest-coverage \
+ -D__UT__ \
+ -I${top_srcdir}/tst/mock/include \
+ -I${includedir} \
+ -I${top_srcdir}/include \
+ -I${CPP_U_TEST_LATEST}/include
+
+
+redismodule_ut_LDFLAGS = -Wl,-rpath=${libdir} ${UT_COVERAGE_LDFLAGS}
+redismodule_ut_LDADD = -L${libdir} -L${CPP_U_TEST_LATEST}/lib -lCppUTest -lCppUTestExt -lgcov
+
+test: redismodule_ut
+ ./run-tests.sh
+
+TESTS = run-tests.sh
--- /dev/null
+# Introduction
+
+This subdirectory provides implementation for the commands which are implemented
+as a [Redis modules](https://redis.io/topics/modules-intro).
+
+# Commands
+
+## SETIE key value oldvalue [expiration EX seconds|PX milliseconds]
+
+Time complexity: O(1) + O(1)
+
+Checks a String 'key' for 'oldvalue' equality and set key for 'value' with
+optional expired.
+
+```
+Example:
+
+redis> get mykey
+(nil)
+redis> setie mykey "Hello again" "Hello"
+(nil)
+
+redis> set mykey "Hello"
+OK
+redis> get mykey
+"Hello"
+redis> setie mykey "Hello again" "Hello"
+"OK"
+redis> get mykey
+"Hello again"
+redis> setie mykey "Hello 2" "Hello"
+(nil)
+redis> get mykey
+"Hello again"
+redis> setie mykey "Hello 2" "Hello again" ex 100
+"OK"
+redis> ttl mykey
+(integer) 96
+redis> get mykey
+"Hello 2"
+```
+
+## SETNE key value oldvalue [expiration EX seconds|PX milliseconds]
+
+Time complexity: O(1) + O(1)
+
+Checks a String 'key' for 'oldvalue' not equality and set key for 'value' with optional expired.
+
+Example:
+
+```
+redis> get mykey
+(nil)
+redis> setne mykey "Hello again" "Hello"
+"OK"
+redis> get mykey
+"Hello again"
+redis> setne mykey "Hello 2" "Hello again"
+(nil)
+redis> setne mykey "Hello 2" "Hello"
+"OK"
+redis> get mykey
+"Hello 2"
+redis> setne mykey "Hello 3" "Hello" ex 100
+"OK"
+redis> get mykey
+"Hello 3"
+redis> ttl mykey
+(integer) 93
+```
+
+## DELIE key oldvalue
+
+Time complexity: O(1) + O(1)
+
+Checks a String 'key' for 'oldvalue' equality and delete the key.
+
+```
+Example:
+redis> get mykey
+(nil)
+redis> set mykey "Hello"
+"OK"
+redis> get mykey
+"Hello"
+redis> delie mykey "Hello again"
+(integer) 0
+redis> get mykey
+"Hello"
+redis> delie mykey "Hello"
+(integer) 1
+redis> get mykey
+(nil)
+```
+
+## DELNE key oldvalue
+
+Time complexity: O(1) + O(1)
+
+Checks a String 'key' for 'oldvalue' not equality and delete the key.
+
+```
+Example:
+redis> get mykey
+(nil)
+redis> set mykey "Hello"
+"OK"
+redis> get mykey
+"Hello"
+redis> delne mykey "Hello"
+(integer) 0
+redis> get mykey
+"Hello"
+redis> delne mykey "Hello again"
+(integer) 1
+redis> get mykey
+(nil)
+```
+
+## MSETPUB key value [key value...] channel message
+
+Time complexity: O(N) where N is the number of keys to set + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+
+Set the given keys to their respective values and post a message to the given channel
+
+## SETXXPUB key value channel message
+
+Time complexity: O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+
+Set key to hold string value if key already exist and post a message to the given channel if set key value successfully
+
+## SETNXPUB key value channel message
+
+Time complexity: O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+
+Set key to hold string value if key does not exist and post a message to the given channel if set key value successfully
+
+## SETIEPUB key value oldvalue channel message
+
+Time complexity: O(1) + O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+
+Checks a String 'key' for 'oldvalue' equality and set key for 'value' and post a message to the given channel if set key value successfully
+
+## SETNEPUB key value oldvalue channel message
+
+Time complexity: O(1) + O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+
+Checks a String 'key' for 'oldvalue' not equality and set key for 'value' and post a message to the given channel if set key value successfully
+
+## DELPUB key [key...] channel message
+
+Time complexity: O(N) where N is the number of keys that will be removed + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+
+Removes the specified keys and post a message to the given channel if delete key successfully(return >0)
+
+## DELIEPUB key oldvalue channel message
+
+ime complexity: O(1) + O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+
+Checks a String 'key' for 'oldvalue' equality and delete the key and post a message to the given channel if delete key successfully(return 1)
+
+## DELNEPUB key oldvalue channel message
+
+Time complexity: O(1) + O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+
+Checks a String 'key' for 'oldvalue' not equality and delete the key and post a message to the given channel if delete key successfully(return 1)
+
+## NGET pattern
+
+Time complexity: O(N) with N being the number of keys in the instance + O(N) where N is the number of keys to retrieve
+
+Returns all key-value pairs matching pattern.
+
+```
+example:
+
+redis> nget mykey*
+(empty list or set)
+
+redis> set mykey1 "myvalue1"
+OK
+redis> set mykey2 "myvalue2"
+OK
+redis> set mykey3 "myvalue3"
+OK
+redis> set mykey4 "myvalue4"
+OK
+redis> nget mykey*
+1) "mykey2"
+2) "myvalue2"
+3) "mykey1"
+4) "myvalue1"
+5) "mykey4"
+6) "myvalue4"
+7) "mykey3"
+8) "myvalue3"
+```
+
+## NDEL pattern
+
+Time complexity: O(N) with N being the number of keys in the instance + O(N) where N is the number of keys that will be removed
+
+Remove all key-value pairs matching pattern.
+
+```
+example:
+
+redis> nget mykey*
+1) "mykey2"
+2) "myvalue2"
+3) "mykey1"
+4) "myvalue1"
+5) "mykey4"
+6) "myvalue4"
+7) "mykey3"
+8) "myvalue3"
+
+redis> ndel mykey*
+(integer) 4
+
+redis> ndel mykey*
+(integer) 0
+```
--- /dev/null
+#!/bin/bash
+
+autoreconf --install
--- /dev/null
+AC_INIT([redismodule], [0.0.0], [], [], [https://gerrit.oran-osc.org/r/#/admin/projects/ric-plt/dbaas])
+AC_CONFIG_AUX_DIR([build-aux])
+AC_CONFIG_MACRO_DIRS([m4])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_FILES([run-tests.sh], [chmod +x run-tests.sh])
+
+
+AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects tar-pax])
+
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+LT_INIT([disable-static])
+
+# Checks for programs.
+AC_PROG_CXX
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+
+
+# Checks for header files.
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_STDBOOL
+
+AC_CONFIG_FILES([Makefile])
+
+AC_OUTPUT
--- /dev/null
+/*
+ * Copyright (c) 2018-2019 Nokia.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef REDISMODULE_H
+#define REDISMODULE_H
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
+
+/* ---------------- Defines common between core and modules --------------- */
+
+/* Error status return values. */
+#define REDISMODULE_OK 0
+#define REDISMODULE_ERR 1
+
+/* API versions. */
+#define REDISMODULE_APIVER_1 1
+
+/* API flags and constants */
+#define REDISMODULE_READ (1<<0)
+#define REDISMODULE_WRITE (1<<1)
+
+#define REDISMODULE_LIST_HEAD 0
+#define REDISMODULE_LIST_TAIL 1
+
+/* Key types. */
+#define REDISMODULE_KEYTYPE_EMPTY 0
+#define REDISMODULE_KEYTYPE_STRING 1
+#define REDISMODULE_KEYTYPE_LIST 2
+#define REDISMODULE_KEYTYPE_HASH 3
+#define REDISMODULE_KEYTYPE_SET 4
+#define REDISMODULE_KEYTYPE_ZSET 5
+#define REDISMODULE_KEYTYPE_MODULE 6
+
+/* Reply types. */
+#define REDISMODULE_REPLY_UNKNOWN -1
+#define REDISMODULE_REPLY_STRING 0
+#define REDISMODULE_REPLY_ERROR 1
+#define REDISMODULE_REPLY_INTEGER 2
+#define REDISMODULE_REPLY_ARRAY 3
+#define REDISMODULE_REPLY_NULL 4
+
+/* Postponed array length. */
+#define REDISMODULE_POSTPONED_ARRAY_LEN -1
+
+/* Expire */
+#define REDISMODULE_NO_EXPIRE -1
+
+/* Sorted set API flags. */
+#define REDISMODULE_ZADD_XX (1<<0)
+#define REDISMODULE_ZADD_NX (1<<1)
+#define REDISMODULE_ZADD_ADDED (1<<2)
+#define REDISMODULE_ZADD_UPDATED (1<<3)
+#define REDISMODULE_ZADD_NOP (1<<4)
+
+/* Hash API flags. */
+#define REDISMODULE_HASH_NONE 0
+#define REDISMODULE_HASH_NX (1<<0)
+#define REDISMODULE_HASH_XX (1<<1)
+#define REDISMODULE_HASH_CFIELDS (1<<2)
+#define REDISMODULE_HASH_EXISTS (1<<3)
+
+/* Context Flags: Info about the current context returned by RM_GetContextFlags */
+
+/* The command is running in the context of a Lua script */
+#define REDISMODULE_CTX_FLAGS_LUA 0x0001
+/* The command is running inside a Redis transaction */
+#define REDISMODULE_CTX_FLAGS_MULTI 0x0002
+/* The instance is a master */
+#define REDISMODULE_CTX_FLAGS_MASTER 0x0004
+/* The instance is a slave */
+#define REDISMODULE_CTX_FLAGS_SLAVE 0x0008
+/* The instance is read-only (usually meaning it's a slave as well) */
+#define REDISMODULE_CTX_FLAGS_READONLY 0x0010
+/* The instance is running in cluster mode */
+#define REDISMODULE_CTX_FLAGS_CLUSTER 0x0020
+/* The instance has AOF enabled */
+#define REDISMODULE_CTX_FLAGS_AOF 0x0040 //
+/* The instance has RDB enabled */
+#define REDISMODULE_CTX_FLAGS_RDB 0x0080 //
+/* The instance has Maxmemory set */
+#define REDISMODULE_CTX_FLAGS_MAXMEMORY 0x0100
+/* Maxmemory is set and has an eviction policy that may delete keys */
+#define REDISMODULE_CTX_FLAGS_EVICT 0x0200
+
+
+#define REDISMODULE_NOTIFY_GENERIC (1<<2) /* g */
+#define REDISMODULE_NOTIFY_STRING (1<<3) /* $ */
+#define REDISMODULE_NOTIFY_LIST (1<<4) /* l */
+#define REDISMODULE_NOTIFY_SET (1<<5) /* s */
+#define REDISMODULE_NOTIFY_HASH (1<<6) /* h */
+#define REDISMODULE_NOTIFY_ZSET (1<<7) /* z */
+#define REDISMODULE_NOTIFY_EXPIRED (1<<8) /* x */
+#define REDISMODULE_NOTIFY_EVICTED (1<<9) /* e */
+#define REDISMODULE_NOTIFY_ALL (REDISMODULE_NOTIFY_GENERIC | REDISMODULE_NOTIFY_STRING | REDISMODULE_NOTIFY_LIST | REDISMODULE_NOTIFY_SET | REDISMODULE_NOTIFY_HASH | REDISMODULE_NOTIFY_ZSET | REDISMODULE_NOTIFY_EXPIRED | REDISMODULE_NOTIFY_EVICTED) /* A */
+
+
+/* A special pointer that we can use between the core and the module to signal
+ * field deletion, and that is impossible to be a valid pointer. */
+#define REDISMODULE_HASH_DELETE ((RedisModuleString*)(long)1)
+
+/* Error messages. */
+#define REDISMODULE_ERRORMSG_WRONGTYPE "WRONGTYPE Operation against a key holding the wrong kind of value"
+
+#define REDISMODULE_POSITIVE_INFINITE (1.0/0.0)
+#define REDISMODULE_NEGATIVE_INFINITE (-1.0/0.0)
+
+#define REDISMODULE_NOT_USED(V) ((void) V)
+
+/* ------------------------- End of common defines ------------------------ */
+
+#ifndef REDISMODULE_CORE
+
+typedef long long mstime_t;
+
+/* Incomplete structures for compiler checks but opaque access. */
+typedef struct RedisModuleCtx RedisModuleCtx;
+typedef struct RedisModuleKey RedisModuleKey;
+typedef struct RedisModuleString RedisModuleString;
+typedef struct RedisModuleCallReply RedisModuleCallReply;
+typedef struct RedisModuleIO RedisModuleIO;
+typedef struct RedisModuleType RedisModuleType;
+typedef struct RedisModuleDigest RedisModuleDigest;
+typedef struct RedisModuleBlockedClient RedisModuleBlockedClient;
+
+typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+
+typedef int (*RedisModuleNotificationFunc) (RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key);
+typedef void *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver);
+typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value);
+typedef void (*RedisModuleTypeRewriteFunc)(RedisModuleIO *aof, RedisModuleString *key, void *value);
+typedef size_t (*RedisModuleTypeMemUsageFunc)(const void *value);
+typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value);
+typedef void (*RedisModuleTypeFreeFunc)(void *value);
+
+#define REDISMODULE_TYPE_METHOD_VERSION 1
+typedef struct RedisModuleTypeMethods {
+ uint64_t version;
+ RedisModuleTypeLoadFunc rdb_load;
+ RedisModuleTypeSaveFunc rdb_save;
+ RedisModuleTypeRewriteFunc aof_rewrite;
+ RedisModuleTypeMemUsageFunc mem_usage;
+ RedisModuleTypeDigestFunc digest;
+ RedisModuleTypeFreeFunc free;
+} RedisModuleTypeMethods;
+
+#define REDISMODULE_GET_API(name) \
+ RedisModule_GetApi("RedisModule_" #name, ((void **)&RedisModule_ ## name))
+
+#define REDISMODULE_API_FUNC(x) (*x)
+
+
+void *REDISMODULE_API_FUNC(RedisModule_Alloc)(size_t bytes);
+void *REDISMODULE_API_FUNC(RedisModule_Realloc)(void *ptr, size_t bytes);
+void REDISMODULE_API_FUNC(RedisModule_Free)(void *ptr);
+void *REDISMODULE_API_FUNC(RedisModule_Calloc)(size_t nmemb, size_t size);
+char *REDISMODULE_API_FUNC(RedisModule_Strdup)(const char *str);
+int REDISMODULE_API_FUNC(RedisModule_GetApi)(const char *, void *);
+int REDISMODULE_API_FUNC(RedisModule_CreateCommand)(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep);
+void REDISMODULE_API_FUNC(RedisModule_SetModuleAttribs)(RedisModuleCtx *ctx, const char *name, int ver, int apiver);
+int REDISMODULE_API_FUNC(RedisModule_IsModuleNameBusy)(const char *name);
+int REDISMODULE_API_FUNC(RedisModule_WrongArity)(RedisModuleCtx *ctx);
+int REDISMODULE_API_FUNC(RedisModule_ReplyWithLongLong)(RedisModuleCtx *ctx, long long ll);
+int REDISMODULE_API_FUNC(RedisModule_GetSelectedDb)(RedisModuleCtx *ctx);
+int REDISMODULE_API_FUNC(RedisModule_SelectDb)(RedisModuleCtx *ctx, int newid);
+void *REDISMODULE_API_FUNC(RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode);
+void REDISMODULE_API_FUNC(RedisModule_CloseKey)(RedisModuleKey *kp);
+int REDISMODULE_API_FUNC(RedisModule_KeyType)(RedisModuleKey *kp);
+size_t REDISMODULE_API_FUNC(RedisModule_ValueLength)(RedisModuleKey *kp);
+int REDISMODULE_API_FUNC(RedisModule_ListPush)(RedisModuleKey *kp, int where, RedisModuleString *ele);
+RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ListPop)(RedisModuleKey *key, int where);
+RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_Call)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...);
+const char *REDISMODULE_API_FUNC(RedisModule_CallReplyProto)(RedisModuleCallReply *reply, size_t *len);
+void REDISMODULE_API_FUNC(RedisModule_FreeCallReply)(RedisModuleCallReply *reply);
+int REDISMODULE_API_FUNC(RedisModule_CallReplyType)(RedisModuleCallReply *reply);
+long long REDISMODULE_API_FUNC(RedisModule_CallReplyInteger)(RedisModuleCallReply *reply);
+size_t REDISMODULE_API_FUNC(RedisModule_CallReplyLength)(RedisModuleCallReply *reply);
+RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_CallReplyArrayElement)(RedisModuleCallReply *reply, size_t idx);
+RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateString)(RedisModuleCtx *ctx, const char *ptr, size_t len);
+RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromLongLong)(RedisModuleCtx *ctx, long long ll);
+RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromString)(RedisModuleCtx *ctx, const RedisModuleString *str);
+RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringPrintf)(RedisModuleCtx *ctx, const char *fmt, ...);
+void REDISMODULE_API_FUNC(RedisModule_FreeString)(RedisModuleCtx *ctx, RedisModuleString *str);
+const char *REDISMODULE_API_FUNC(RedisModule_StringPtrLen)(const RedisModuleString *str, size_t *len);
+int REDISMODULE_API_FUNC(RedisModule_ReplyWithError)(RedisModuleCtx *ctx, const char *err);
+int REDISMODULE_API_FUNC(RedisModule_ReplyWithSimpleString)(RedisModuleCtx *ctx, const char *msg);
+int REDISMODULE_API_FUNC(RedisModule_ReplyWithArray)(RedisModuleCtx *ctx, long len);
+void REDISMODULE_API_FUNC(RedisModule_ReplySetArrayLength)(RedisModuleCtx *ctx, long len);
+int REDISMODULE_API_FUNC(RedisModule_ReplyWithStringBuffer)(RedisModuleCtx *ctx, const char *buf, size_t len);
+int REDISMODULE_API_FUNC(RedisModule_ReplyWithString)(RedisModuleCtx *ctx, RedisModuleString *str);
+int REDISMODULE_API_FUNC(RedisModule_ReplyWithNull)(RedisModuleCtx *ctx);
+int REDISMODULE_API_FUNC(RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d);
+int REDISMODULE_API_FUNC(RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply);
+int REDISMODULE_API_FUNC(RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll);
+int REDISMODULE_API_FUNC(RedisModule_StringToDouble)(const RedisModuleString *str, double *d);
+void REDISMODULE_API_FUNC(RedisModule_AutoMemory)(RedisModuleCtx *ctx);
+int REDISMODULE_API_FUNC(RedisModule_Replicate)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...);
+int REDISMODULE_API_FUNC(RedisModule_ReplicateVerbatim)(RedisModuleCtx *ctx);
+const char *REDISMODULE_API_FUNC(RedisModule_CallReplyStringPtr)(RedisModuleCallReply *reply, size_t *len);
+RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromCallReply)(RedisModuleCallReply *reply);
+int REDISMODULE_API_FUNC(RedisModule_DeleteKey)(RedisModuleKey *key);
+int REDISMODULE_API_FUNC(RedisModule_UnlinkKey)(RedisModuleKey *key);
+int REDISMODULE_API_FUNC(RedisModule_StringSet)(RedisModuleKey *key, RedisModuleString *str);
+char *REDISMODULE_API_FUNC(RedisModule_StringDMA)(RedisModuleKey *key, size_t *len, int mode);
+int REDISMODULE_API_FUNC(RedisModule_StringTruncate)(RedisModuleKey *key, size_t newlen);
+mstime_t REDISMODULE_API_FUNC(RedisModule_GetExpire)(RedisModuleKey *key);
+int REDISMODULE_API_FUNC(RedisModule_SetExpire)(RedisModuleKey *key, mstime_t expire);
+int REDISMODULE_API_FUNC(RedisModule_ZsetAdd)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr);
+int REDISMODULE_API_FUNC(RedisModule_ZsetIncrby)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore);
+int REDISMODULE_API_FUNC(RedisModule_ZsetScore)(RedisModuleKey *key, RedisModuleString *ele, double *score);
+int REDISMODULE_API_FUNC(RedisModule_ZsetRem)(RedisModuleKey *key, RedisModuleString *ele, int *deleted);
+void REDISMODULE_API_FUNC(RedisModule_ZsetRangeStop)(RedisModuleKey *key);
+int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex);
+int REDISMODULE_API_FUNC(RedisModule_ZsetLastInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex);
+int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max);
+int REDISMODULE_API_FUNC(RedisModule_ZsetLastInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max);
+RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ZsetRangeCurrentElement)(RedisModuleKey *key, double *score);
+int REDISMODULE_API_FUNC(RedisModule_ZsetRangeNext)(RedisModuleKey *key);
+int REDISMODULE_API_FUNC(RedisModule_ZsetRangePrev)(RedisModuleKey *key);
+int REDISMODULE_API_FUNC(RedisModule_ZsetRangeEndReached)(RedisModuleKey *key);
+int REDISMODULE_API_FUNC(RedisModule_HashSet)(RedisModuleKey *key, int flags, ...);
+int REDISMODULE_API_FUNC(RedisModule_HashGet)(RedisModuleKey *key, int flags, ...);
+int REDISMODULE_API_FUNC(RedisModule_IsKeysPositionRequest)(RedisModuleCtx *ctx);
+void REDISMODULE_API_FUNC(RedisModule_KeyAtPos)(RedisModuleCtx *ctx, int pos);
+unsigned long long REDISMODULE_API_FUNC(RedisModule_GetClientId)(RedisModuleCtx *ctx);
+int REDISMODULE_API_FUNC(RedisModule_GetContextFlags)(RedisModuleCtx *ctx);
+void *REDISMODULE_API_FUNC(RedisModule_PoolAlloc)(RedisModuleCtx *ctx, size_t bytes);
+RedisModuleType *REDISMODULE_API_FUNC(RedisModule_CreateDataType)(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods);
+int REDISMODULE_API_FUNC(RedisModule_ModuleTypeSetValue)(RedisModuleKey *key, RedisModuleType *mt, void *value);
+RedisModuleType *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetType)(RedisModuleKey *key);
+void *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetValue)(RedisModuleKey *key);
+void REDISMODULE_API_FUNC(RedisModule_SaveUnsigned)(RedisModuleIO *io, uint64_t value);
+uint64_t REDISMODULE_API_FUNC(RedisModule_LoadUnsigned)(RedisModuleIO *io);
+void REDISMODULE_API_FUNC(RedisModule_SaveSigned)(RedisModuleIO *io, int64_t value);
+int64_t REDISMODULE_API_FUNC(RedisModule_LoadSigned)(RedisModuleIO *io);
+void REDISMODULE_API_FUNC(RedisModule_EmitAOF)(RedisModuleIO *io, const char *cmdname, const char *fmt, ...);
+void REDISMODULE_API_FUNC(RedisModule_SaveString)(RedisModuleIO *io, RedisModuleString *s);
+void REDISMODULE_API_FUNC(RedisModule_SaveStringBuffer)(RedisModuleIO *io, const char *str, size_t len);
+RedisModuleString *REDISMODULE_API_FUNC(RedisModule_LoadString)(RedisModuleIO *io);
+char *REDISMODULE_API_FUNC(RedisModule_LoadStringBuffer)(RedisModuleIO *io, size_t *lenptr);
+void REDISMODULE_API_FUNC(RedisModule_SaveDouble)(RedisModuleIO *io, double value);
+double REDISMODULE_API_FUNC(RedisModule_LoadDouble)(RedisModuleIO *io);
+void REDISMODULE_API_FUNC(RedisModule_SaveFloat)(RedisModuleIO *io, float value);
+float REDISMODULE_API_FUNC(RedisModule_LoadFloat)(RedisModuleIO *io);
+void REDISMODULE_API_FUNC(RedisModule_Log)(RedisModuleCtx *ctx, const char *level, const char *fmt, ...);
+void REDISMODULE_API_FUNC(RedisModule_LogIOError)(RedisModuleIO *io, const char *levelstr, const char *fmt, ...);
+int REDISMODULE_API_FUNC(RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len);
+void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str);
+int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b);
+RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetContextFromIO)(RedisModuleIO *io);
+long long REDISMODULE_API_FUNC(RedisModule_Milliseconds)(void);
+void REDISMODULE_API_FUNC(RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, unsigned char *ele, size_t len);
+void REDISMODULE_API_FUNC(RedisModule_DigestAddLongLong)(RedisModuleDigest *md, long long ele);
+void REDISMODULE_API_FUNC(RedisModule_DigestEndSequence)(RedisModuleDigest *md);
+
+/* Experimental APIs */
+#ifdef REDISMODULE_EXPERIMENTAL_API
+RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_BlockClient)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms);
+int REDISMODULE_API_FUNC(RedisModule_UnblockClient)(RedisModuleBlockedClient *bc, void *privdata);
+int REDISMODULE_API_FUNC(RedisModule_IsBlockedReplyRequest)(RedisModuleCtx *ctx);
+int REDISMODULE_API_FUNC(RedisModule_IsBlockedTimeoutRequest)(RedisModuleCtx *ctx);
+void *REDISMODULE_API_FUNC(RedisModule_GetBlockedClientPrivateData)(RedisModuleCtx *ctx);
+int REDISMODULE_API_FUNC(RedisModule_AbortBlock)(RedisModuleBlockedClient *bc);
+RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetThreadSafeContext)(RedisModuleBlockedClient *bc);
+void REDISMODULE_API_FUNC(RedisModule_FreeThreadSafeContext)(RedisModuleCtx *ctx);
+void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextLock)(RedisModuleCtx *ctx);
+void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextUnlock)(RedisModuleCtx *ctx);
+int REDISMODULE_API_FUNC(RedisModule_SubscribeToKeyspaceEvents)(RedisModuleCtx *ctx, int types, RedisModuleNotificationFunc cb);
+
+#endif
+
+/* This is included inline inside each Redis module. */
+static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) __attribute__((unused));
+static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) {
+ void *getapifuncptr = ((void**)ctx)[0];
+ RedisModule_GetApi = (int (*)(const char *, void *)) (unsigned long)getapifuncptr;
+ REDISMODULE_GET_API(Alloc);
+ REDISMODULE_GET_API(Calloc);
+ REDISMODULE_GET_API(Free);
+ REDISMODULE_GET_API(Realloc);
+ REDISMODULE_GET_API(Strdup);
+ REDISMODULE_GET_API(CreateCommand);
+ REDISMODULE_GET_API(SetModuleAttribs);
+ REDISMODULE_GET_API(IsModuleNameBusy);
+ REDISMODULE_GET_API(WrongArity);
+ REDISMODULE_GET_API(ReplyWithLongLong);
+ REDISMODULE_GET_API(ReplyWithError);
+ REDISMODULE_GET_API(ReplyWithSimpleString);
+ REDISMODULE_GET_API(ReplyWithArray);
+ REDISMODULE_GET_API(ReplySetArrayLength);
+ REDISMODULE_GET_API(ReplyWithStringBuffer);
+ REDISMODULE_GET_API(ReplyWithString);
+ REDISMODULE_GET_API(ReplyWithNull);
+ REDISMODULE_GET_API(ReplyWithCallReply);
+ REDISMODULE_GET_API(ReplyWithDouble);
+ REDISMODULE_GET_API(ReplySetArrayLength);
+ REDISMODULE_GET_API(GetSelectedDb);
+ REDISMODULE_GET_API(SelectDb);
+ REDISMODULE_GET_API(OpenKey);
+ REDISMODULE_GET_API(CloseKey);
+ REDISMODULE_GET_API(KeyType);
+ REDISMODULE_GET_API(ValueLength);
+ REDISMODULE_GET_API(ListPush);
+ REDISMODULE_GET_API(ListPop);
+ REDISMODULE_GET_API(StringToLongLong);
+ REDISMODULE_GET_API(StringToDouble);
+ REDISMODULE_GET_API(Call);
+ REDISMODULE_GET_API(CallReplyProto);
+ REDISMODULE_GET_API(FreeCallReply);
+ REDISMODULE_GET_API(CallReplyInteger);
+ REDISMODULE_GET_API(CallReplyType);
+ REDISMODULE_GET_API(CallReplyLength);
+ REDISMODULE_GET_API(CallReplyArrayElement);
+ REDISMODULE_GET_API(CallReplyStringPtr);
+ REDISMODULE_GET_API(CreateStringFromCallReply);
+ REDISMODULE_GET_API(CreateString);
+ REDISMODULE_GET_API(CreateStringFromLongLong);
+ REDISMODULE_GET_API(CreateStringFromString);
+ REDISMODULE_GET_API(CreateStringPrintf);
+ REDISMODULE_GET_API(FreeString);
+ REDISMODULE_GET_API(StringPtrLen);
+ REDISMODULE_GET_API(AutoMemory);
+ REDISMODULE_GET_API(Replicate);
+ REDISMODULE_GET_API(ReplicateVerbatim);
+ REDISMODULE_GET_API(DeleteKey);
+ REDISMODULE_GET_API(UnlinkKey);
+ REDISMODULE_GET_API(StringSet);
+ REDISMODULE_GET_API(StringDMA);
+ REDISMODULE_GET_API(StringTruncate);
+ REDISMODULE_GET_API(GetExpire);
+ REDISMODULE_GET_API(SetExpire);
+ REDISMODULE_GET_API(ZsetAdd);
+ REDISMODULE_GET_API(ZsetIncrby);
+ REDISMODULE_GET_API(ZsetScore);
+ REDISMODULE_GET_API(ZsetRem);
+ REDISMODULE_GET_API(ZsetRangeStop);
+ REDISMODULE_GET_API(ZsetFirstInScoreRange);
+ REDISMODULE_GET_API(ZsetLastInScoreRange);
+ REDISMODULE_GET_API(ZsetFirstInLexRange);
+ REDISMODULE_GET_API(ZsetLastInLexRange);
+ REDISMODULE_GET_API(ZsetRangeCurrentElement);
+ REDISMODULE_GET_API(ZsetRangeNext);
+ REDISMODULE_GET_API(ZsetRangePrev);
+ REDISMODULE_GET_API(ZsetRangeEndReached);
+ REDISMODULE_GET_API(HashSet);
+ REDISMODULE_GET_API(HashGet);
+ REDISMODULE_GET_API(IsKeysPositionRequest);
+ REDISMODULE_GET_API(KeyAtPos);
+ REDISMODULE_GET_API(GetClientId);
+ REDISMODULE_GET_API(GetContextFlags);
+ REDISMODULE_GET_API(PoolAlloc);
+ REDISMODULE_GET_API(CreateDataType);
+ REDISMODULE_GET_API(ModuleTypeSetValue);
+ REDISMODULE_GET_API(ModuleTypeGetType);
+ REDISMODULE_GET_API(ModuleTypeGetValue);
+ REDISMODULE_GET_API(SaveUnsigned);
+ REDISMODULE_GET_API(LoadUnsigned);
+ REDISMODULE_GET_API(SaveSigned);
+ REDISMODULE_GET_API(LoadSigned);
+ REDISMODULE_GET_API(SaveString);
+ REDISMODULE_GET_API(SaveStringBuffer);
+ REDISMODULE_GET_API(LoadString);
+ REDISMODULE_GET_API(LoadStringBuffer);
+ REDISMODULE_GET_API(SaveDouble);
+ REDISMODULE_GET_API(LoadDouble);
+ REDISMODULE_GET_API(SaveFloat);
+ REDISMODULE_GET_API(LoadFloat);
+ REDISMODULE_GET_API(EmitAOF);
+ REDISMODULE_GET_API(Log);
+ REDISMODULE_GET_API(LogIOError);
+ REDISMODULE_GET_API(StringAppendBuffer);
+ REDISMODULE_GET_API(RetainString);
+ REDISMODULE_GET_API(StringCompare);
+ REDISMODULE_GET_API(GetContextFromIO);
+ REDISMODULE_GET_API(Milliseconds);
+ REDISMODULE_GET_API(DigestAddStringBuffer);
+ REDISMODULE_GET_API(DigestAddLongLong);
+ REDISMODULE_GET_API(DigestEndSequence);
+
+#ifdef REDISMODULE_EXPERIMENTAL_API
+ REDISMODULE_GET_API(GetThreadSafeContext);
+ REDISMODULE_GET_API(FreeThreadSafeContext);
+ REDISMODULE_GET_API(ThreadSafeContextLock);
+ REDISMODULE_GET_API(ThreadSafeContextUnlock);
+ REDISMODULE_GET_API(BlockClient);
+ REDISMODULE_GET_API(UnblockClient);
+ REDISMODULE_GET_API(IsBlockedReplyRequest);
+ REDISMODULE_GET_API(IsBlockedTimeoutRequest);
+ REDISMODULE_GET_API(GetBlockedClientPrivateData);
+ REDISMODULE_GET_API(AbortBlock);
+ REDISMODULE_GET_API(SubscribeToKeyspaceEvents);
+
+#endif
+
+ if (RedisModule_IsModuleNameBusy && RedisModule_IsModuleNameBusy(name)) return REDISMODULE_ERR;
+ RedisModule_SetModuleAttribs(ctx,name,ver,apiver);
+ return REDISMODULE_OK;
+}
+
+#else
+
+/* Things only defined for the modules core, not exported to modules
+ * including this file. */
+#define RedisModuleString robj
+
+#endif /* REDISMODULE_CORE */
+#endif /* REDISMOUDLE_H */
--- /dev/null
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_prog_doxygen.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# DX_INIT_DOXYGEN(PROJECT-NAME, [DOXYFILE-PATH], [OUTPUT-DIR], ...)
+# DX_DOXYGEN_FEATURE(ON|OFF)
+# DX_DOT_FEATURE(ON|OFF)
+# DX_HTML_FEATURE(ON|OFF)
+# DX_CHM_FEATURE(ON|OFF)
+# DX_CHI_FEATURE(ON|OFF)
+# DX_MAN_FEATURE(ON|OFF)
+# DX_RTF_FEATURE(ON|OFF)
+# DX_XML_FEATURE(ON|OFF)
+# DX_PDF_FEATURE(ON|OFF)
+# DX_PS_FEATURE(ON|OFF)
+#
+# DESCRIPTION
+#
+# The DX_*_FEATURE macros control the default setting for the given
+# Doxygen feature. Supported features are 'DOXYGEN' itself, 'DOT' for
+# generating graphics, 'HTML' for plain HTML, 'CHM' for compressed HTML
+# help (for MS users), 'CHI' for generating a separate .chi file by the
+# .chm file, and 'MAN', 'RTF', 'XML', 'PDF' and 'PS' for the appropriate
+# output formats. The environment variable DOXYGEN_PAPER_SIZE may be
+# specified to override the default 'a4wide' paper size.
+#
+# By default, HTML, PDF and PS documentation is generated as this seems to
+# be the most popular and portable combination. MAN pages created by
+# Doxygen are usually problematic, though by picking an appropriate subset
+# and doing some massaging they might be better than nothing. CHM and RTF
+# are specific for MS (note that you can't generate both HTML and CHM at
+# the same time). The XML is rather useless unless you apply specialized
+# post-processing to it.
+#
+# The macros mainly control the default state of the feature. The use can
+# override the default by specifying --enable or --disable. The macros
+# ensure that contradictory flags are not given (e.g.,
+# --enable-doxygen-html and --enable-doxygen-chm,
+# --enable-doxygen-anything with --disable-doxygen, etc.) Finally, each
+# feature will be automatically disabled (with a warning) if the required
+# programs are missing.
+#
+# Once all the feature defaults have been specified, call DX_INIT_DOXYGEN
+# with the following parameters: a one-word name for the project for use
+# as a filename base etc., an optional configuration file name (the
+# default is '$(srcdir)/Doxyfile', the same as Doxygen's default), and an
+# optional output directory name (the default is 'doxygen-doc'). To run
+# doxygen multiple times for different configuration files and output
+# directories provide more parameters: the second, forth, sixth, etc
+# parameter are configuration file names and the third, fifth, seventh,
+# etc parameter are output directories. No checking is done to catch
+# duplicates.
+#
+# Automake Support
+#
+# The DX_RULES substitution can be used to add all needed rules to the
+# Makefile. Note that this is a substitution without being a variable:
+# only the @DX_RULES@ syntax will work.
+#
+# The provided targets are:
+#
+# doxygen-doc: Generate all doxygen documentation.
+#
+# doxygen-run: Run doxygen, which will generate some of the
+# documentation (HTML, CHM, CHI, MAN, RTF, XML)
+# but will not do the post processing required
+# for the rest of it (PS, PDF).
+#
+# doxygen-ps: Generate doxygen PostScript documentation.
+#
+# doxygen-pdf: Generate doxygen PDF documentation.
+#
+# Note that by default these are not integrated into the automake targets.
+# If doxygen is used to generate man pages, you can achieve this
+# integration by setting man3_MANS to the list of man pages generated and
+# then adding the dependency:
+#
+# $(man3_MANS): doxygen-doc
+#
+# This will cause make to run doxygen and generate all the documentation.
+#
+# The following variable is intended for use in Makefile.am:
+#
+# DX_CLEANFILES = everything to clean.
+#
+# Then add this variable to MOSTLYCLEANFILES.
+#
+# LICENSE
+#
+# Copyright (c) 2009 Oren Ben-Kiki <oren@ben-kiki.org>
+# Copyright (c) 2015 Olaf Mandel <olaf@mandel.name>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 23
+
+## ----------##
+## Defaults. ##
+## ----------##
+
+DX_ENV=""
+AC_DEFUN([DX_FEATURE_doc], ON)
+AC_DEFUN([DX_FEATURE_dot], OFF)
+AC_DEFUN([DX_FEATURE_man], OFF)
+AC_DEFUN([DX_FEATURE_html], ON)
+AC_DEFUN([DX_FEATURE_chm], OFF)
+AC_DEFUN([DX_FEATURE_chi], OFF)
+AC_DEFUN([DX_FEATURE_rtf], OFF)
+AC_DEFUN([DX_FEATURE_xml], OFF)
+AC_DEFUN([DX_FEATURE_pdf], ON)
+AC_DEFUN([DX_FEATURE_ps], ON)
+
+## --------------- ##
+## Private macros. ##
+## --------------- ##
+
+# DX_ENV_APPEND(VARIABLE, VALUE)
+# ------------------------------
+# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen and add it
+# as a substitution (but not a Makefile variable). The substitution
+# is skipped if the variable name is VERSION.
+AC_DEFUN([DX_ENV_APPEND],
+[AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])dnl
+m4_if([$1], [VERSION], [], [AC_SUBST([$1], [$2])dnl
+AM_SUBST_NOTMAKE([$1])])dnl
+])
+
+# DX_DIRNAME_EXPR
+# ---------------
+# Expand into a shell expression prints the directory part of a path.
+AC_DEFUN([DX_DIRNAME_EXPR],
+ [[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']])
+
+# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF)
+# -------------------------------------
+# Expands according to the M4 (static) status of the feature.
+AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])])
+
+# DX_REQUIRE_PROG(VARIABLE, PROGRAM)
+# ----------------------------------
+# Require the specified program to be found for the DX_CURRENT_FEATURE to work.
+AC_DEFUN([DX_REQUIRE_PROG], [
+AC_PATH_TOOL([$1], [$2])
+if test "$DX_FLAG_[]DX_CURRENT_FEATURE$$1" = 1; then
+ AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION])
+ AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0)
+fi
+])
+
+# DX_TEST_FEATURE(FEATURE)
+# ------------------------
+# Expand to a shell expression testing whether the feature is active.
+AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1])
+
+# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE)
+# -------------------------------------------------
+# Verify that a required features has the right state before trying to turn on
+# the DX_CURRENT_FEATURE.
+AC_DEFUN([DX_CHECK_DEPEND], [
+test "$DX_FLAG_$1" = "$2" \
+|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1,
+ requires, contradicts) doxygen-DX_CURRENT_FEATURE])
+])
+
+# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE)
+# ----------------------------------------------------------
+# Turn off the DX_CURRENT_FEATURE if the required feature is off.
+AC_DEFUN([DX_CLEAR_DEPEND], [
+test "$DX_FLAG_$1" = "$2" || AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0)
+])
+
+# DX_FEATURE_ARG(FEATURE, DESCRIPTION,
+# CHECK_DEPEND, CLEAR_DEPEND,
+# REQUIRE, DO-IF-ON, DO-IF-OFF)
+# --------------------------------------------
+# Parse the command-line option controlling a feature. CHECK_DEPEND is called
+# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND),
+# otherwise CLEAR_DEPEND is called to turn off the default state if a required
+# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional
+# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and
+# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature.
+AC_DEFUN([DX_ARG_ABLE], [
+ AC_DEFUN([DX_CURRENT_FEATURE], [$1])
+ AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2])
+ AC_ARG_ENABLE(doxygen-$1,
+ [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1],
+ [--enable-doxygen-$1]),
+ DX_IF_FEATURE([$1], [don't $2], [$2]))],
+ [
+case "$enableval" in
+#(
+y|Y|yes|Yes|YES)
+ AC_SUBST([DX_FLAG_$1], 1)
+ $3
+;; #(
+n|N|no|No|NO)
+ AC_SUBST([DX_FLAG_$1], 0)
+;; #(
+*)
+ AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1])
+;;
+esac
+], [
+AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)])
+$4
+])
+if DX_TEST_FEATURE([$1]); then
+ $5
+ :
+fi
+if DX_TEST_FEATURE([$1]); then
+ $6
+ :
+else
+ $7
+ :
+fi
+])
+
+## -------------- ##
+## Public macros. ##
+## -------------- ##
+
+# DX_XXX_FEATURE(DEFAULT_STATE)
+# -----------------------------
+AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])])
+AC_DEFUN([DX_DOT_FEATURE], [AC_DEFUN([DX_FEATURE_dot], [$1])])
+AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])])
+AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])])
+AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])])
+AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])])
+AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])])
+AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
+AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
+AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])])
+AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])])
+
+# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR], ...)
+# --------------------------------------------------------------
+# PROJECT also serves as the base name for the documentation files.
+# The default CONFIG-FILE is "$(srcdir)/Doxyfile" and OUTPUT-DOC-DIR is
+# "doxygen-doc".
+# More arguments are interpreted as interleaved CONFIG-FILE and
+# OUTPUT-DOC-DIR values.
+AC_DEFUN([DX_INIT_DOXYGEN], [
+
+# Files:
+AC_SUBST([DX_PROJECT], [$1])
+AC_SUBST([DX_CONFIG], ['ifelse([$2], [], [$(srcdir)/Doxyfile], [$2])'])
+AC_SUBST([DX_DOCDIR], ['ifelse([$3], [], [doxygen-doc], [$3])'])
+m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 4, m4_count($@), 2,
+ [AC_SUBST([DX_CONFIG]m4_eval(DX_i[/2]),
+ 'm4_default_nblank_quoted(m4_argn(DX_i, $@),
+ [$(srcdir)/Doxyfile])')])])dnl
+m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 5, m4_count($@,), 2,
+ [AC_SUBST([DX_DOCDIR]m4_eval([(]DX_i[-1)/2]),
+ 'm4_default_nblank_quoted(m4_argn(DX_i, $@),
+ [doxygen-doc])')])])dnl
+m4_define([DX_loop], m4_dquote(m4_if(m4_eval(3 < m4_count($@)), 1,
+ [m4_for([DX_i], 4, m4_count($@), 2, [, m4_eval(DX_i[/2])])],
+ [])))dnl
+
+# Environment variables used inside doxygen.cfg:
+DX_ENV_APPEND(SRCDIR, $srcdir)
+DX_ENV_APPEND(PROJECT, $DX_PROJECT)
+DX_ENV_APPEND(VERSION, $PACKAGE_VERSION)
+
+# Doxygen itself:
+DX_ARG_ABLE(doc, [generate any doxygen documentation],
+ [],
+ [],
+ [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen)
+ DX_REQUIRE_PROG([DX_PERL], perl)],
+ [DX_ENV_APPEND(PERL_PATH, $DX_PERL)])
+
+# Dot for graphics:
+DX_ARG_ABLE(dot, [generate graphics for doxygen documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [DX_REQUIRE_PROG([DX_DOT], dot)],
+ [DX_ENV_APPEND(HAVE_DOT, YES)
+ DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])],
+ [DX_ENV_APPEND(HAVE_DOT, NO)])
+
+# Man pages generation:
+DX_ARG_ABLE(man, [generate doxygen manual pages],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [],
+ [DX_ENV_APPEND(GENERATE_MAN, YES)],
+ [DX_ENV_APPEND(GENERATE_MAN, NO)])
+
+# RTF file generation:
+DX_ARG_ABLE(rtf, [generate doxygen RTF documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [],
+ [DX_ENV_APPEND(GENERATE_RTF, YES)],
+ [DX_ENV_APPEND(GENERATE_RTF, NO)])
+
+# XML file generation:
+DX_ARG_ABLE(xml, [generate doxygen XML documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [],
+ [DX_ENV_APPEND(GENERATE_XML, YES)],
+ [DX_ENV_APPEND(GENERATE_XML, NO)])
+
+# (Compressed) HTML help generation:
+DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [DX_REQUIRE_PROG([DX_HHC], hhc)],
+ [DX_ENV_APPEND(HHC_PATH, $DX_HHC)
+ DX_ENV_APPEND(GENERATE_HTML, YES)
+ DX_ENV_APPEND(GENERATE_HTMLHELP, YES)],
+ [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)])
+
+# Separate CHI file generation.
+DX_ARG_ABLE(chi, [generate doxygen separate compressed HTML help index file],
+ [DX_CHECK_DEPEND(chm, 1)],
+ [DX_CLEAR_DEPEND(chm, 1)],
+ [],
+ [DX_ENV_APPEND(GENERATE_CHI, YES)],
+ [DX_ENV_APPEND(GENERATE_CHI, NO)])
+
+# Plain HTML pages generation:
+DX_ARG_ABLE(html, [generate doxygen plain HTML documentation],
+ [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)],
+ [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)],
+ [],
+ [DX_ENV_APPEND(GENERATE_HTML, YES)],
+ [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)])
+
+# PostScript file generation:
+DX_ARG_ABLE(ps, [generate doxygen PostScript documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [DX_REQUIRE_PROG([DX_LATEX], latex)
+ DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
+ DX_REQUIRE_PROG([DX_DVIPS], dvips)
+ DX_REQUIRE_PROG([DX_EGREP], egrep)])
+
+# PDF file generation:
+DX_ARG_ABLE(pdf, [generate doxygen PDF documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex)
+ DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
+ DX_REQUIRE_PROG([DX_EGREP], egrep)])
+
+# LaTeX generation for PS and/or PDF:
+if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then
+ DX_ENV_APPEND(GENERATE_LATEX, YES)
+else
+ DX_ENV_APPEND(GENERATE_LATEX, NO)
+fi
+
+# Paper size for PS and/or PDF:
+AC_ARG_VAR(DOXYGEN_PAPER_SIZE,
+ [a4wide (default), a4, letter, legal or executive])
+case "$DOXYGEN_PAPER_SIZE" in
+#(
+"")
+ AC_SUBST(DOXYGEN_PAPER_SIZE, "")
+;; #(
+a4wide|a4|letter|legal|executive)
+ DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE)
+;; #(
+*)
+ AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE'])
+;;
+esac
+
+# Rules:
+AS_IF([[test $DX_FLAG_html -eq 1]],
+[[DX_SNIPPET_html="## ------------------------------- ##
+## Rules specific for HTML output. ##
+## ------------------------------- ##
+
+DX_CLEAN_HTML = \$(DX_DOCDIR)/html]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+ \$(DX_DOCDIR]DX_i[)/html]])[
+
+"]],
+[[DX_SNIPPET_html=""]])
+AS_IF([[test $DX_FLAG_chi -eq 1]],
+[[DX_SNIPPET_chi="
+DX_CLEAN_CHI = \$(DX_DOCDIR)/\$(PACKAGE).chi]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).chi]])["]],
+[[DX_SNIPPET_chi=""]])
+AS_IF([[test $DX_FLAG_chm -eq 1]],
+[[DX_SNIPPET_chm="## ------------------------------ ##
+## Rules specific for CHM output. ##
+## ------------------------------ ##
+
+DX_CLEAN_CHM = \$(DX_DOCDIR)/chm]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+ \$(DX_DOCDIR]DX_i[)/chm]])[\
+${DX_SNIPPET_chi}
+
+"]],
+[[DX_SNIPPET_chm=""]])
+AS_IF([[test $DX_FLAG_man -eq 1]],
+[[DX_SNIPPET_man="## ------------------------------ ##
+## Rules specific for MAN output. ##
+## ------------------------------ ##
+
+DX_CLEAN_MAN = \$(DX_DOCDIR)/man]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+ \$(DX_DOCDIR]DX_i[)/man]])[
+
+"]],
+[[DX_SNIPPET_man=""]])
+AS_IF([[test $DX_FLAG_rtf -eq 1]],
+[[DX_SNIPPET_rtf="## ------------------------------ ##
+## Rules specific for RTF output. ##
+## ------------------------------ ##
+
+DX_CLEAN_RTF = \$(DX_DOCDIR)/rtf]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+ \$(DX_DOCDIR]DX_i[)/rtf]])[
+
+"]],
+[[DX_SNIPPET_rtf=""]])
+AS_IF([[test $DX_FLAG_xml -eq 1]],
+[[DX_SNIPPET_xml="## ------------------------------ ##
+## Rules specific for XML output. ##
+## ------------------------------ ##
+
+DX_CLEAN_XML = \$(DX_DOCDIR)/xml]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+ \$(DX_DOCDIR]DX_i[)/xml]])[
+
+"]],
+[[DX_SNIPPET_xml=""]])
+AS_IF([[test $DX_FLAG_ps -eq 1]],
+[[DX_SNIPPET_ps="## ----------------------------- ##
+## Rules specific for PS output. ##
+## ----------------------------- ##
+
+DX_CLEAN_PS = \$(DX_DOCDIR)/\$(PACKAGE).ps]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps]])[
+
+DX_PS_GOAL = doxygen-ps
+
+doxygen-ps: \$(DX_CLEAN_PS)
+
+]m4_foreach([DX_i], [DX_loop],
+[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag
+ \$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\
+ rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\
+ \$(DX_LATEX) refman.tex; \\
+ \$(DX_MAKEINDEX) refman.idx; \\
+ \$(DX_LATEX) refman.tex; \\
+ countdown=5; \\
+ while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\
+ refman.log > /dev/null 2>&1 \\
+ && test \$\$countdown -gt 0; do \\
+ \$(DX_LATEX) refman.tex; \\
+ countdown=\`expr \$\$countdown - 1\`; \\
+ done; \\
+ \$(DX_DVIPS) -o ../\$(PACKAGE).ps refman.dvi
+
+]])["]],
+[[DX_SNIPPET_ps=""]])
+AS_IF([[test $DX_FLAG_pdf -eq 1]],
+[[DX_SNIPPET_pdf="## ------------------------------ ##
+## Rules specific for PDF output. ##
+## ------------------------------ ##
+
+DX_CLEAN_PDF = \$(DX_DOCDIR)/\$(PACKAGE).pdf]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf]])[
+
+DX_PDF_GOAL = doxygen-pdf
+
+doxygen-pdf: \$(DX_CLEAN_PDF)
+
+]m4_foreach([DX_i], [DX_loop],
+[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag
+ \$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\
+ rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\
+ \$(DX_PDFLATEX) refman.tex; \\
+ \$(DX_MAKEINDEX) refman.idx; \\
+ \$(DX_PDFLATEX) refman.tex; \\
+ countdown=5; \\
+ while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\
+ refman.log > /dev/null 2>&1 \\
+ && test \$\$countdown -gt 0; do \\
+ \$(DX_PDFLATEX) refman.tex; \\
+ countdown=\`expr \$\$countdown - 1\`; \\
+ done; \\
+ mv refman.pdf ../\$(PACKAGE).pdf
+
+]])["]],
+[[DX_SNIPPET_pdf=""]])
+AS_IF([[test $DX_FLAG_ps -eq 1 -o $DX_FLAG_pdf -eq 1]],
+[[DX_SNIPPET_latex="## ------------------------------------------------- ##
+## Rules specific for LaTeX (shared for PS and PDF). ##
+## ------------------------------------------------- ##
+
+DX_V_LATEX = \$(_DX_v_LATEX_\$(V))
+_DX_v_LATEX_ = \$(_DX_v_LATEX_\$(AM_DEFAULT_VERBOSITY))
+_DX_v_LATEX_0 = @echo \" LATEX \" \$][@;
+
+DX_CLEAN_LATEX = \$(DX_DOCDIR)/latex]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+ \$(DX_DOCDIR]DX_i[)/latex]])[
+
+"]],
+[[DX_SNIPPET_latex=""]])
+
+AS_IF([[test $DX_FLAG_doc -eq 1]],
+[[DX_SNIPPET_doc="## --------------------------------- ##
+## Format-independent Doxygen rules. ##
+## --------------------------------- ##
+
+${DX_SNIPPET_html}\
+${DX_SNIPPET_chm}\
+${DX_SNIPPET_man}\
+${DX_SNIPPET_rtf}\
+${DX_SNIPPET_xml}\
+${DX_SNIPPET_ps}\
+${DX_SNIPPET_pdf}\
+${DX_SNIPPET_latex}\
+DX_V_DXGEN = \$(_DX_v_DXGEN_\$(V))
+_DX_v_DXGEN_ = \$(_DX_v_DXGEN_\$(AM_DEFAULT_VERBOSITY))
+_DX_v_DXGEN_0 = @echo \" DXGEN \" \$<;
+
+.PHONY: doxygen-run doxygen-doc \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+.INTERMEDIATE: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+doxygen-run:]m4_foreach([DX_i], [DX_loop],
+ [[ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag]])[
+
+doxygen-doc: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+]m4_foreach([DX_i], [DX_loop],
+[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag: \$(DX_CONFIG]DX_i[) \$(pkginclude_HEADERS)
+ \$(A""M_V_at)rm -rf \$(DX_DOCDIR]DX_i[)
+ \$(DX_V_DXGEN)\$(DX_ENV) DOCDIR=\$(DX_DOCDIR]DX_i[) \$(DX_DOXYGEN) \$(DX_CONFIG]DX_i[)
+ \$(A""M_V_at)echo Timestamp >\$][@
+
+]])dnl
+[DX_CLEANFILES = \\]
+m4_foreach([DX_i], [DX_loop],
+[[ \$(DX_DOCDIR]DX_i[)/doxygen_sqlite3.db \\
+ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag \\
+]])dnl
+[ -r \\
+ \$(DX_CLEAN_HTML) \\
+ \$(DX_CLEAN_CHM) \\
+ \$(DX_CLEAN_CHI) \\
+ \$(DX_CLEAN_MAN) \\
+ \$(DX_CLEAN_RTF) \\
+ \$(DX_CLEAN_XML) \\
+ \$(DX_CLEAN_PS) \\
+ \$(DX_CLEAN_PDF) \\
+ \$(DX_CLEAN_LATEX)"]],
+[[DX_SNIPPET_doc=""]])
+AC_SUBST([DX_RULES],
+["${DX_SNIPPET_doc}"])dnl
+AM_SUBST_NOTMAKE([DX_RULES])
+
+#For debugging:
+#echo DX_FLAG_doc=$DX_FLAG_doc
+#echo DX_FLAG_dot=$DX_FLAG_dot
+#echo DX_FLAG_man=$DX_FLAG_man
+#echo DX_FLAG_html=$DX_FLAG_html
+#echo DX_FLAG_chm=$DX_FLAG_chm
+#echo DX_FLAG_chi=$DX_FLAG_chi
+#echo DX_FLAG_rtf=$DX_FLAG_rtf
+#echo DX_FLAG_xml=$DX_FLAG_xml
+#echo DX_FLAG_pdf=$DX_FLAG_pdf
+#echo DX_FLAG_ps=$DX_FLAG_ps
+#echo DX_ENV=$DX_ENV
+])
--- /dev/null
+#!/bin/sh
+
+./redismodule_ut
+if [ $? != 0 ]
+then
+ exit -1
+fi
+subsystem=redismodule
+prbname=libredismodule
+UT_DIR=${VOBTAG}/$subsystem
+gcda_files=$(find $UT_DIR -name '*.gcda')
+if [ -z "$gcda_files" ]
+then
+ UT_DIR=${VOBTAG}/$subsystem/buildme.ut
+ gcda_files=$(find $UT_DIR -name '*.gcda')
+ if [ -z "$gcda_files" ]
+ then
+ echo "no gcda files, so cannot generate UT coverage"
+ exit 0
+ fi
+fi
+echo "gcda file is found"
+lcov_src_patterns='*/redismodule/src/*'
+lcov_objs_root=${VOBTAG}/$subsystem
+lcov_remove_patterns='*/tst/*'
+${VOBTAG}/flexiserver/build/ut_lcov.sh ${lcov_objs_root} ${lcov_src_patterns} ${lcov_remove_patterns}
+
--- /dev/null
+/*
+ * Copyright (c) 2018-2019 Nokia.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "redismodule.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "../../redismodule/include/redismodule.h"
+
+#ifdef __UT__
+#include "exstringsStub.h"
+#endif
+
+/* make sure the response is not NULL or an error.
+sends the error to the client and exit the current function if its */
+#define ASSERT_NOERROR(r) \
+ if (r == NULL) { \
+ return RedisModule_ReplyWithError(ctx,"ERR reply is NULL"); \
+ } else if (RedisModule_CallReplyType(r) == REDISMODULE_REPLY_ERROR) { \
+ RedisModule_ReplyWithCallReply(ctx,r); \
+ RedisModule_FreeCallReply(r); \
+ return REDISMODULE_ERR; \
+ }
+
+#define OBJ_OP_NO 0
+#define OBJ_OP_XX (1<<1) /* OP if key exist */
+#define OBJ_OP_NX (1<<2) /* OP if key not exist */
+#define OBJ_OP_IE (1<<4) /* OP if equal old value */
+#define OBJ_OP_NE (1<<5) /* OP if not equal old value */
+
+
+int setStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
+ int argc, const int flag)
+{
+ RedisModuleString *oldvalstr = NULL;
+ RedisModuleCallReply *reply = NULL;
+
+ if (argc < 4)
+ return RedisModule_WrongArity(ctx);
+ else
+ oldvalstr = argv[3];
+
+ /*Check if key type is string*/
+ RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
+ REDISMODULE_READ);
+ int type = RedisModule_KeyType(key);
+ RedisModule_CloseKey(key);
+
+ if (type == REDISMODULE_KEYTYPE_EMPTY) {
+ if (flag == OBJ_OP_IE){
+ RedisModule_ReplyWithNull(ctx);
+ return REDISMODULE_OK;
+ }
+ } else if (type != REDISMODULE_KEYTYPE_STRING) {
+ return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
+ }
+
+ /*Get the value*/
+ reply = RedisModule_Call(ctx, "GET", "s", argv[1]);
+ ASSERT_NOERROR(reply)
+ size_t curlen=0, oldvallen=0;
+ const char *oldval = RedisModule_StringPtrLen(oldvalstr, &oldvallen);
+ const char *curval = RedisModule_CallReplyStringPtr(reply, &curlen);
+ if (((flag == OBJ_OP_IE) &&
+ (!curval || (oldvallen != curlen) || strncmp(oldval, curval, curlen)))
+ ||
+ ((flag == OBJ_OP_NE) && curval && (oldvallen == curlen) &&
+ !strncmp(oldval, curval, curlen))) {
+ RedisModule_FreeCallReply(reply);
+ return RedisModule_ReplyWithNull(ctx);
+ }
+ RedisModule_FreeCallReply(reply);
+
+ /* Prepare the arguments for the command. */
+ int i, j=0, cmdargc=argc-2;
+ RedisModuleString *cmdargv[cmdargc];
+ for (i = 1; i < argc; i++) {
+ if (i == 3)
+ continue;
+ cmdargv[j++] = argv[i];
+ }
+
+ /* Call the command and pass back the reply. */
+ reply = RedisModule_Call(ctx, "SET", "v!", cmdargv, cmdargc);
+ ASSERT_NOERROR(reply)
+ RedisModule_ReplyWithCallReply(ctx, reply);
+
+ RedisModule_FreeCallReply(reply);
+ return REDISMODULE_OK;
+}
+
+int SetIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ return setStringGenericCommand(ctx, argv, argc, OBJ_OP_IE);
+}
+
+int SetNE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ return setStringGenericCommand(ctx, argv, argc, OBJ_OP_NE);
+}
+
+int delStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
+ int argc, const int flag)
+{
+ RedisModuleString *oldvalstr = NULL;
+ RedisModuleCallReply *reply = NULL;
+
+ if (argc == 3)
+ oldvalstr = argv[2];
+ else
+ return RedisModule_WrongArity(ctx);
+
+ /*Check if key type is string*/
+ RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
+ REDISMODULE_READ);
+ int type = RedisModule_KeyType(key);
+ RedisModule_CloseKey(key);
+
+ if (type == REDISMODULE_KEYTYPE_EMPTY) {
+ return RedisModule_ReplyWithLongLong(ctx, 0);
+ } else if (type != REDISMODULE_KEYTYPE_STRING) {
+ return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
+ }
+
+ /*Get the value*/
+ reply = RedisModule_Call(ctx, "GET", "s", argv[1]);
+ ASSERT_NOERROR(reply)
+ size_t curlen = 0, oldvallen = 0;
+ const char *oldval = RedisModule_StringPtrLen(oldvalstr, &oldvallen);
+ const char *curval = RedisModule_CallReplyStringPtr(reply, &curlen);
+ if (((flag == OBJ_OP_IE) &&
+ (!curval || (oldvallen != curlen) || strncmp(oldval, curval, curlen)))
+ ||
+ ((flag == OBJ_OP_NE) && curval && (oldvallen == curlen) &&
+ !strncmp(oldval, curval, curlen))) {
+ RedisModule_FreeCallReply(reply);
+ return RedisModule_ReplyWithLongLong(ctx, 0);
+ }
+ RedisModule_FreeCallReply(reply);
+
+ /* Prepare the arguments for the command. */
+ int cmdargc=1;
+ RedisModuleString *cmdargv[1];
+ cmdargv[0] = argv[1];
+
+ /* Call the command and pass back the reply. */
+ reply = RedisModule_Call(ctx, "UNLINK", "v!", cmdargv, cmdargc);
+ ASSERT_NOERROR(reply)
+ RedisModule_ReplyWithCallReply(ctx, reply);
+
+ RedisModule_FreeCallReply(reply);
+ return REDISMODULE_OK;
+}
+
+int DelIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ return delStringGenericCommand(ctx, argv, argc, OBJ_OP_IE);
+}
+
+int DelNE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ return delStringGenericCommand(ctx, argv, argc, OBJ_OP_NE);
+}
+
+int NGet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ RedisModuleCallReply *reply = NULL;
+
+ if (argc != 2)
+ return RedisModule_WrongArity(ctx);
+
+ /* Call the command to get keys with pattern. */
+ reply = RedisModule_Call(ctx, "KEYS", "s", argv[1]);
+ ASSERT_NOERROR(reply)
+
+ /* Prepare the arguments for the command. */
+ size_t items = RedisModule_CallReplyLength(reply);
+ if (items == 0) {
+ //RedisModule_ReplyWithArray(ctx, items);
+ RedisModule_ReplyWithCallReply(ctx, reply);
+ RedisModule_FreeCallReply(reply);
+ }
+ else {
+ RedisModuleString *cmdargv[items];
+ size_t i=0, j;
+ for (j = 0; j < items; j++) {
+ RedisModuleString *rms = RedisModule_CreateStringFromCallReply(RedisModule_CallReplyArrayElement(reply, j));
+ cmdargv[i++] = rms;
+
+ /*Assume all keys via SDL is string type for sake of saving time*/
+#if 0
+ /*Check if key type is string*/
+ RedisModuleKey *key = RedisModule_OpenKey(ctx, rms ,REDISMODULE_READ);
+
+ if (key) {
+ int type = RedisModule_KeyType(key);
+ RedisModule_CloseKey(key);
+ if (type == REDISMODULE_KEYTYPE_STRING) {
+ cmdargv[i++] = rms;
+ }
+ } else {
+ RedisModule_CloseKey(key);
+ }
+#endif
+ }
+ RedisModule_FreeCallReply(reply);
+
+ reply = RedisModule_Call(ctx, "MGET", "v", cmdargv, i);
+ ASSERT_NOERROR(reply)
+ items = RedisModule_CallReplyLength(reply);
+ RedisModule_ReplyWithArray(ctx, i*2);
+ for (j = 0; (j<items && j<i); j++) {
+ RedisModule_ReplyWithString(ctx, cmdargv[j]);
+ RedisModule_ReplyWithString(ctx, RedisModule_CreateStringFromCallReply(RedisModule_CallReplyArrayElement(reply, j)));
+ }
+
+ RedisModule_FreeCallReply(reply);
+ }
+
+ return REDISMODULE_OK;
+}
+
+int NDel_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ RedisModuleCallReply *reply = NULL;
+
+ if (argc != 2)
+ return RedisModule_WrongArity(ctx);
+
+ /* Call the command to get keys with pattern. */
+ reply = RedisModule_Call(ctx, "KEYS", "s", argv[1]);
+ ASSERT_NOERROR(reply)
+
+ /* Prepare the arguments for the command. */
+ size_t items = RedisModule_CallReplyLength(reply);
+ if (items == 0) {
+ RedisModule_ReplyWithLongLong(ctx, 0);
+ RedisModule_FreeCallReply(reply);
+ }
+ else {
+ RedisModuleString *cmdargv[items];
+ size_t i=0, j;
+ for (j = 0; j < items; j++) {
+ RedisModuleString *rms = RedisModule_CreateStringFromCallReply(RedisModule_CallReplyArrayElement(reply, j));
+ cmdargv[i++] = rms;
+
+ /*Assume all keys via SDL is string type for sake of saving time*/
+#if 0
+ //Check if key type is string
+ RedisModuleKey *key = RedisModule_OpenKey(ctx, rms ,REDISMODULE_READ);
+
+ if (key) {
+ int type = RedisModule_KeyType(key);
+ RedisModule_CloseKey(key);
+ if (type == REDISMODULE_KEYTYPE_STRING) {
+ cmdargv[i++] = rms;
+ }
+ } else {
+ RedisModule_CloseKey(key);
+ }
+#endif
+ }
+ RedisModule_FreeCallReply(reply);
+
+ reply = RedisModule_Call(ctx, "UNLINK", "v!", cmdargv, i);
+ ASSERT_NOERROR(reply)
+ RedisModule_ReplyWithCallReply(ctx, reply);
+ RedisModule_FreeCallReply(reply);
+
+ }
+
+ return REDISMODULE_OK;
+}
+
+int setPubStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
+ int argc, const int flag)
+{
+ RedisModuleString *oldvalstr = NULL, *channel = NULL, *message = NULL;
+ RedisModuleCallReply *reply = NULL;
+
+ if (flag == OBJ_OP_NO) {
+ if (argc < 5 || (argc % 2) == 0)
+ return RedisModule_WrongArity(ctx);
+ else {
+ channel = argv[argc-2];
+ message = argv[argc-1];
+ }
+ } else if (flag == OBJ_OP_XX || flag == OBJ_OP_NX) {
+ if (argc != 5)
+ return RedisModule_WrongArity(ctx);
+ else {
+ channel = argv[3];
+ message = argv[4];
+ }
+ } else {
+ if (argc != 6)
+ return RedisModule_WrongArity(ctx);
+ else {
+ oldvalstr = argv[3];
+ channel = argv[4];
+ message = argv[5];
+ }
+ }
+
+ /*Check if key type is string*/
+ RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
+ REDISMODULE_READ);
+ int type = RedisModule_KeyType(key);
+ RedisModule_CloseKey(key);
+
+ if (flag != OBJ_OP_NO) {
+ if (type == REDISMODULE_KEYTYPE_EMPTY) {
+ if (flag == OBJ_OP_IE || flag == OBJ_OP_XX){
+ return RedisModule_ReplyWithNull(ctx);
+ }
+ } else if (flag == OBJ_OP_NX) {
+ return RedisModule_ReplyWithNull(ctx);
+ } else if (type != REDISMODULE_KEYTYPE_STRING) {
+ return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
+ }
+ }
+
+ if (flag == OBJ_OP_IE || flag == OBJ_OP_NE) {
+ /*Get the value*/
+ reply = RedisModule_Call(ctx, "GET", "s", argv[1]);
+ ASSERT_NOERROR(reply)
+ size_t curlen = 0, oldvallen = 0;
+ const char *oldval = RedisModule_StringPtrLen(oldvalstr, &oldvallen);
+ const char *curval = RedisModule_CallReplyStringPtr(reply, &curlen);
+ if (((flag == OBJ_OP_IE) &&
+ (!curval || (oldvallen != curlen) || strncmp(oldval, curval, curlen)))
+ ||
+ ((flag == OBJ_OP_NE) && curval && (oldvallen == curlen) &&
+ !strncmp(oldval, curval, curlen))) {
+ RedisModule_FreeCallReply(reply);
+ return RedisModule_ReplyWithNull(ctx);
+ }
+ RedisModule_FreeCallReply(reply);
+ }
+
+
+ /* Prepare the arguments for the command. */
+ int i, j=0, cmdargc=argc-3;
+ RedisModuleString *cmdargv[cmdargc];
+ for (i = 1; i < argc-2; i++) {
+ if ((flag == OBJ_OP_IE || flag == OBJ_OP_NE) && (i == 3))
+ continue;
+ cmdargv[j++] = argv[i];
+ }
+
+ /* Call the command and pass back the reply. */
+ reply = RedisModule_Call(ctx, "MSET", "v!", cmdargv, j);
+ ASSERT_NOERROR(reply)
+ int replytype = RedisModule_CallReplyType(reply);
+ if (replytype == REDISMODULE_REPLY_NULL) {
+ RedisModule_ReplyWithNull(ctx);
+ }
+ else {
+ cmdargc = 2;
+ cmdargv[0] = channel;
+ cmdargv[1] = message;
+ RedisModuleCallReply *pubreply = RedisModule_Call(ctx, "PUBLISH", "v", cmdargv, cmdargc);
+ RedisModule_FreeCallReply(pubreply);
+ RedisModule_ReplyWithCallReply(ctx, reply);
+ }
+
+ RedisModule_FreeCallReply(reply);
+ return REDISMODULE_OK;
+}
+
+int SetPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NO);
+}
+
+int SetIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_IE);
+}
+
+int SetNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NE);
+}
+
+int SetNXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NX);
+}
+
+int SetXXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_XX);
+}
+
+int delPubStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
+ int argc, const int flag)
+{
+ RedisModuleString *oldvalstr = NULL, *channel = NULL, *message = NULL;
+ RedisModuleCallReply *reply = NULL;
+
+ if (flag == OBJ_OP_NO) {
+ if (argc < 4)
+ return RedisModule_WrongArity(ctx);
+ else {
+ channel = argv[argc-2];
+ message = argv[argc-1];
+ }
+ } else {
+ if (argc != 5)
+ return RedisModule_WrongArity(ctx);
+ else {
+ oldvalstr = argv[2];
+ channel = argv[3];
+ message = argv[4];
+ }
+ }
+
+ if (flag != OBJ_OP_NO) {
+ /*Check if key type is string*/
+ RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
+ REDISMODULE_READ);
+ int type = RedisModule_KeyType(key);
+ RedisModule_CloseKey(key);
+
+ if (type == REDISMODULE_KEYTYPE_EMPTY) {
+ return RedisModule_ReplyWithLongLong(ctx, 0);
+ } else if (type != REDISMODULE_KEYTYPE_STRING) {
+ return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
+ }
+ }
+
+ if (flag == OBJ_OP_IE || flag == OBJ_OP_NE) {
+ /*Get the value*/
+ reply = RedisModule_Call(ctx, "GET", "s", argv[1]);
+ ASSERT_NOERROR(reply)
+ size_t curlen = 0, oldvallen = 0;
+ const char *oldval = RedisModule_StringPtrLen(oldvalstr, &oldvallen);
+ const char *curval = RedisModule_CallReplyStringPtr(reply, &curlen);
+ if (((flag == OBJ_OP_IE) &&
+ (!curval || (oldvallen != curlen) || strncmp(oldval, curval, curlen)))
+ ||
+ ((flag == OBJ_OP_NE) && curval && (oldvallen == curlen) &&
+ !strncmp(oldval, curval, curlen))) {
+ RedisModule_FreeCallReply(reply);
+ return RedisModule_ReplyWithLongLong(ctx, 0);
+ }
+ RedisModule_FreeCallReply(reply);
+ }
+
+
+ /* Prepare the arguments for the command. */
+ int i, j=0, cmdargc=argc-3;
+ RedisModuleString *cmdargv[cmdargc];
+ for (i = 1; i < argc-2; i++) {
+ if ((flag == OBJ_OP_IE || flag == OBJ_OP_NE) && (i == 2))
+ continue;
+ cmdargv[j++] = argv[i];
+ }
+
+ /* Call the command and pass back the reply. */
+ reply = RedisModule_Call(ctx, "UNLINK", "v!", cmdargv, j);
+ ASSERT_NOERROR(reply)
+ int replytype = RedisModule_CallReplyType(reply);
+ if (replytype == REDISMODULE_REPLY_NULL) {
+ RedisModule_ReplyWithNull(ctx);
+ }
+ else if (RedisModule_CallReplyInteger(reply) == 0) {
+ RedisModule_ReplyWithCallReply(ctx, reply);
+ } else {
+ cmdargc = 2;
+ cmdargv[0] = channel;
+ cmdargv[1] = message;
+ RedisModuleCallReply *pubreply = RedisModule_Call(ctx, "PUBLISH", "v", cmdargv, cmdargc);
+ RedisModule_FreeCallReply(pubreply);
+ RedisModule_ReplyWithCallReply(ctx, reply);
+ }
+
+ RedisModule_FreeCallReply(reply);
+ return REDISMODULE_OK;
+}
+
+int DelPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ return delPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NO);
+}
+
+int DelIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ return delPubStringGenericCommand(ctx, argv, argc, OBJ_OP_IE);
+}
+
+int DelNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ return delPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NE);
+}
+
+/* This function must be present on each Redis module. It is used in order to
+ * register the commands into the Redis server. */
+int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
+ REDISMODULE_NOT_USED(argv);
+ REDISMODULE_NOT_USED(argc);
+
+ if (RedisModule_Init(ctx,"exstrings",1,REDISMODULE_APIVER_1)
+ == REDISMODULE_ERR) return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"setie",
+ SetIE_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"setne",
+ SetNE_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"delie",
+ DelIE_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"delne",
+ DelNE_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"nget",
+ NGet_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"ndel",
+ NDel_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"msetpub",
+ SetPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"setiepub",
+ SetIEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"setnepub",
+ SetNEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"setxxpub",
+ SetXXPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"setnxpub",
+ SetNXPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"delpub",
+ DelPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"deliepub",
+ DelIEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"delnepub",
+ DelNEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ return REDISMODULE_OK;
+}
--- /dev/null
+/*
+ * Copyright (c) 2018-2019 Nokia.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EXSTRINGSTUB_H_
+#define EXSTRINGSTUB_H_
+
+
+#include "redismodule.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "../../../../redismodule/tst/mock/include/redismodule.h"
+
+int setStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, const int flag);
+int SetIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int SetNE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) ;
+int delStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, const int flag);
+int DelIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int DelNE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int SetPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int SetIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int SetNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int SetNXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int SetXXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int DelPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int DelIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int DelNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int NGet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int NDel_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int setPubStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, const int flag);
+int delPubStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, const int flag);
+
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2018-2019 Nokia.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef REDISMODULE_H
+#define REDISMODULE_H
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
+
+/* ---------------- Defines common between core and modules --------------- */
+
+
+
+
+/* Error status return values. */
+#define REDISMODULE_OK 0
+#define REDISMODULE_ERR 1
+
+/* API versions. */
+#define REDISMODULE_APIVER_1 1
+
+/* API flags and constants */
+#define REDISMODULE_READ (1<<0)
+#define REDISMODULE_WRITE (1<<1)
+
+#define REDISMODULE_LIST_HEAD 0
+#define REDISMODULE_LIST_TAIL 1
+
+/* Key types. */
+#define REDISMODULE_KEYTYPE_EMPTY 0
+#define REDISMODULE_KEYTYPE_STRING 1
+#define REDISMODULE_KEYTYPE_LIST 2
+#define REDISMODULE_KEYTYPE_HASH 3
+#define REDISMODULE_KEYTYPE_SET 4
+#define REDISMODULE_KEYTYPE_ZSET 5
+#define REDISMODULE_KEYTYPE_MODULE 6
+
+/* Reply types. */
+#define REDISMODULE_REPLY_UNKNOWN -1
+#define REDISMODULE_REPLY_STRING 0
+#define REDISMODULE_REPLY_ERROR 1
+#define REDISMODULE_REPLY_INTEGER 2
+#define REDISMODULE_REPLY_ARRAY 3
+#define REDISMODULE_REPLY_NULL 4
+
+/* Postponed array length. */
+#define REDISMODULE_POSTPONED_ARRAY_LEN -1
+
+/* Expire */
+#define REDISMODULE_NO_EXPIRE -1
+
+/* Sorted set API flags. */
+#define REDISMODULE_ZADD_XX (1<<0)
+#define REDISMODULE_ZADD_NX (1<<1)
+#define REDISMODULE_ZADD_ADDED (1<<2)
+#define REDISMODULE_ZADD_UPDATED (1<<3)
+#define REDISMODULE_ZADD_NOP (1<<4)
+
+/* Hash API flags. */
+#define REDISMODULE_HASH_NONE 0
+#define REDISMODULE_HASH_NX (1<<0)
+#define REDISMODULE_HASH_XX (1<<1)
+#define REDISMODULE_HASH_CFIELDS (1<<2)
+#define REDISMODULE_HASH_EXISTS (1<<3)
+
+/* Context Flags: Info about the current context returned by RM_GetContextFlags */
+
+/* The command is running in the context of a Lua script */
+#define REDISMODULE_CTX_FLAGS_LUA 0x0001
+/* The command is running inside a Redis transaction */
+#define REDISMODULE_CTX_FLAGS_MULTI 0x0002
+/* The instance is a master */
+#define REDISMODULE_CTX_FLAGS_MASTER 0x0004
+/* The instance is a slave */
+#define REDISMODULE_CTX_FLAGS_SLAVE 0x0008
+/* The instance is read-only (usually meaning it's a slave as well) */
+#define REDISMODULE_CTX_FLAGS_READONLY 0x0010
+/* The instance is running in cluster mode */
+#define REDISMODULE_CTX_FLAGS_CLUSTER 0x0020
+/* The instance has AOF enabled */
+#define REDISMODULE_CTX_FLAGS_AOF 0x0040 //
+/* The instance has RDB enabled */
+#define REDISMODULE_CTX_FLAGS_RDB 0x0080 //
+/* The instance has Maxmemory set */
+#define REDISMODULE_CTX_FLAGS_MAXMEMORY 0x0100
+/* Maxmemory is set and has an eviction policy that may delete keys */
+#define REDISMODULE_CTX_FLAGS_EVICT 0x0200
+
+
+/* A special pointer that we can use between the core and the module to signal
+ * field deletion, and that is impossible to be a valid pointer. */
+#define REDISMODULE_HASH_DELETE ((RedisModuleString*)(long)1)
+
+/* Error messages. */
+#define REDISMODULE_ERRORMSG_WRONGTYPE "WRONGTYPE Operation against a key holding the wrong kind of value"
+
+#define REDISMODULE_POSITIVE_INFINITE (1.0/0.0)
+#define REDISMODULE_NEGATIVE_INFINITE (-1.0/0.0)
+
+#define REDISMODULE_NOT_USED(V) ((void) V)
+
+/* ------------------------- End of common defines ------------------------ */
+
+
+
+
+#ifndef REDISMODULE_CORE
+
+
+
+typedef long long mstime_t;
+
+/* Incomplete structures for compiler checks but opaque access. */
+typedef struct RedisModuleCtx RedisModuleCtx;
+typedef struct RedisModuleKey RedisModuleKey;
+typedef struct RedisModuleString RedisModuleString;
+typedef struct RedisModuleCallReply RedisModuleCallReply;
+typedef struct RedisModuleIO RedisModuleIO;
+typedef struct RedisModuleType RedisModuleType;
+typedef struct RedisModuleDigest RedisModuleDigest;
+typedef struct RedisModuleBlockedClient RedisModuleBlockedClient;
+
+//typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+
+typedef void *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver);
+typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value);
+typedef void (*RedisModuleTypeRewriteFunc)(RedisModuleIO *aof, RedisModuleString *key, void *value);
+typedef size_t (*RedisModuleTypeMemUsageFunc)(const void *value);
+typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value);
+typedef void (*RedisModuleTypeFreeFunc)(void *value);
+
+#define REDISMODULE_TYPE_METHOD_VERSION 1
+typedef struct RedisModuleTypeMethods {
+ uint64_t version;
+ RedisModuleTypeLoadFunc rdb_load;
+ RedisModuleTypeSaveFunc rdb_save;
+ RedisModuleTypeRewriteFunc aof_rewrite;
+ RedisModuleTypeMemUsageFunc mem_usage;
+ RedisModuleTypeDigestFunc digest;
+ RedisModuleTypeFreeFunc free;
+} RedisModuleTypeMethods;
+
+#define REDISMODULE_GET_API(name) \
+ RedisModule_GetApi("RedisModule_" #name, ((void **)&RedisModule_ ## name))
+
+#define REDISMODULE_API_FUNC(x) (*x)
+
+#if 1
+
+
+typedef struct redisObject {
+ unsigned type:4;
+ unsigned encoding:4;
+ int refcount;
+ void *ptr;
+} robj;
+/* This structure represents a module inside the system. */
+struct RedisModule {
+ void *handle; /* Module dlopen() handle. */
+ char *name; /* Module name. */
+ int ver; /* Module version. We use just progressive integers. */
+ int apiver; /* Module API version as requested during initialization.*/
+ //list *types; /* Module data types. */
+};
+typedef struct RedisModule RedisModule;
+
+//static dict *modules; /* Hash table of modules. SDS -> RedisModule ptr.*/
+
+/* Entries in the context->amqueue array, representing objects to free
+ * when the callback returns. */
+struct AutoMemEntry {
+ void *ptr;
+ int type;
+};
+
+/* AutMemEntry type field values. */
+#define REDISMODULE_AM_KEY 0
+#define REDISMODULE_AM_STRING 1
+#define REDISMODULE_AM_REPLY 2
+#define REDISMODULE_AM_FREED 3 /* Explicitly freed by user already. */
+
+/* The pool allocator block. Redis Modules can allocate memory via this special
+ * allocator that will automatically release it all once the callback returns.
+ * This means that it can only be used for ephemeral allocations. However
+ * there are two advantages for modules to use this API:
+ *
+ * 1) The memory is automatically released when the callback returns.
+ * 2) This allocator is faster for many small allocations since whole blocks
+ * are allocated, and small pieces returned to the caller just advancing
+ * the index of the allocation.
+ *
+ * Allocations are always rounded to the size of the void pointer in order
+ * to always return aligned memory chunks. */
+
+#define REDISMODULE_POOL_ALLOC_MIN_SIZE (1024*8)
+#define REDISMODULE_POOL_ALLOC_ALIGN (sizeof(void*))
+
+typedef struct RedisModulePoolAllocBlock {
+ uint32_t size;
+ uint32_t used;
+ struct RedisModulePoolAllocBlock *next;
+ char memory[];
+} RedisModulePoolAllocBlock;
+
+/* This structure represents the context in which Redis modules operate.
+ * Most APIs module can access, get a pointer to the context, so that the API
+ * implementation can hold state across calls, or remember what to free after
+ * the call and so forth.
+ *
+ * Note that not all the context structure is always filled with actual values
+ * but only the fields needed in a given context. */
+
+struct RedisModuleBlockedClient;
+
+struct RedisModuleCtx {
+ void *getapifuncptr; /* NOTE: Must be the first field. */
+ struct RedisModule *module; /* Module reference. */
+ //client *client; /* Client calling a command. */
+ struct RedisModuleBlockedClient *blocked_client; /* Blocked client for
+ thread safe context. */
+ struct AutoMemEntry *amqueue; /* Auto memory queue of objects to free. */
+ int amqueue_len; /* Number of slots in amqueue. */
+ int amqueue_used; /* Number of used slots in amqueue. */
+ int flags; /* REDISMODULE_CTX_... flags. */
+ void **postponed_arrays; /* To set with RM_ReplySetArrayLength(). */
+ int postponed_arrays_count; /* Number of entries in postponed_arrays. */
+ void *blocked_privdata; /* Privdata set when unblocking a client. */
+
+ /* Used if there is the REDISMODULE_CTX_KEYS_POS_REQUEST flag set. */
+ int *keys_pos;
+ int keys_count;
+
+ struct RedisModulePoolAllocBlock *pa_head;
+};
+typedef struct RedisModuleCtx RedisModuleCtx;
+
+#define REDISMODULE_CTX_INIT {(void*)(unsigned long)&RM_GetApi, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, 0, NULL, NULL, 0, NULL}
+#define REDISMODULE_CTX_MULTI_EMITTED (1<<0)
+#define REDISMODULE_CTX_AUTO_MEMORY (1<<1)
+#define REDISMODULE_CTX_KEYS_POS_REQUEST (1<<2)
+#define REDISMODULE_CTX_BLOCKED_REPLY (1<<3)
+#define REDISMODULE_CTX_BLOCKED_TIMEOUT (1<<4)
+#define REDISMODULE_CTX_THREAD_SAFE (1<<5)
+
+/* This represents a Redis key opened with RM_OpenKey(). */
+struct RedisModuleKey {
+ RedisModuleCtx *ctx;
+ //redisDb *db;
+ robj *key; /* Key name object. */
+ robj *value; /* Value object, or NULL if the key was not found. */
+ void *iter; /* Iterator. */
+ int mode; /* Opening mode. */
+
+ /* Zset iterator. */
+ uint32_t ztype; /* REDISMODULE_ZSET_RANGE_* */
+ //zrangespec zrs; /* Score range. */
+ //zlexrangespec zlrs; /* Lex range. */
+ uint32_t zstart; /* Start pos for positional ranges. */
+ uint32_t zend; /* End pos for positional ranges. */
+ void *zcurrent; /* Zset iterator current node. */
+ int zer; /* Zset iterator end reached flag
+ (true if end was reached). */
+};
+typedef struct RedisModuleKey RedisModuleKey;
+
+/* RedisModuleKey 'ztype' values. */
+#define REDISMODULE_ZSET_RANGE_NONE 0 /* This must always be 0. */
+#define REDISMODULE_ZSET_RANGE_LEX 1
+#define REDISMODULE_ZSET_RANGE_SCORE 2
+#define REDISMODULE_ZSET_RANGE_POS 3
+
+/* Function pointer type of a function representing a command inside
+ * a Redis module. */
+
+typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+
+
+/* This struct holds the information about a command registered by a module.*/
+struct RedisModuleCommandProxy {
+ struct RedisModule *module;
+ RedisModuleCmdFunc func;
+ struct redisCommand *rediscmd;
+};
+typedef struct RedisModuleCommandProxy RedisModuleCommandProxy;
+
+#define REDISMODULE_REPLYFLAG_NONE 0
+#define REDISMODULE_REPLYFLAG_TOPARSE (1<<0) /* Protocol must be parsed. */
+#define REDISMODULE_REPLYFLAG_NESTED (1<<1) /* Nested reply object. No proto
+ or struct free. */
+
+/* Reply of RM_Call() function. The function is filled in a lazy
+ * way depending on the function called on the reply structure. By default
+ * only the type, proto and protolen are filled. */
+typedef struct RedisModuleCallReply {
+ RedisModuleCtx *ctx;
+ int type; /* REDISMODULE_REPLY_... */
+ int flags; /* REDISMODULE_REPLYFLAG_... */
+ size_t len; /* Len of strings or num of elements of arrays. */
+ char *proto; /* Raw reply protocol. An SDS string at top-level object. */
+ size_t protolen;/* Length of protocol. */
+ union {
+ const char *str; /* String pointer for string and error replies. This
+ does not need to be freed, always points inside
+ a reply->proto buffer of the reply object or, in
+ case of array elements, of parent reply objects. */
+ long long ll; /* Reply value for integer reply. */
+ struct RedisModuleCallReply *array; /* Array of sub-reply elements. */
+ } val;
+} RedisModuleCallReply;
+
+/* Structure representing a blocked client. We get a pointer to such
+ * an object when blocking from modules. */
+typedef struct RedisModuleBlockedClient {
+ //client *client; /* Pointer to the blocked client. or NULL if the client
+ // was destroyed during the life of this object. */
+ RedisModule *module; /* Module blocking the client. */
+ RedisModuleCmdFunc reply_callback; /* Reply callback on normal completion.*/
+ RedisModuleCmdFunc timeout_callback; /* Reply callback on timeout. */
+ void (*free_privdata)(void *); /* privdata cleanup callback. */
+ void *privdata; /* Module private data that may be used by the reply
+ or timeout callback. It is set via the
+ RedisModule_UnblockClient() API. */
+ //client *reply_client; /* Fake client used to accumulate replies
+ // in thread safe contexts. */
+ int dbid; /* Database number selected by the original client. */
+} RedisModuleBlockedClient;
+
+#define RedisModuleString robj
+
+#endif
+
+
+
+
+int RedisModule_CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep);
+int RedisModule_WrongArity(RedisModuleCtx *ctx);
+int RedisModule_ReplyWithLongLong(RedisModuleCtx *ctx, long long ll);
+void *RedisModule_OpenKey(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode);
+RedisModuleCallReply *RedisModule_Call(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...);
+void RedisModule_FreeCallReply(RedisModuleCallReply *reply);
+int RedisModule_CallReplyType(RedisModuleCallReply *reply);
+long long RedisModule_CallReplyInteger(RedisModuleCallReply *reply);
+const char *RedisModule_StringPtrLen(const RedisModuleString *str, size_t *len);
+int RedisModule_ReplyWithError(RedisModuleCtx *ctx, const char *err);
+int RedisModule_ReplyWithString(RedisModuleCtx *ctx, RedisModuleString *str);
+int RedisModule_ReplyWithNull(RedisModuleCtx *ctx);
+int RedisModule_ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply);
+const char *RedisModule_CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len);
+RedisModuleString *RedisModule_CreateStringFromCallReply(RedisModuleCallReply *reply);
+
+int RedisModule_KeyType(RedisModuleKey *kp);
+void RedisModule_CloseKey(RedisModuleKey *kp);
+
+/* This is included inline inside each Redis module. */
+int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver);
+
+size_t RedisModule_CallReplyLength(RedisModuleCallReply *reply);
+RedisModuleCallReply *RedisModule_CallReplyArrayElement(RedisModuleCallReply *reply, size_t idx);
+int RedisModule_ReplyWithArray(RedisModuleCtx *ctx, long len);
+
+
+/* Things only defined for the modules core, not exported to modules
+ * including this file. */
+
+#else
+
+/* Things only defined for the modules core, not exported to modules
+ * including this file. */
+#define RedisModuleString robj
+
+#endif /* REDISMODULE_CORE */
+#endif /* REDISMOUDLE_H */
--- /dev/null
+/*
+ * Copyright (c) 2018-2019 Nokia.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+#include <unistd.h>
+#include <string.h>
+
+
+
+
+extern "C" {
+#include "redismodule.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+}
+
+
+int RedisModule_CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep)
+{
+ (void)ctx;
+ (void)name;
+ (void)cmdfunc;
+ (void)strflags;
+ (void)firstkey;
+ (void)lastkey;
+ (void)keystep;
+ return REDISMODULE_OK;
+
+}
+
+int RedisModule_WrongArity(RedisModuleCtx *ctx)
+{
+ (void)ctx;
+ return REDISMODULE_ERR;
+}
+
+int RedisModule_ReplyWithLongLong(RedisModuleCtx *ctx, long long ll)
+{
+
+ (void)ctx;
+ mock().setData("RedisModule_ReplyWithLongLong", (int)ll);
+ return REDISMODULE_OK;
+}
+
+void *RedisModule_OpenKey(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode)
+{
+ (void)ctx;
+ (void)keyname;
+ (void)mode;
+
+ if (mock().hasData("RedisModule_OpenKey_no"))
+ {
+ return (void*)(0);
+ }
+
+ if (mock().hasData("RedisModule_OpenKey_have"))
+ {
+ return (void*)(111111);
+ }
+
+
+ return (void*)(0);
+}
+
+RedisModuleCallReply *RedisModule_Call(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...)
+{
+ (void)ctx;
+ (void)cmdname;
+ (void)fmt;
+
+ if (!strcmp(cmdname, "GET"))
+ mock().setData("GET", 1);
+ else if (!strcmp(cmdname, "SET"))
+ mock().setData("SET", 1);
+ else if (!strcmp(cmdname, "MSET"))
+ mock().setData("MSET", 1);
+ else if (!strcmp(cmdname, "DEL"))
+ mock().setData("DEL", 1);
+ else if (!strcmp(cmdname, "UNLINK"))
+ mock().setData("UNLINK", 1);
+ else if (!strcmp(cmdname, "PUBLISH"))
+ mock().setData("PUBLISH", 1);
+ else if (!strcmp(cmdname, "KEYS"))
+ mock().setData("KEYS", 1);
+ else if (!strcmp(cmdname, "MGET"))
+ mock().setData("MGET", 1);
+
+ if (mock().hasData("RedisModule_Call_Return_Null"))
+ return NULL;
+ else
+ return (RedisModuleCallReply *)1;
+}
+
+void RedisModule_FreeCallReply(RedisModuleCallReply *reply)
+{
+ (void)reply;
+ mock().setData("RedisModule_FreeCallReply", mock().getData("RedisModule_FreeCallReply").getIntValue()+1);
+}
+
+int RedisModule_CallReplyType(RedisModuleCallReply *reply)
+{
+
+ (void)reply;
+ if (mock().hasData("RedisModule_CallReplyType_null"))
+ {
+ return REDISMODULE_REPLY_NULL;
+ }
+
+ if (mock().hasData("RedisModule_CallReplyType_inter"))
+ {
+ return REDISMODULE_REPLY_INTEGER;
+ }
+
+ if (mock().hasData("RedisModule_CallReplyType_str"))
+ {
+ return REDISMODULE_REPLY_STRING;
+ }
+
+ if (mock().hasData("RedisModule_CallReplyType_err"))
+ {
+ return REDISMODULE_REPLY_ERROR;
+ }
+
+ return REDISMODULE_REPLY_NULL;;
+
+}
+
+long long RedisModule_CallReplyInteger(RedisModuleCallReply *reply)
+{
+
+ (void)reply;
+ return mock().getData("RedisModule_CallReplyInteger").getIntValue();
+}
+
+const char *RedisModule_StringPtrLen(const RedisModuleString *str, size_t *len)
+{
+
+ (void)str;
+ *len = 5;
+ if (mock().hasData("RedisModule_String_same"))
+ {
+ return "11111";
+ }
+
+ if (mock().hasData("RedisModule_String_nosame"))
+ {
+ return "22222";
+ }
+
+ return "11111";
+}
+
+int RedisModule_ReplyWithError(RedisModuleCtx *ctx, const char *err)
+{
+ (void)ctx;
+ (void)err;
+ mock().setData("RedisModule_ReplyWithError", 1);
+ return REDISMODULE_OK;
+}
+
+int RedisModule_ReplyWithString(RedisModuleCtx *ctx, RedisModuleString *str)
+{
+ (void)ctx;
+ (void)str;
+ mock().setData("RedisModule_ReplyWithString", mock().getData("RedisModule_ReplyWithString").getIntValue()+1);
+ return REDISMODULE_OK;
+}
+
+int RedisModule_ReplyWithNull(RedisModuleCtx *ctx)
+{
+
+ (void)ctx;
+ mock().setData("RedisModule_ReplyWithNull", 1);
+ return REDISMODULE_OK;
+}
+
+int RedisModule_ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply)
+{
+ (void)ctx;
+ (void)reply;
+ mock().setData("RedisModule_ReplyWithCallReply", 1);
+ return REDISMODULE_OK;
+}
+
+const char *RedisModule_CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len)
+{
+ (void)reply;
+
+ *len = 5;
+
+ if (mock().hasData("RedisModule_String_same"))
+ {
+ return "11111";
+ }
+
+
+ if (mock().hasData("RedisModule_String_nosame"))
+ {
+ *len = 6;
+ return "333333";
+ }
+
+ return "11111";
+}
+
+RedisModuleString *RedisModule_CreateStringFromCallReply(RedisModuleCallReply *reply)
+{
+ (void)reply;
+ return (RedisModuleString *)1;
+}
+
+
+int RedisModule_KeyType(RedisModuleKey *kp)
+{
+
+
+ (void)kp;
+ if (mock().hasData("RedisModule_KeyType_empty"))
+ {
+ return REDISMODULE_KEYTYPE_EMPTY;
+ }
+
+ if (mock().hasData("RedisModule_KeyType_str"))
+ {
+ return REDISMODULE_KEYTYPE_STRING;
+ }
+
+ if (mock().hasData("RedisModule_KeyType_set"))
+ {
+
+ return REDISMODULE_KEYTYPE_SET;
+ }
+
+ return REDISMODULE_KEYTYPE_EMPTY;
+
+
+}
+
+void RedisModule_CloseKey(RedisModuleKey *kp)
+{
+ (void)kp;
+ mock().actualCall("RedisModule_CloseKey");
+}
+
+/* This is included inline inside each Redis module. */
+int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver)
+{
+ (void)ctx;
+ (void)name;
+ (void)ver;
+ (void)apiver;
+ return REDISMODULE_OK;
+}
+
+size_t RedisModule_CallReplyLength(RedisModuleCallReply *reply)
+{
+ (void)reply;
+ return mock().getData("RedisModule_CallReplyLength").getIntValue();
+}
+
+
+RedisModuleCallReply *RedisModule_CallReplyArrayElement(RedisModuleCallReply *reply, size_t idx)
+{
+ (void)reply;
+ (void)idx;
+ return (RedisModuleCallReply *)1;
+}
+
+int RedisModule_ReplyWithArray(RedisModuleCtx *ctx, long len)
+{
+ (void)ctx;
+ mock().setData("RedisModule_ReplyWithArray", (int)len);
+ return REDISMODULE_OK;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2018-2019 Nokia.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+#include <map>
+#include <list>
+#include <set>
+#include <vector>
+#include <syslog.h>
+
+
+//#include <stdio.h>
+//#include <stdlib.h>
+//#include <ctype.h>
+
+
+extern "C" {
+#include "exstringsStub.h"
+#include "redismodule.h"
+}
+
+#include "CppUTest/TestHarness.h"
+#include "CppUTestExt/MockSupport.h"
+
+#define OBJ_OP_NO 0
+#define OBJ_OP_XX (1<<1) /* OP if key exist */
+#define OBJ_OP_NX (1<<2) /* OP if key not exist */
+#define OBJ_OP_IE (1<<4) /* OP if equal old value */
+#define OBJ_OP_NE (1<<5) /* OP if not equal old value */
+
+
+TEST_GROUP(exstring)
+{
+ void setup()
+ {
+
+ mock().enable();
+ mock().ignoreOtherCalls();
+ }
+
+ void teardown()
+ {
+ mock().clear();
+ mock().disable();
+ }
+
+};
+
+TEST(exstring, OnLoad)
+{
+ RedisModuleCtx ctx;
+ int ret = RedisModule_OnLoad(&ctx, 0, 0);
+ CHECK_EQUAL(ret, 0);
+}
+
+TEST(exstring, setie)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[4]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ int ret = SetIE_RedisCommand(&ctx, redisStrVec, 4);
+ CHECK_EQUAL(ret, 0);
+ delete []redisStrVec;
+}
+
+TEST(exstring, setne)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[4]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ int ret = SetNE_RedisCommand(&ctx,redisStrVec, 4);
+ CHECK_EQUAL(ret, 0);
+ delete []redisStrVec;
+}
+
+TEST(exstring, command_parameter_number_incorrect)
+{
+ RedisModuleCtx ctx;
+ int ret = setStringGenericCommand(&ctx, 0, 3, OBJ_OP_IE);
+ CHECK_EQUAL(ret, 1);
+}
+
+
+TEST(exstring, setie_command_no_key)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[4]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ mock().setData("RedisModule_OpenKey_no", 1);
+
+ int ret = setStringGenericCommand(&ctx, redisStrVec, 4, OBJ_OP_IE);
+ CHECK_EQUAL(ret, 0);
+ delete []redisStrVec;
+
+}
+
+
+TEST(exstring, setie_command_has_key_set)
+{
+ RedisModuleCtx ctx;
+ //RedisModuleString str;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[4]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_set", 1);
+ int ret = setStringGenericCommand(&ctx, redisStrVec, 4, OBJ_OP_IE);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 1);
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, setie_command_key_string_nosame)
+{
+ RedisModuleCtx ctx;
+ //RedisModuleString str;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[4]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+
+ mock().setData("RedisModule_String_nosame", 1);
+
+
+ int ret = setStringGenericCommand(&ctx, redisStrVec, 4, OBJ_OP_IE);
+ CHECK_EQUAL(ret, 0);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithNull").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, setie_command_key_same_string_reply)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[4]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ int ret = setStringGenericCommand(&ctx, redisStrVec, 4, OBJ_OP_IE);
+ CHECK_EQUAL(ret, 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
+ delete []redisStrVec;
+}
+
+
+
+TEST(exstring, setne_command_key_string_same_replrstr)
+{
+ RedisModuleCtx ctx;
+ //RedisModuleString str;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[4]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ //mock().setData("RedisModule_CallReplyType_str", 1);
+
+ int ret = setStringGenericCommand(&ctx, redisStrVec, 4, OBJ_OP_NE);
+ CHECK_EQUAL(ret, 0);
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, setne_command_setne_key_string_nosame_replrstr)
+{
+ RedisModuleCtx ctx;
+ //RedisModuleString str;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[4]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_nosame", 1);
+ mock().setData("RedisModule_CallReplyType_str", 1);
+
+ int ret = setStringGenericCommand(&ctx, redisStrVec, 4, OBJ_OP_NE);
+ CHECK_EQUAL(ret, 0);
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, delie)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[3]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = DelIE_RedisCommand(&ctx, redisStrVec, 3);
+ CHECK_EQUAL(ret, 0);
+ mock().checkExpectations();
+ delete []redisStrVec;
+}
+
+TEST(exstring, delne)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[3]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = DelNE_RedisCommand(&ctx,redisStrVec, 3);
+ CHECK_EQUAL(ret, 0);
+ mock().checkExpectations();
+ delete []redisStrVec;
+}
+
+TEST(exstring, del_command_parameter_number_incorrect)
+{
+ RedisModuleCtx ctx;
+ int ret = 0;
+ ret = delStringGenericCommand(&ctx, 0, 2, OBJ_OP_IE);
+ CHECK_EQUAL(ret, 1);
+
+ ret = 0;
+ ret = delStringGenericCommand(&ctx, 0, 4, OBJ_OP_NE);
+ CHECK_EQUAL(ret, 1);
+}
+
+TEST(exstring, delie_command_no_key)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[3]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ mock().setData("RedisModule_OpenKey_no", 1);
+
+ int ret = delStringGenericCommand(&ctx, redisStrVec, 3, OBJ_OP_IE);
+ CHECK_EQUAL(ret, 0);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithLongLong").getIntValue(), 0);
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, delie_command_have_key_set)
+{
+ RedisModuleCtx ctx;
+ //RedisModuleString str;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[3]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_set", 1);
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = delStringGenericCommand(&ctx, redisStrVec, 3, OBJ_OP_IE);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 1);
+ delete []redisStrVec;
+}
+
+TEST(exstring, delie_command_key_string_nosame)
+{
+ RedisModuleCtx ctx;
+ //RedisModuleString str;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[3]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+
+ mock().setData("RedisModule_String_nosame", 1);
+
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = delStringGenericCommand(&ctx, redisStrVec, 3, OBJ_OP_IE);
+ CHECK_EQUAL(ret, 0);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithLongLong").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
+ delete []redisStrVec;
+
+}
+
+
+TEST(exstring, delie_command_key_same_string_reply)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[3]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = delStringGenericCommand(&ctx, redisStrVec, 3, OBJ_OP_IE);
+ CHECK_EQUAL(ret, 0);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
+ delete []redisStrVec;
+}
+
+
+TEST(exstring, delne_command_key_string_same_reply)
+{
+ RedisModuleCtx ctx;
+ //RedisModuleString str;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[3]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_inter", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = delStringGenericCommand(&ctx, redisStrVec, 3, OBJ_OP_NE);
+ CHECK_EQUAL(ret, 0);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithLongLong").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, delne_command_key_string_nosame_reply)
+{
+ RedisModuleCtx ctx;
+ //RedisModuleString str;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[3]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_nosame", 1);
+ mock().setData("RedisModule_CallReplyType_inter", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = delStringGenericCommand(&ctx, redisStrVec, 3, OBJ_OP_NE);
+ CHECK_EQUAL(ret, 0);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, setpub)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = SetPub_RedisCommand(&ctx, redisStrVec, 5);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ delete []redisStrVec;
+}
+
+TEST(exstring, setxxpub)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = SetXXPub_RedisCommand(&ctx, redisStrVec, 5);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ delete []redisStrVec;
+}
+
+TEST(exstring, setnxpub)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = SetNXPub_RedisCommand(&ctx, redisStrVec, 5);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ delete []redisStrVec;
+}
+
+TEST(exstring, setiepub)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[6]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+ redisStrVec[5] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = SetIEPub_RedisCommand(&ctx, redisStrVec, 6);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ delete []redisStrVec;
+}
+
+TEST(exstring, setnepub)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[6]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+ redisStrVec[5] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = SetNEPub_RedisCommand(&ctx, redisStrVec, 6);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ delete []redisStrVec;
+}
+
+TEST(exstring, setpub_command_parameter_number_incorrect)
+{
+ RedisModuleCtx ctx;
+ int ret = 0;
+ ret = setPubStringGenericCommand(&ctx, 0, 2, OBJ_OP_NO);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+ ret = 0;
+ ret = setPubStringGenericCommand(&ctx, 0, 8, OBJ_OP_NO);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+ ret = 0;
+ ret = setPubStringGenericCommand(&ctx, 0, 3, OBJ_OP_XX);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+ ret = 0;
+ ret = setPubStringGenericCommand(&ctx, 0, 6, OBJ_OP_NX);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+ ret = 0;
+ ret = setPubStringGenericCommand(&ctx, 0, 4, OBJ_OP_IE);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+ ret = 0;
+ ret = setPubStringGenericCommand(&ctx, 0, 8, OBJ_OP_NE);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+}
+
+TEST(exstring, setpub_command_no_key_replynull)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)0;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)2;
+ redisStrVec[3] = (RedisModuleString *)3;
+ redisStrVec[4] = (RedisModuleString *)4;
+
+ mock().setData("RedisModule_KeyType_empty", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NO);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("MSET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
+
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, setpub_command_no_key_replystr)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)0;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)2;
+ redisStrVec[3] = (RedisModuleString *)3;
+ redisStrVec[4] = (RedisModuleString *)4;
+
+ mock().setData("RedisModule_KeyType_empty", 1);
+ mock().setData("RedisModule_CallReplyType_str", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NO);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("MSET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
+
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, setxxpub_command_has_no_key)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)0;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)2;
+ redisStrVec[3] = (RedisModuleString *)3;
+ redisStrVec[4] = (RedisModuleString *)4;
+
+ mock().setData("RedisModule_KeyType_empty", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_XX);
+
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithNull").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("MSET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 0);
+
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, setxxpub_command_parameter_has_key_set)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)0;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)2;
+ redisStrVec[3] = (RedisModuleString *)3;
+ redisStrVec[4] = (RedisModuleString *)4;
+
+ mock().setData("RedisModule_KeyType_set", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_XX);
+
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("MSET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 0);
+
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, setxxpub_command_has_key_string)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)0;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)2;
+ redisStrVec[3] = (RedisModuleString *)3;
+ redisStrVec[4] = (RedisModuleString *)4;
+
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_CallReplyType_str", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_XX);
+
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("MSET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
+
+ delete []redisStrVec;
+
+}
+
+
+TEST(exstring, setnxpub_command_has_key_string)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)0;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)2;
+ redisStrVec[3] = (RedisModuleString *)3;
+ redisStrVec[4] = (RedisModuleString *)4;
+
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NX);
+
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithNull").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("MSET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 0);
+
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, setnxpub_command_has_no_key)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)0;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)2;
+ redisStrVec[3] = (RedisModuleString *)3;
+ redisStrVec[4] = (RedisModuleString *)4;
+
+ mock().setData("RedisModule_KeyType_empty", 1);
+ mock().setData("RedisModule_CallReplyType_str", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NX);
+
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("MSET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
+
+ delete []redisStrVec;
+
+}
+
+
+
+TEST(exstring, setiepub_command_has_no_key)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[6]);
+
+ redisStrVec[0] = (RedisModuleString *)0;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)2;
+ redisStrVec[3] = (RedisModuleString *)3;
+ redisStrVec[4] = (RedisModuleString *)4;
+ redisStrVec[5] = (RedisModuleString *)5;
+
+ mock().setData("RedisModule_KeyType_empty", 1);
+ mock().setData("RedisModule_CallReplyType_str", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_IE);
+
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithNull").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("MSET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 0);
+
+ delete []redisStrVec;
+
+}
+
+
+TEST(exstring, setiepub_command_key_string_nosame)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[6]);
+
+ redisStrVec[0] = (RedisModuleString *)0;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)2;
+ redisStrVec[3] = (RedisModuleString *)3;
+ redisStrVec[4] = (RedisModuleString *)4;
+ redisStrVec[5] = (RedisModuleString *)5;
+
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_CallReplyType_str", 1);
+ mock().setData("RedisModule_String_nosame", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_IE);
+
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithNull").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("MSET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
+
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, setiepub_command_key_same_string_replynull)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[6]);
+
+ redisStrVec[0] = (RedisModuleString *)0;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)2;
+ redisStrVec[3] = (RedisModuleString *)3;
+ redisStrVec[4] = (RedisModuleString *)4;
+ redisStrVec[5] = (RedisModuleString *)5;
+
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_IE);
+
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("MSET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithNull").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
+
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, setiepub_command_key_same_string_reply)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[6]);
+
+ redisStrVec[0] = (RedisModuleString *)0;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)2;
+ redisStrVec[3] = (RedisModuleString *)3;
+ redisStrVec[4] = (RedisModuleString *)4;
+ redisStrVec[5] = (RedisModuleString *)5;
+
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_str", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_IE);
+
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("MSET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 3);
+
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, setnepub_command_has_no_key)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[6]);
+
+ redisStrVec[0] = (RedisModuleString *)0;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)2;
+ redisStrVec[3] = (RedisModuleString *)3;
+ redisStrVec[4] = (RedisModuleString *)4;
+ redisStrVec[5] = (RedisModuleString *)5;
+
+ mock().setData("RedisModule_KeyType_empty", 1);
+ mock().setData("RedisModule_CallReplyType_str", 1);
+ mock().setData("RedisModule_String_nosame", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_NE);
+
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("MSET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 3);
+
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, setnepub_command_key_string_same_reply)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[6]);
+
+ redisStrVec[0] = (RedisModuleString *)0;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)2;
+ redisStrVec[3] = (RedisModuleString *)3;
+ redisStrVec[4] = (RedisModuleString *)4;
+ redisStrVec[5] = (RedisModuleString *)5;
+
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_str", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_NE);
+
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("MSET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithNull").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
+
+ delete []redisStrVec;
+
+}
+
+
+TEST(exstring, setnepub_command_key_string_nosame_reply)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[6]);
+
+ redisStrVec[0] = (RedisModuleString *)0;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)2;
+ redisStrVec[3] = (RedisModuleString *)3;
+ redisStrVec[4] = (RedisModuleString *)4;
+ redisStrVec[5] = (RedisModuleString *)5;
+
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_CallReplyType_str", 1);
+ mock().setData("RedisModule_String_nosame", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_NE);
+
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("MSET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 3);
+
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, delpub)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[4]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ int ret = DelPub_RedisCommand(&ctx, redisStrVec, 4);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+
+ delete []redisStrVec;
+}
+
+TEST(exstring, deliepub)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = DelIEPub_RedisCommand(&ctx, redisStrVec, 5);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ delete []redisStrVec;
+}
+
+TEST(exstring, delnepub)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = DelNEPub_RedisCommand(&ctx, redisStrVec, 5);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ delete []redisStrVec;
+}
+
+TEST(exstring, delpub_command_parameter_number_incorrect)
+{
+ RedisModuleCtx ctx;
+ int ret = 0;
+ ret = delPubStringGenericCommand(&ctx, 0, 2, OBJ_OP_NO);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+ ret = 0;
+ ret = delPubStringGenericCommand(&ctx, 0, 4, OBJ_OP_IE);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+ ret = 0;
+ ret = delPubStringGenericCommand(&ctx, 0, 8, OBJ_OP_NE);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+}
+
+TEST(exstring, delpub_command_reply_null)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+ mock().setData("RedisModule_CallReplyInteger", 0);
+ mock().setData("RedisModule_CallReplyType_inter", 1);
+ mock().setData("RedisModule_Call_Return_Null", 0);
+
+ int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NO);
+ CHECK_EQUAL(ret, 0);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 1);
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, delpub_command_reply_error)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+ mock().setData("RedisModule_CallReplyInteger", 0);
+ mock().setData("RedisModule_CallReplyType_err", 1);
+
+ int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NO);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, delpub_command_has_no_key)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+ mock().setData("RedisModule_CallReplyInteger", 0);
+ mock().setData("RedisModule_CallReplyType_inter", 1);
+
+ int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NO);
+ CHECK_EQUAL(ret, 0);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, deliepub_command_has_no_key)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+ mock().setData("RedisModule_KeyType_empty", 1);
+
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_IE);
+ CHECK_EQUAL(ret, 0);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithLongLong").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 0);
+ delete []redisStrVec;
+
+}
+
+TEST(exstring, deliepub_command_has_key_set)
+{
+ RedisModuleCtx ctx;
+ //RedisModuleString str;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_set", 1);
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_IE);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 0);
+
+ delete []redisStrVec;
+}
+
+TEST(exstring, deliepub_command_key_string_nosame)
+{
+ RedisModuleCtx ctx;
+ //RedisModuleString str;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_nosame", 1);
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_IE);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithLongLong").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
+
+ delete []redisStrVec;
+}
+
+TEST(exstring, deliepub_command_same_string_replynull)
+{
+ RedisModuleCtx ctx;
+ //RedisModuleString str;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_null", 1);
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_IE);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithNull").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
+
+ delete []redisStrVec;
+}
+
+TEST(exstring, deliepub_command_same_string_reply)
+{
+ RedisModuleCtx ctx;
+ //RedisModuleString str;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_str", 1);
+ mock().setData("RedisModule_CallReplyInteger", 1);
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_IE);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 3);
+
+ delete []redisStrVec;
+}
+
+TEST(exstring, delnepub_command_same_string_reply)
+{
+ RedisModuleCtx ctx;
+ //RedisModuleString str;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_same", 1);
+ mock().setData("RedisModule_CallReplyType_str", 1);
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NE);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithLongLong").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
+
+ delete []redisStrVec;
+}
+
+TEST(exstring, delnepub_command_nosame_string_reply)
+{
+ RedisModuleCtx ctx;
+ //RedisModuleString str;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+ redisStrVec[2] = (RedisModuleString *)1;
+ redisStrVec[3] = (RedisModuleString *)1;
+ redisStrVec[4] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_OpenKey_have", 1);
+ mock().setData("RedisModule_KeyType_str", 1);
+ mock().setData("RedisModule_String_nosame", 1);
+ mock().setData("RedisModule_CallReplyType_str", 1);
+ mock().setData("RedisModule_CallReplyInteger", 1);
+ mock().expectOneCall("RedisModule_CloseKey");
+ int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NE);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ mock().checkExpectations();
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 3);
+
+ delete []redisStrVec;
+}
+
+TEST(exstring, nget_command_parameter_number_incorrect)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[2]);
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+
+ int ret = NGet_RedisCommand(&ctx, redisStrVec, 3);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+ delete []redisStrVec;
+}
+
+TEST(exstring, nget_command_zero_item)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[2]);
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_CallReplyLength", 0);
+ int ret = NGet_RedisCommand(&ctx, redisStrVec, 2);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ CHECK_EQUAL(mock().getData("KEYS").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
+
+ delete []redisStrVec;
+}
+
+TEST(exstring, nget_command_none_zero_items)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[2]);
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_CallReplyLength", 3);
+ int ret = NGet_RedisCommand(&ctx, redisStrVec, 2);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ CHECK_EQUAL(mock().getData("KEYS").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("MGET").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithArray").getIntValue(), 3*2);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithString").getIntValue(), 3*2);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
+
+ delete []redisStrVec;
+}
+
+TEST(exstring, ndel_command_parameter_parameter_number_incorrect)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[2]);
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+
+ int ret = NDel_RedisCommand(&ctx, redisStrVec, 3);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+ delete []redisStrVec;
+}
+
+TEST(exstring, ndel_command_zero_item)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[2]);
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_CallReplyLength", 0);
+ int ret = NDel_RedisCommand(&ctx, redisStrVec, 2);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ CHECK_EQUAL(mock().getData("KEYS").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithLongLong").getIntValue(), 0);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
+
+ delete []redisStrVec;
+}
+
+TEST(exstring, ndel_command_none_zero_items)
+{
+ RedisModuleCtx ctx;
+ RedisModuleString ** redisStrVec = new (RedisModuleString*[2]);
+ redisStrVec[0] = (RedisModuleString *)1;
+ redisStrVec[1] = (RedisModuleString *)1;
+
+ mock().setData("RedisModule_CallReplyLength", 3);
+ int ret = NDel_RedisCommand(&ctx, redisStrVec, 2);
+ CHECK_EQUAL(ret, REDISMODULE_OK);
+ CHECK_EQUAL(mock().getData("KEYS").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
+ CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
+
+ delete []redisStrVec;
+}
--- /dev/null
+/*
+ * Copyright (c) 2018-2019 Nokia.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CppUTest/CommandLineTestRunner.h"
+
+extern "C" {
+#include <stdio.h>
+}
+
+int main(int ac, char** av)
+{
+ return CommandLineTestRunner::RunAllTests(ac, av);
+}
\ No newline at end of file