#include <gtest/gtest.h>

#include "tuple.h"

TEST(TUPLE, TUPLE2)
{
    char buf[128] = {0};
    struct tuple2 temp;
    struct tuple2 tuple_a;
    struct tuple2 tuple_b;
    struct tuple2 reversed_tuple_a;
    struct tuple2 reversed_tuple_b;

    memset(&temp, 0, sizeof(struct tuple2));
    memset(&tuple_a, 0, sizeof(struct tuple2));
    memset(&tuple_b, 0, sizeof(struct tuple2));
    memset(&reversed_tuple_a, 0, sizeof(struct tuple2));
    memset(&reversed_tuple_b, 0, sizeof(struct tuple2));

    tuple_a.addr_family = AF_INET;
    tuple_a.src_addr.v4.s_addr = inet_addr("192.168.1.2");
    tuple_a.dst_addr.v4.s_addr = inet_addr("192.168.1.3");

    tuple_b.addr_family = AF_INET6;
    inet_pton(AF_INET6, "2001:db8::ff00:42:8329", &tuple_b.src_addr.v6);
    inet_pton(AF_INET6, "2001:db8::ff00:42:832a", &tuple_b.dst_addr.v6);

    // to_str
    memset(buf, 0, sizeof(buf));
    tuple2_to_str(&tuple_a, buf, sizeof(buf));
    EXPECT_STREQ(buf, "192.168.1.2-192.168.1.3");
    memset(buf, 0, sizeof(buf));
    tuple2_to_str(&tuple_b, buf, sizeof(buf));
    EXPECT_STREQ(buf, "2001:db8::ff00:42:8329-2001:db8::ff00:42:832a");

    // reverse
    tuple2_reverse(&tuple_a, &reversed_tuple_a);
    tuple2_reverse(&tuple_b, &reversed_tuple_b);
    memset(buf, 0, sizeof(buf));
    tuple2_to_str(&reversed_tuple_a, buf, sizeof(buf));
    EXPECT_STREQ(buf, "192.168.1.3-192.168.1.2");
    memset(buf, 0, sizeof(buf));
    tuple2_to_str(&reversed_tuple_b, buf, sizeof(buf));
    EXPECT_STREQ(buf, "2001:db8::ff00:42:832a-2001:db8::ff00:42:8329");

    // hash
    EXPECT_TRUE(tuple2_hash(&tuple_a) == tuple2_hash(&reversed_tuple_a));
    EXPECT_TRUE(tuple2_hash(&tuple_b) == tuple2_hash(&reversed_tuple_b));

    // cmp
    EXPECT_TRUE(tuple2_cmp(&tuple_a, &tuple_a) == 0);
    EXPECT_TRUE(tuple2_cmp(&tuple_b, &tuple_b) == 0);

    EXPECT_TRUE(tuple2_cmp(&tuple_a, &reversed_tuple_a) != 0);
    EXPECT_TRUE(tuple2_cmp(&tuple_b, &reversed_tuple_b) != 0);

    tuple2_reverse(&reversed_tuple_a, &temp);
    EXPECT_TRUE(tuple2_cmp(&tuple_a, &temp) == 0);

    tuple2_reverse(&reversed_tuple_b, &temp);
    EXPECT_TRUE(tuple2_cmp(&tuple_b, &temp) == 0);
}

