resp.c

Basic RESP handling library in C
git clone git://git.finwo.net/lib/resp.c
Log | Files | Refs | LICENSE

basic.c (4317B)


      1 /*
      2  * RESP encoding and decoding tests using finwo/assert.
      3  */
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 #include <unistd.h>
      8 
      9 #include "../src/resp.h"
     10 #include "test.h"
     11 
     12 /* Write encoded buf to pipe, read back one RESP value. Caller resp_frees result. */
     13 static resp_object *round_trip(const char *buf, size_t len) {
     14   int fd[2];
     15   if (pipe(fd) != 0) return NULL;
     16   ssize_t n = write(fd[1], buf, len);
     17   close(fd[1]);
     18   if (n != (ssize_t)len) {
     19     close(fd[0]);
     20     return NULL;
     21   }
     22   resp_object *o = resp_read(fd[0]);
     23   close(fd[0]);
     24   return o;
     25 }
     26 
     27 void test_resp_encode_decode_bulk(void) {
     28   resp_object        bulk = {.type = RESPT_BULK, .u = {.s = strdup("hello")}};
     29   const resp_object *av[] = {&bulk};
     30   char              *buf  = NULL;
     31   size_t             len  = 0;
     32   ASSERT_EQUALS(0, resp_encode_array(1, av, &buf, &len));
     33   ASSERT("encoded", buf != NULL && len > 0);
     34   resp_object *dec = round_trip(buf, len);
     35   ASSERT("decode non-NULL", dec != NULL);
     36   ASSERT_EQUALS(RESPT_ARRAY, dec->type);
     37   ASSERT_EQUALS(1, (int)dec->u.arr.n);
     38   ASSERT_EQUALS(RESPT_BULK, dec->u.arr.elem[0].type);
     39   ASSERT_STRING_EQUALS("hello", dec->u.arr.elem[0].u.s);
     40   resp_free(dec);
     41   free(buf);
     42   free(bulk.u.s);
     43 }
     44 
     45 void test_resp_encode_decode_int(void) {
     46   resp_object        iobj = {.type = RESPT_INT, .u = {.i = -42}};
     47   const resp_object *av[] = {&iobj};
     48   char              *buf  = NULL;
     49   size_t             len  = 0;
     50   ASSERT_EQUALS(0, resp_encode_array(1, av, &buf, &len));
     51   resp_object *dec = round_trip(buf, len);
     52   ASSERT("decode non-NULL", dec != NULL);
     53   ASSERT_EQUALS(RESPT_ARRAY, dec->type);
     54   ASSERT_EQUALS(1, (int)dec->u.arr.n);
     55   ASSERT_EQUALS(RESPT_INT, dec->u.arr.elem[0].type);
     56   ASSERT_EQUALS(-42, (int)dec->u.arr.elem[0].u.i);
     57   resp_free(dec);
     58   free(buf);
     59 }
     60 
     61 void test_resp_encode_decode_array_of_strings(void) {
     62   resp_object        k    = {.type = RESPT_BULK, .u = {.s = strdup("key")}};
     63   resp_object        v    = {.type = RESPT_BULK, .u = {.s = strdup("value")}};
     64   const resp_object *av[] = {&k, &v};
     65   char              *buf  = NULL;
     66   size_t             len  = 0;
     67   ASSERT_EQUALS(0, resp_encode_array(2, av, &buf, &len));
     68   resp_object *dec = round_trip(buf, len);
     69   ASSERT("decode non-NULL", dec != NULL);
     70   ASSERT_EQUALS(RESPT_ARRAY, dec->type);
     71   ASSERT_EQUALS(2, (int)dec->u.arr.n);
     72   ASSERT_EQUALS(RESPT_BULK, dec->u.arr.elem[0].type);
     73   ASSERT_EQUALS(RESPT_BULK, dec->u.arr.elem[1].type);
     74   ASSERT_STRING_EQUALS("key", dec->u.arr.elem[0].u.s);
     75   ASSERT_STRING_EQUALS("value", dec->u.arr.elem[1].u.s);
     76   resp_free(dec);
     77   free(buf);
     78   free(k.u.s);
     79   free(v.u.s);
     80 }
     81 
     82 void test_resp_map_get_string(void) {
     83   resp_object  k1  = {.type = RESPT_BULK, .u = {.s = strdup("a")}};
     84   resp_object  v1  = {.type = RESPT_BULK, .u = {.s = strdup("1")}};
     85   resp_object  k2  = {.type = RESPT_BULK, .u = {.s = strdup("b")}};
     86   resp_object  v2  = {.type = RESPT_BULK, .u = {.s = strdup("2")}};
     87   resp_object *map = calloc(1, sizeof(resp_object));
     88   ASSERT("map alloc", map != NULL);
     89   map->type          = RESPT_ARRAY;
     90   map->u.arr.n       = 4;
     91   map->u.arr.elem    = calloc(4, sizeof(resp_object));
     92   map->u.arr.elem[0] = k1;
     93   map->u.arr.elem[1] = v1;
     94   map->u.arr.elem[2] = k2;
     95   map->u.arr.elem[3] = v2;
     96   ASSERT_STRING_EQUALS("1", resp_map_get_string(map, "a"));
     97   ASSERT_STRING_EQUALS("2", resp_map_get_string(map, "b"));
     98   ASSERT("missing key returns NULL", resp_map_get_string(map, "c") == NULL);
     99   resp_free(map);
    100 }
    101 
    102 void test_resp_map_get_missing_key(void) {
    103   resp_object *map = resp_array_init();
    104   ASSERT("map alloc", map != NULL);
    105   ASSERT("missing key NULL", resp_map_get_string(map, "x") == NULL);
    106   ASSERT("resp_map_get NULL", resp_map_get(map, "x") == NULL);
    107   resp_free(map);
    108 }
    109 
    110 void test_resp_read_invalid_returns_null(void) {
    111   int fd[2];
    112   ASSERT_EQUALS(0, pipe(fd));
    113   if (write(fd[1], "X\r\n", 3) != 3) {
    114     close(fd[0]);
    115     close(fd[1]);
    116     return;
    117   }
    118   close(fd[1]);
    119   resp_object *o = resp_read(fd[0]);
    120   close(fd[0]);
    121   ASSERT("invalid type byte returns NULL", o == NULL);
    122 }
    123 
    124 int main(void) {
    125   RUN(test_resp_encode_decode_bulk);
    126   RUN(test_resp_encode_decode_int);
    127   RUN(test_resp_encode_decode_array_of_strings);
    128   RUN(test_resp_map_get_string);
    129   RUN(test_resp_map_get_missing_key);
    130   RUN(test_resp_read_invalid_returns_null);
    131   return TEST_REPORT();
    132 }