651 lines
18 KiB
C
651 lines
18 KiB
C
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "parser.h"
|
|
#include "sds.h"
|
|
#include "test-helper.h"
|
|
|
|
typedef struct log_entry_s log_entry_t;
|
|
|
|
struct log_entry_s {
|
|
redis_protocol obj;
|
|
int type;
|
|
|
|
/* string_t specifics */
|
|
char string_buf[1024];
|
|
int string_size;
|
|
|
|
/* array_t specifics */
|
|
size_t array_len;
|
|
|
|
/* integer_t specifics */
|
|
int64_t integer_value;
|
|
};
|
|
|
|
#define CB_LOG_SIZE 10
|
|
static log_entry_t cb_log[CB_LOG_SIZE];
|
|
static int cb_log_idx = 0;
|
|
|
|
static void reset_cb_log(void) {
|
|
memset(cb_log, 0xff, sizeof(cb_log));
|
|
cb_log_idx = 0;
|
|
}
|
|
|
|
static log_entry_t *dup_cb_log(void) {
|
|
log_entry_t *log = malloc(sizeof(cb_log));
|
|
memcpy(log, cb_log, sizeof(cb_log));
|
|
return log;
|
|
}
|
|
|
|
int on_string(redis_parser *parser, redis_protocol *p, const char *buf, size_t len) {
|
|
((void)parser);
|
|
|
|
log_entry_t *log = (log_entry_t*)p->data;
|
|
|
|
/* Use new entry when this is the first call */
|
|
if (log == NULL) {
|
|
log = p->data = &cb_log[cb_log_idx++];
|
|
log->obj = *p;
|
|
log->type = p->type;
|
|
log->string_buf[0] = '\0';
|
|
log->string_size = p->size;
|
|
}
|
|
|
|
/* Type should never change when called multiple times */
|
|
assert(log->type == p->type);
|
|
|
|
/* Cursor should equal current string length */
|
|
assert(p->cursor == (signed)strlen(log->string_buf));
|
|
|
|
/* Append string data */
|
|
strncat(log->string_buf, buf, len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int on_array(redis_parser *parser, redis_protocol *p, size_t len) {
|
|
((void)parser);
|
|
|
|
log_entry_t *log = (log_entry_t*)p->data;
|
|
|
|
/* Should only be called once */
|
|
assert(log == NULL);
|
|
|
|
/* Use new entry */
|
|
log = p->data = &cb_log[cb_log_idx++];
|
|
log->obj = *p;
|
|
log->type = p->type;
|
|
log->array_len = len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int on_integer(redis_parser *parser, redis_protocol *p, int64_t value) {
|
|
((void)parser);
|
|
|
|
log_entry_t *log = (log_entry_t*)p->data;
|
|
|
|
/* Should only be called once */
|
|
assert(log == NULL);
|
|
|
|
/* Use new entry */
|
|
log = p->data = &cb_log[cb_log_idx++];
|
|
log->obj = *p;
|
|
log->type = p->type;
|
|
log->integer_value = value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int on_nil(redis_parser *parser, redis_protocol *p) {
|
|
((void)parser);
|
|
|
|
log_entry_t *log = (log_entry_t*)p->data;
|
|
|
|
/* Should only be called once */
|
|
assert(log == NULL);
|
|
|
|
/* Use new entry */
|
|
log = p->data = &cb_log[cb_log_idx++];
|
|
log->obj = *p;
|
|
log->type = p->type;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int destroy_called = 0;
|
|
|
|
void destroy(redis_parser *parser, redis_protocol *p) {
|
|
((void)parser);
|
|
((void)p);
|
|
|
|
destroy_called++;
|
|
}
|
|
|
|
static redis_parser_callbacks callbacks = {
|
|
&on_string,
|
|
&on_array,
|
|
&on_integer,
|
|
&on_nil,
|
|
&destroy
|
|
};
|
|
|
|
#define RESET_PARSER(__parser) do { \
|
|
reset_cb_log(); \
|
|
redis_parser_init((__parser), &callbacks); \
|
|
destroy_called = 0; \
|
|
} while(0)
|
|
|
|
void test_char_by_char(const char *buf, size_t len) {
|
|
log_entry_t *ref;
|
|
redis_parser *p;
|
|
redis_protocol *res;
|
|
size_t i, j, k;
|
|
|
|
ref = dup_cb_log();
|
|
p = malloc(sizeof(redis_parser));
|
|
|
|
for (i = 0; i < (len-1); i++) {
|
|
for (j = i+1; j < len; j++) {
|
|
RESET_PARSER(p);
|
|
|
|
#ifdef DEBUG
|
|
sds debug = sdsempty();
|
|
debug = sdscatrepr(debug, buf, i);
|
|
debug = sdscatprintf(debug, " + ");
|
|
debug = sdscatrepr(debug, buf+i, j-i);
|
|
debug = sdscatprintf(debug, " + ");
|
|
debug = sdscatrepr(debug, buf+j, len-j);
|
|
fprintf(stderr, "%s\n", debug);
|
|
sdsfree(debug);
|
|
#endif
|
|
|
|
/* Slice 1 */
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, i), i);
|
|
assert(NULL == res); /* no result */
|
|
|
|
/* Slice 2 */
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf+i, j-i), j-i);
|
|
assert(NULL == res); /* no result */
|
|
|
|
/* Slice 3 */
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf+j, len-j), len-j);
|
|
assert(NULL != res);
|
|
|
|
/* Compare callback log with reference */
|
|
for (k = 0; k < CB_LOG_SIZE; k++) {
|
|
log_entry_t expect = ref[k];
|
|
log_entry_t actual = cb_log[k];
|
|
|
|
/* Not interested in the redis_protocol data */
|
|
memset(&expect.obj, 0, sizeof(expect.obj));
|
|
memset(&actual.obj, 0, sizeof(actual.obj));
|
|
assert(memcmp(&expect, &actual, sizeof(expect)) == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
free(p);
|
|
free(ref);
|
|
}
|
|
|
|
#define SETUP(var) \
|
|
redis_parser _parser, *(var) = &_parser; \
|
|
redis_parser_init((var), &callbacks);
|
|
|
|
/* Not a real test, just print sizeof's */
|
|
TEST(struct_size) {
|
|
printf("redis_protocol: %lu bytes\n", sizeof(redis_protocol));
|
|
printf("redis_parser: %lu bytes\n", sizeof(redis_parser));
|
|
}
|
|
|
|
TEST(string) {
|
|
SETUP(p);
|
|
|
|
const char *buf = "$5\r\nhello\r\n";
|
|
size_t len = 11;
|
|
redis_protocol *res;
|
|
|
|
/* Parse and check resulting protocol_t */
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, len), len);
|
|
assert(res != NULL);
|
|
assert_equal_size_t(res->type, REDIS_STRING);
|
|
assert_equal_size_t(res->poff, 0);
|
|
assert_equal_size_t(res->plen, 11);
|
|
assert_equal_size_t(res->coff, 4);
|
|
assert_equal_size_t(res->clen, 5);
|
|
|
|
/* Check callbacks */
|
|
assert(cb_log_idx == 1);
|
|
assert_equal_int(cb_log[0].string_size, 5);
|
|
assert(!strncmp(cb_log[0].string_buf, buf+4, 5));
|
|
|
|
/* Chunked check */
|
|
test_char_by_char(buf, len);
|
|
}
|
|
|
|
TEST(empty_string) {
|
|
SETUP(p);
|
|
|
|
const char *buf = "$0\r\n\r\n";
|
|
size_t len = 6;
|
|
redis_protocol *res;
|
|
|
|
/* Parse and check resulting protocol_t */
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, len), len);
|
|
assert(res != NULL);
|
|
assert_equal_size_t(res->type, REDIS_STRING);
|
|
assert_equal_size_t(res->poff, 0);
|
|
assert_equal_size_t(res->plen, 6);
|
|
assert_equal_size_t(res->coff, 4);
|
|
assert_equal_size_t(res->clen, 0);
|
|
|
|
/* Check callbacks */
|
|
assert(cb_log_idx == 1);
|
|
assert_equal_int(cb_log[0].string_size, 0);
|
|
assert(!strncmp(cb_log[0].string_buf, buf+4, 0));
|
|
|
|
/* Chunked check */
|
|
test_char_by_char(buf, len);
|
|
}
|
|
|
|
TEST(nil_string) {
|
|
SETUP(p);
|
|
|
|
const char *buf = "$-1\r\n";
|
|
size_t len = 5;
|
|
redis_protocol *res;
|
|
|
|
/* Parse and check resulting protocol_t */
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, len), len);
|
|
assert(res != NULL);
|
|
assert_equal_size_t(res->type, REDIS_NIL);
|
|
assert_equal_size_t(res->poff, 0);
|
|
assert_equal_size_t(res->plen, 5);
|
|
assert_equal_size_t(res->coff, 0);
|
|
assert_equal_size_t(res->clen, 0);
|
|
|
|
/* Chunked check */
|
|
test_char_by_char(buf, len);
|
|
}
|
|
|
|
TEST(array) {
|
|
SETUP(p);
|
|
|
|
const char *buf =
|
|
"*2\r\n"
|
|
"$5\r\nhello\r\n"
|
|
"$5\r\nworld\r\n";
|
|
size_t len = 26;
|
|
redis_protocol *res;
|
|
|
|
/* Parse and check resulting protocol_t */
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, len), len);
|
|
assert(res != NULL);
|
|
assert_equal_size_t(res->type, REDIS_ARRAY);
|
|
assert_equal_size_t(res->poff, 0);
|
|
assert_equal_size_t(res->plen, 26);
|
|
assert_equal_size_t(res->coff, 0);
|
|
assert_equal_size_t(res->clen, 0);
|
|
|
|
/* Check callbacks */
|
|
assert_equal_size_t(cb_log_idx, 3);
|
|
|
|
assert_equal_size_t(cb_log[0].obj.poff, 0);
|
|
assert_equal_size_t(cb_log[0].obj.plen, 4);
|
|
assert_equal_size_t(cb_log[0].array_len, 2);
|
|
|
|
assert_equal_size_t(cb_log[1].obj.poff, 4);
|
|
assert_equal_size_t(cb_log[1].obj.plen, 4+5+2);
|
|
assert_equal_size_t(cb_log[1].obj.coff, 4+4);
|
|
assert_equal_size_t(cb_log[1].obj.clen, 5);
|
|
assert_equal_int(cb_log[1].string_size, 5);
|
|
assert(!strncmp(cb_log[1].string_buf, buf+4+4, 5));
|
|
|
|
assert_equal_size_t(cb_log[2].obj.poff, 4+11);
|
|
assert_equal_size_t(cb_log[2].obj.plen, 4+5+2);
|
|
assert_equal_size_t(cb_log[2].obj.coff, 4+11+4);
|
|
assert_equal_size_t(cb_log[2].obj.clen, 5);
|
|
assert_equal_int(cb_log[2].string_size, 5);
|
|
assert(!strncmp(cb_log[2].string_buf, buf+4+11+4, 5));
|
|
|
|
/* Chunked check */
|
|
test_char_by_char(buf, len);
|
|
}
|
|
|
|
TEST(empty_array) {
|
|
SETUP(p);
|
|
|
|
const char *buf = "*0\r\n";
|
|
size_t len = 4;
|
|
redis_protocol *res;
|
|
|
|
/* Parse and check resulting protocol_t */
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, len), len);
|
|
assert(res != NULL);
|
|
assert_equal_size_t(res->type, REDIS_ARRAY);
|
|
assert_equal_size_t(res->poff, 0);
|
|
assert_equal_size_t(res->plen, 4);
|
|
|
|
/* Check callbacks */
|
|
assert_equal_size_t(cb_log_idx, 1);
|
|
assert_equal_size_t(cb_log[0].array_len, 0);
|
|
|
|
/* Chunked check */
|
|
test_char_by_char(buf, len);
|
|
}
|
|
|
|
TEST(nil_array) {
|
|
SETUP(p);
|
|
|
|
const char *buf = "*-1\r\n";
|
|
size_t len = 5;
|
|
redis_protocol *res;
|
|
|
|
/* Parse and check resulting protocol_t */
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, len), len);
|
|
assert(res != NULL);
|
|
assert_equal_size_t(res->type, REDIS_NIL);
|
|
assert_equal_size_t(res->poff, 0);
|
|
assert_equal_size_t(res->plen, 5);
|
|
|
|
/* Chunked check */
|
|
test_char_by_char(buf, len);
|
|
}
|
|
|
|
TEST(integer) {
|
|
SETUP(p);
|
|
|
|
const char *buf = ":1234\r\n";
|
|
size_t len = 7;
|
|
redis_protocol *res;
|
|
|
|
/* Parse and check resulting protocol_t */
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, len), len);
|
|
assert(res != NULL);
|
|
assert_equal_size_t(res->type, REDIS_INTEGER);
|
|
assert_equal_size_t(res->poff, 0);
|
|
assert_equal_size_t(res->plen, 7);
|
|
assert_equal_size_t(res->coff, 1);
|
|
assert_equal_size_t(res->clen, 4);
|
|
|
|
/* Check callbacks */
|
|
assert_equal_size_t(cb_log_idx, 1);
|
|
assert_equal_size_t(cb_log[0].integer_value, 1234);
|
|
|
|
/* Chunked check */
|
|
test_char_by_char(buf, len);
|
|
|
|
/* Negative sign */
|
|
buf = ":-123\r\n";
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, strlen(buf)), strlen(buf));
|
|
assert(res != NULL);
|
|
assert_equal_size_t(cb_log_idx, 1);
|
|
assert_equal_int64_t(cb_log[0].integer_value, -123);
|
|
test_char_by_char(buf, strlen(buf));
|
|
|
|
/* Positive sign */
|
|
buf = ":+123\r\n";
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, strlen(buf)), strlen(buf));
|
|
assert(res != NULL);
|
|
assert_equal_size_t(cb_log_idx, 1);
|
|
assert_equal_int64_t(cb_log[0].integer_value, 123);
|
|
test_char_by_char(buf, strlen(buf));
|
|
|
|
/* Zero */
|
|
buf = ":0\r\n";
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, strlen(buf)), strlen(buf));
|
|
assert(res != NULL);
|
|
assert_equal_size_t(cb_log_idx, 1);
|
|
assert_equal_int64_t(cb_log[0].integer_value, 0);
|
|
test_char_by_char(buf, strlen(buf));
|
|
|
|
/* Signed zero, positive */
|
|
buf = ":+0\r\n";
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, strlen(buf)), 2);
|
|
assert(res == NULL);
|
|
assert(redis_parser_err(p) == RPE_INVALID_INT);
|
|
|
|
/* Signed zero, negative */
|
|
buf = ":-0\r\n";
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, strlen(buf)), 2);
|
|
assert(res == NULL);
|
|
assert(redis_parser_err(p) == RPE_INVALID_INT);
|
|
|
|
/* Start with 0 */
|
|
buf = ":0123\r\n";
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, strlen(buf)), 2);
|
|
assert(res == NULL);
|
|
assert(redis_parser_err(p) == RPE_EXPECTED_CR);
|
|
|
|
/* Start with non-digit */
|
|
buf = ":x123\r\n";
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, strlen(buf)), 1);
|
|
assert(res == NULL);
|
|
assert(redis_parser_err(p) == RPE_INVALID_INT);
|
|
|
|
/* Non-digit in the middle */
|
|
buf = ":12x3\r\n";
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, strlen(buf)), 3);
|
|
assert(res == NULL);
|
|
assert(redis_parser_err(p) == RPE_INVALID_INT);
|
|
|
|
/* Non-digit at the end */
|
|
buf = ":123x\r\n";
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, strlen(buf)), 4);
|
|
assert(res == NULL);
|
|
assert(redis_parser_err(p) == RPE_INVALID_INT);
|
|
|
|
/* Signed 64-bit maximum */
|
|
buf = ":9223372036854775807\r\n";
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, strlen(buf)), strlen(buf));
|
|
assert(res != NULL);
|
|
assert_equal_size_t(cb_log_idx, 1);
|
|
assert_equal_int64_t(cb_log[0].integer_value, INT64_MAX);
|
|
test_char_by_char(buf, strlen(buf));
|
|
|
|
/* Signed 64-bit maximum overflow */
|
|
buf = ":9223372036854775808\r\n";
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, strlen(buf)), strlen(buf)-3);
|
|
assert(res == NULL);
|
|
assert(redis_parser_err(p) == RPE_OVERFLOW);
|
|
|
|
/* Signed 64-bit minimum */
|
|
buf = ":-9223372036854775808\r\n";
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, strlen(buf)), strlen(buf));
|
|
assert(res != NULL);
|
|
assert_equal_size_t(cb_log_idx, 1);
|
|
assert_equal_int64_t(cb_log[0].integer_value, INT64_MIN);
|
|
test_char_by_char(buf, strlen(buf));
|
|
|
|
/* Signed 64-bit minimum overflow (or underflow...) */
|
|
buf = ":-9223372036854775809\r\n";
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, strlen(buf)), strlen(buf)-3);
|
|
assert(res == NULL);
|
|
assert(redis_parser_err(p) == RPE_OVERFLOW);
|
|
}
|
|
|
|
TEST(nil) {
|
|
SETUP(p);
|
|
|
|
const char *buf = "$-1\r\n";
|
|
size_t len = 5;
|
|
redis_protocol *res;
|
|
|
|
/* Parse and check resulting protocol_t */
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, len), len);
|
|
assert(res != NULL);
|
|
assert_equal_size_t(res->type, REDIS_NIL);
|
|
assert_equal_size_t(res->poff, 0);
|
|
assert_equal_size_t(res->plen, 5);
|
|
assert_equal_size_t(res->coff, 0);
|
|
assert_equal_size_t(res->clen, 0);
|
|
|
|
/* Check callbacks */
|
|
assert_equal_size_t(cb_log_idx, 1);
|
|
|
|
/* Chunked check */
|
|
test_char_by_char(buf, len);
|
|
}
|
|
|
|
TEST(status) {
|
|
SETUP(p);
|
|
|
|
const char *buf = "+status\r\n";
|
|
size_t len = 9;
|
|
redis_protocol *res;
|
|
|
|
/* Parse and check resulting protocol_t */
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, len), len);
|
|
assert(res != NULL);
|
|
assert_equal_size_t(res->type, REDIS_STATUS);
|
|
assert_equal_size_t(res->poff, 0);
|
|
assert_equal_size_t(res->plen, 9);
|
|
assert_equal_size_t(res->coff, 1);
|
|
assert_equal_size_t(res->clen, 6);
|
|
assert(!strncmp(cb_log[0].string_buf, buf+1, 6));
|
|
|
|
/* Chunked check */
|
|
test_char_by_char(buf, len);
|
|
}
|
|
|
|
TEST(error) {
|
|
SETUP(p);
|
|
|
|
const char *buf = "-error\r\n";
|
|
size_t len = 8;
|
|
redis_protocol *res;
|
|
|
|
/* Parse and check resulting protocol_t */
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, buf, len), len);
|
|
assert(res != NULL);
|
|
assert_equal_size_t(res->type, REDIS_ERROR);
|
|
assert_equal_size_t(res->poff, 0);
|
|
assert_equal_size_t(res->plen, 8);
|
|
assert_equal_size_t(res->coff, 1);
|
|
assert_equal_size_t(res->clen, 5);
|
|
assert(!strncmp(cb_log[0].string_buf, buf+1, 5));
|
|
|
|
/* Chunked check */
|
|
test_char_by_char(buf, len);
|
|
}
|
|
|
|
TEST(abort_after_error) {
|
|
SETUP(p);
|
|
|
|
redis_protocol *res;
|
|
enum redis_parser_errno err;
|
|
|
|
assert_equal_size_t(redis_parser_execute(p, &res, "+ok\r", 4), 4);
|
|
assert(res == NULL);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, "\r", 1), 0);
|
|
assert(res == NULL);
|
|
|
|
/* Test if the error matches what we expect */
|
|
err = redis_parser_err(p);
|
|
assert(err == RPE_EXPECTED_LF);
|
|
assert(strcmp("expected \\n", redis_parser_strerror(err)) == 0);
|
|
|
|
/* Test that the parser doesn't continue after an error */
|
|
assert_equal_size_t(redis_parser_execute(p, &res, "\n", 1), 0);
|
|
assert(res == NULL);
|
|
}
|
|
|
|
TEST(destroy_callback_after_success) {
|
|
SETUP(p);
|
|
|
|
redis_protocol *res;
|
|
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, "+ok\r\n", 5), 5);
|
|
assert(res != NULL);
|
|
assert(redis_parser_err(p) == RPE_OK);
|
|
|
|
/* Test that the destroy callback is NOT called when there are
|
|
* no errors or the parser is in-flight */
|
|
redis_parser_destroy(p);
|
|
assert_equal_int(destroy_called, 0);
|
|
}
|
|
|
|
TEST(destroy_callback_after_error) {
|
|
SETUP(p);
|
|
|
|
redis_protocol *res;
|
|
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, "+ok\r\r", 5), 4);
|
|
assert(res == NULL);
|
|
assert(redis_parser_err(p) != RPE_OK);
|
|
|
|
/* Test that the destroy callback is called after an error */
|
|
redis_parser_destroy(p);
|
|
assert_equal_int(destroy_called, 1);
|
|
}
|
|
|
|
TEST(destroy_callback_in_flight) {
|
|
SETUP(p);
|
|
|
|
redis_protocol *res;
|
|
|
|
RESET_PARSER(p);
|
|
assert_equal_size_t(redis_parser_execute(p, &res, "+ok\r", 4), 4);
|
|
assert(res == NULL);
|
|
assert(redis_parser_err(p) == RPE_OK);
|
|
|
|
/* Test that the destroy callback is called when the parser is in-flight */
|
|
redis_parser_destroy(p);
|
|
assert_equal_int(destroy_called, 1);
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
((void)argc);
|
|
((void)argv);
|
|
|
|
test_struct_size();
|
|
|
|
test_string();
|
|
test_empty_string();
|
|
test_nil_string();
|
|
|
|
test_array();
|
|
test_empty_array();
|
|
test_nil_array();
|
|
|
|
test_integer();
|
|
test_nil();
|
|
test_status();
|
|
test_error();
|
|
|
|
test_abort_after_error();
|
|
test_destroy_callback_after_success();
|
|
test_destroy_callback_after_error();
|
|
test_destroy_callback_in_flight();
|
|
|
|
return 0;
|
|
}
|