TEST(TUPLE, TUPLE4)
{
    char buf[128] = {0};
    struct tuple4 temp;
    struct tuple4 tuple_a;
    struct tuple4 tuple_b;
    struct tuple4 reversed_tuple_a;
    struct tuple4 reversed_tuple_b;

    memset(&temp, 0, sizeof(struct tuple4));
    memset(&tuple_a, 0, sizeof(struct tuple4));
    memset(&tuple_b, 0, sizeof(struct tuple4));
    memset(&reversed_tuple_a, 0, sizeof(struct tuple4));
    memset(&reversed_tuple_b, 0, sizeof(struct tuple4));

    tuple_a.addr_family = AF_INET;
    tuple_a.src_addr.v4.s_addr = inet_addr("192.168.1.2");
    tuple_a.dst_addr.v4.s_addr = inet_addr("192.168.1.3");
    tuple_a.src_port = htons(1234);
    tuple_a.dst_port = htons(5678);

    tuple_b.addr_family = AF_INET6;
    inet_pton(AF_INET6, "2001:db8::ff00:42:8329", &tuple_b.src_addr.v6);
    inet_pton(AF_INET6, "2001:db8::ff00:42:832a", &tuple_b.dst_addr.v6);
    tuple_b.src_port = htons(1234);
    tuple_b.dst_port = htons(5678);

    // to_str
    memset(buf, 0, sizeof(buf));
    tuple4_to_str(&tuple_a, buf, sizeof(buf));
    EXPECT_STREQ(buf, "192.168.1.2:1234-192.168.1.3:5678");
    memset(buf, 0, sizeof(buf));
    tuple4_to_str(&tuple_b, buf, sizeof(buf));
    EXPECT_STREQ(buf, "2001:db8::ff00:42:8329:1234-2001:db8::ff00:42:832a:5678");

    // reverse
    tuple4_reverse(&tuple_a, &reversed_tuple_a);
    tuple4_reverse(&tuple_b, &reversed_tuple_b);
    memset(buf, 0, sizeof(buf));
    tuple4_to_str(&reversed_tuple_a, buf, sizeof(buf));
    EXPECT_STREQ(buf, "192.168.1.3:5678-192.168.1.2:1234");
    memset(buf, 0, sizeof(buf));
    tuple4_to_str(&reversed_tuple_b, buf, sizeof(buf));
    EXPECT_STREQ(buf, "2001:db8::ff00:42:832a:5678-2001:db8::ff00:42:8329:1234");

    // hash
    EXPECT_TRUE(tuple4_hash(&tuple_a) == tuple4_hash(&reversed_tuple_a));
    EXPECT_TRUE(tuple4_hash(&tuple_b) == tuple4_hash(&reversed_tuple_b));

    // cmp
    EXPECT_TRUE(tuple4_cmp(&tuple_a, &tuple_a) == 0);
    EXPECT_TRUE(tuple4_cmp(&tuple_b, &tuple_b) == 0);

    EXPECT_TRUE(tuple4_cmp(&tuple_a, &reversed_tuple_a) != 0);
    EXPECT_TRUE(tuple4_cmp(&tuple_b, &reversed_tuple_b) != 0);

    tuple4_reverse(&reversed_tuple_a, &temp);
    EXPECT_TRUE(tuple4_cmp(&tuple_a, &temp) == 0);

    tuple4_reverse(&reversed_tuple_b, &temp);
    EXPECT_TRUE(tuple4_cmp(&tuple_b, &temp) == 0);
}

TEST(TUPLE, TUPLE5)
{
    char buf[128] = {0};
    struct tuple5 temp;
    struct tuple5 tuple_a;
    struct tuple5 tuple_b;
    struct tuple5 reversed_tuple_a;
    struct tuple5 reversed_tuple_b;

    memset(&temp, 0, sizeof(struct tuple5));
    memset(&tuple_a, 0, sizeof(struct tuple5));
    memset(&tuple_b, 0, sizeof(struct tuple5));
    memset(&reversed_tuple_a, 0, sizeof(struct tuple5));
    memset(&reversed_tuple_b, 0, sizeof(struct tuple5));

    tuple_a.addr_family = AF_INET;
    tuple_a.src_addr.v4.s_addr = inet_addr("192.168.1.2");
    tuple_a.dst_addr.v4.s_addr = inet_addr("192.168.1.3");
    tuple_a.src_port = htons(1234);
    tuple_a.dst_port = htons(5678);
    tuple_a.ip_proto = IPPROTO_TCP;

    tuple_b.addr_family = AF_INET6;
    inet_pton(AF_INET6, "2001:db8::ff00:42:8329", &tuple_b.src_addr.v6);
    inet_pton(AF_INET6, "2001:db8::ff00:42:832a", &tuple_b.dst_addr.v6);
    tuple_b.src_port = htons(1234);
    tuple_b.dst_port = htons(5678);
    tuple_b.ip_proto = IPPROTO_UDP;

    // to_str
    memset(buf, 0, sizeof(buf));
    tuple5_to_str(&tuple_a, buf, sizeof(buf));
    EXPECT_STREQ(buf, "192.168.1.2:1234-192.168.1.3:5678-6");
    memset(buf, 0, sizeof(buf));
    tuple5_to_str(&tuple_b, buf, sizeof(buf));
    EXPECT_STREQ(buf, "2001:db8::ff00:42:8329:1234-2001:db8::ff00:42:832a:5678-17");

    // reverse
    tuple5_reverse(&tuple_a, &reversed_tuple_a);
    tuple5_reverse(&tuple_b, &reversed_tuple_b);
    memset(buf, 0, sizeof(buf));
    tuple5_to_str(&reversed_tuple_a, buf, sizeof(buf));
    EXPECT_STREQ(buf, "192.168.1.3:5678-192.168.1.2:1234-6");
    memset(buf, 0, sizeof(buf));
    tuple5_to_str(&reversed_tuple_b, buf, sizeof(buf));
    EXPECT_STREQ(buf, "2001:db8::ff00:42:832a:5678-2001:db8::ff00:42:8329:1234-17");

    // hash
    EXPECT_TRUE(tuple5_hash(&tuple_a) == tuple5_hash(&reversed_tuple_a));
    EXPECT_TRUE(tuple5_hash(&tuple_b) == tuple5_hash(&reversed_tuple_b));

    // cmp
    EXPECT_TRUE(tuple5_cmp(&tuple_a, &tuple_a) == 0);
    EXPECT_TRUE(tuple5_cmp(&tuple_b, &tuple_b) == 0);

    EXPECT_TRUE(tuple5_cmp(&tuple_a, &reversed_tuple_a) != 0);
    EXPECT_TRUE(tuple5_cmp(&tuple_b, &reversed_tuple_b) != 0);

    tuple5_reverse(&reversed_tuple_a, &temp);
    EXPECT_TRUE(tuple5_cmp(&tuple_a, &temp) == 0);

    tuple5_reverse(&reversed_tuple_b, &temp);
    EXPECT_TRUE(tuple5_cmp(&tuple_b, &temp) == 0);
}

