#include <gtest/gtest.h>

#include "session_priv.h"

#define SESSION_KEY_IPV4_TCP(name)                        \
    struct tuple6 name;                                   \
    memset(&name, 0, sizeof(struct tuple6));              \
    (name).ip_type = IP_TYPE_V4;                          \
    (name).src_addr.v4.s_addr = inet_addr("192.168.1.2"); \
    (name).dst_addr.v4.s_addr = inet_addr("192.168.1.3"); \
    (name).src_port = htons(1234);                        \
    (name).dst_port = htons(5678);                        \
    (name).ip_proto = IPPROTO_TCP;                        \
    (name).domain = 0;

#define SESSION_KEY_IPV6_UDP(name)                                           \
    struct tuple6 name;                                                      \
    memset(&name, 0, sizeof(struct tuple6));                                 \
    (name).ip_type = IP_TYPE_V6;                                             \
    inet_pton(AF_INET6, "2001:db8:0:0:0:ff00:42:8329", &(name).src_addr.v6); \
    inet_pton(AF_INET6, "2001:db8:0:0:0:ff00:42:832a", &(name).dst_addr.v6); \
    (name).src_port = htons(1234);                                           \
    (name).dst_port = htons(5678);                                           \
    (name).ip_proto = IPPROTO_UDP;                                           \
    (name).domain = 0;

#define SESSION_KEY_IPV6_TCP(name)                                           \
    struct tuple6 name;                                                      \
    memset(&name, 0, sizeof(struct tuple6));                                 \
    (name).ip_type = IP_TYPE_V6;                                             \
    inet_pton(AF_INET6, "2001:db8:0:0:0:ff00:42:8329", &(name).src_addr.v6); \
    inet_pton(AF_INET6, "2001:db8:0:0:0:ff00:42:832a", &(name).dst_addr.v6); \
    (name).src_port = htons(1234);                                           \
    (name).dst_port = htons(5678);                                           \
    (name).ip_proto = IPPROTO_TCP;                                           \
    (name).domain = 0;

void free_ex_data(struct session *sess, uint8_t idx, void *ex_ptr, void *arg)
{
    if (ex_ptr)
    {
        printf("free_ex_data: %s\n", (char *)ex_ptr);
        free(ex_ptr);
        ex_ptr = NULL;
    }
}

TEST(SESSION, EX_NEW_INDEX)
{
    uint8_t idx1 = session_get_ex_new_index("key1", NULL, NULL);
    uint8_t idx2 = session_get_ex_new_index("key2", NULL, NULL);
    uint8_t idx3 = session_get_ex_new_index("key1", NULL, NULL);
    EXPECT_TRUE(idx1 != idx2);
    EXPECT_TRUE(idx1 == idx3);
}

TEST(SESSION, EX_SET_GET)
{
    struct session sess;
    memset(&sess, 0, sizeof(sess));
    uint8_t idx = session_get_ex_new_index("ex_set_get", NULL, NULL);
    session_set_ex_data(&sess, idx, (void *)0x1234);
    EXPECT_TRUE(session_get0_ex_data(&sess, idx) == (void *)0x1234);
}

TEST(SESSION, EX_FREE_BY_RESET)
{
    struct session sess;
    memset(&sess, 0, sizeof(sess));
    uint8_t idx = session_get_ex_new_index("ex_free_by_reset", free_ex_data, NULL);
    char *ptr = strdup("hello");
    session_set_ex_data(&sess, idx, ptr);
    session_set_ex_data(&sess, idx, NULL);
}

TEST(SESSION, EX_FREE_BY_CB)
{
    struct session sess;
    memset(&sess, 0, sizeof(sess));
    uint8_t idx = session_get_ex_new_index("ex_free_by_cb", free_ex_data, NULL);
    char *ptr = strdup("hello");
    session_set_ex_data(&sess, idx, ptr);
    session_free_ex_data(&sess, idx);
}

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