TEST(TUPLE, TUPLE6)
{
    char buf[128] = {0};
    struct tuple6 temp;
    struct tuple6 tuple_a;
    struct tuple6 tuple_b;
    struct tuple6 reversed_tuple_a;
    struct tuple6 reversed_tuple_b;

    memset(&temp, 0, sizeof(struct tuple6));
    memset(&tuple_a, 0, sizeof(struct tuple6));
    memset(&tuple_b, 0, sizeof(struct tuple6));
    memset(&reversed_tuple_a, 0, sizeof(struct tuple6));
    memset(&reversed_tuple_b, 0, sizeof(struct tuple6));

    tuple_a.addr_family = AF_INET;
    tuple_a.src_addr.v4.s_addr = inet_addr("192.168.1.2");
    tuple_a.dst_addr.v4.s_addr = inet_addr("192.168.1.3");
    tuple_a.src_port = htons(1234);
    tuple_a.dst_port = htons(5678);
    tuple_a.ip_proto = IPPROTO_TCP;
    tuple_a.domain = 0;

    tuple_b.addr_family = AF_INET6;
    inet_pton(AF_INET6, "2001:db8::ff00:42:8329", &tuple_b.src_addr.v6);
    inet_pton(AF_INET6, "2001:db8::ff00:42:832a", &tuple_b.dst_addr.v6);
    tuple_b.src_port = htons(1234);
    tuple_b.dst_port = htons(5678);
    tuple_b.ip_proto = IPPROTO_UDP;
    tuple_b.domain = 0;

    // to_str
    memset(buf, 0, sizeof(buf));
    tuple6_to_str(&tuple_a, buf, sizeof(buf));
    EXPECT_STREQ(buf, "192.168.1.2:1234-192.168.1.3:5678-6-0");
    memset(buf, 0, sizeof(buf));
    tuple6_to_str(&tuple_b, buf, sizeof(buf));
    EXPECT_STREQ(buf, "2001:db8::ff00:42:8329:1234-2001:db8::ff00:42:832a:5678-17-0");

    // reverse
    tuple6_reverse(&tuple_a, &reversed_tuple_a);
    tuple6_reverse(&tuple_b, &reversed_tuple_b);
    memset(buf, 0, sizeof(buf));
    tuple6_to_str(&reversed_tuple_a, buf, sizeof(buf));
    EXPECT_STREQ(buf, "192.168.1.3:5678-192.168.1.2:1234-6-0");
    memset(buf, 0, sizeof(buf));
    tuple6_to_str(&reversed_tuple_b, buf, sizeof(buf));
    EXPECT_STREQ(buf, "2001:db8::ff00:42:832a:5678-2001:db8::ff00:42:8329:1234-17-0");

    // hash
    EXPECT_TRUE(tuple6_hash(&tuple_a) == tuple6_hash(&reversed_tuple_a));
    EXPECT_TRUE(tuple6_hash(&tuple_b) == tuple6_hash(&reversed_tuple_b));

    // cmp
    EXPECT_TRUE(tuple6_cmp(&tuple_a, &tuple_a) == 0);
    EXPECT_TRUE(tuple6_cmp(&tuple_b, &tuple_b) == 0);

    EXPECT_TRUE(tuple6_cmp(&tuple_a, &reversed_tuple_a) != 0);
    EXPECT_TRUE(tuple6_cmp(&tuple_b, &reversed_tuple_b) != 0);

    tuple6_reverse(&reversed_tuple_a, &temp);
    EXPECT_TRUE(tuple6_cmp(&tuple_a, &temp) == 0);

    tuple6_reverse(&reversed_tuple_b, &temp);
    EXPECT_TRUE(tuple6_cmp(&tuple_b, &temp) == 0);
}

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