#include <gtest/gtest.h>

#include "session_private.h"
#include "session_timer.h"

TEST(SESSION_TIMER, EXPIRE)
{
    struct session *sess = NULL;
    struct session sess1;
    struct session sess2;
    struct session sess3;
    struct session_timer *timer = session_timer_new(100);
    EXPECT_TRUE(timer != NULL);

    session_init(&sess1);
    session_init(&sess2);
    session_init(&sess3);

    session_timer_add(timer, &sess1, 100 + 5);
    session_timer_add(timer, &sess2, 100 + 5);
    session_timer_add(timer, &sess3, 100 + 10);

    // not expire
    sess = session_timer_expire(timer, 100 + 4);
    EXPECT_TRUE(sess == NULL);
    // expire
    sess = session_timer_expire(timer, 100 + 5);
    EXPECT_TRUE(sess == &sess1);
    sess = session_timer_expire(timer, 100 + 5);
    EXPECT_TRUE(sess == &sess2);
    // not expire
    sess = session_timer_expire(timer, 100 + 5);
    EXPECT_TRUE(sess == NULL);
    sess = session_timer_expire(timer, 100 + 9);
    EXPECT_TRUE(sess == NULL);
    // expire
    sess = session_timer_expire(timer, 100 + 10);
    EXPECT_TRUE(sess == &sess3);
    // not expire
    sess = session_timer_expire(timer, 100 + 10);
    EXPECT_TRUE(sess == NULL);

    session_timer_free(timer);
}

TEST(SESSION_TIMER, BEFORE_EXPIRE_DEL)
{
    struct session *sess = NULL;
    struct session sess1;
    struct session sess2;
    struct session sess3;
    struct session_timer *timer = session_timer_new(1);
    EXPECT_TRUE(timer != NULL);

    session_init(&sess1);
    session_init(&sess2);
    session_init(&sess3);

    session_timer_add(timer, &sess1, 100 + 5);
    session_timer_add(timer, &sess2, 100 + 5);
    session_timer_add(timer, &sess3, 100 + 10);

    // not expire
    sess = session_timer_expire(timer, 100 + 4);
    EXPECT_TRUE(sess == NULL);
    // del sess1
    session_timer_del(timer, &sess1);
    // expire
    sess = session_timer_expire(timer, 100 + 5);
    EXPECT_TRUE(sess == &sess2);
    sess = session_timer_expire(timer, 100 + 5);
    EXPECT_TRUE(sess == NULL);
    // expire
    sess = session_timer_expire(timer, 100 + 10);
    EXPECT_TRUE(sess == &sess3);
    // not expire
    sess = session_timer_expire(timer, 100 + 10);
    EXPECT_TRUE(sess == NULL);

    session_timer_free(timer);
}

TEST(SESSION_TIMER, AFTER_EXPIRE_DEL)
{
    struct session *sess = NULL;
    struct session sess1;
    struct session sess2;
    struct session sess3;
    struct session_timer *timer = session_timer_new(1);
    EXPECT_TRUE(timer != NULL);

    session_init(&sess1);
    session_init(&sess2);
    session_init(&sess3);

    session_timer_add(timer, &sess1, 100 + 5);
    session_timer_add(timer, &sess2, 100 + 5);
    session_timer_add(timer, &sess3, 100 + 10);

    // expire
    sess = session_timer_expire(timer, 100 + 5);
    EXPECT_TRUE(sess == &sess1);
    // del sess2
    session_timer_del(timer, &sess2);
    // not expire
    sess = session_timer_expire(timer, 100 + 5);
    EXPECT_TRUE(sess == NULL);
    // expire
    sess = session_timer_expire(timer, 100 + 10);
    EXPECT_TRUE(sess == &sess3);

    session_timer_free(timer);
}

TEST(SESSION_TIMER, BEFORE_EXPIRE_UPDATE)
{
    struct session *sess = NULL;
    struct session sess1;
    struct session sess2;
    struct session_timer *timer = session_timer_new(100);
    EXPECT_TRUE(timer != NULL);

    session_init(&sess1);
    session_init(&sess2);

    session_timer_add(timer, &sess1, 100 + 5);
    session_timer_add(timer, &sess2, 100 + 10);

    // not expire
    sess = session_timer_expire(timer, 100 + 4);
    EXPECT_TRUE(sess == NULL);
    // expire
    sess = session_timer_expire(timer, 100 + 5);
    EXPECT_TRUE(sess == &sess1);
    // not expire
    sess = session_timer_expire(timer, 100 + 5);
    EXPECT_TRUE(sess == NULL);
    // update sess2
    session_timer_update(timer, &sess2, 100 + 20);
    // not expire
    sess = session_timer_expire(timer, 100 + 19);
    EXPECT_TRUE(sess == NULL);
    // expire
    sess = session_timer_expire(timer, 100 + 20);
    EXPECT_TRUE(sess == &sess2);

    session_timer_free(timer);
}

TEST(SESSION_TIMER, NEXT_EXPIRE_INTERVAL)
{
    struct session sess1;
    struct session sess2;
    struct session_timer *timer = session_timer_new(100);
    EXPECT_TRUE(timer != NULL);

    session_init(&sess1);
    session_init(&sess2);

    EXPECT_TRUE(session_timer_next_expire_interval(timer) == UINT64_MAX);

    session_timer_add(timer, &sess1, 1000);
    session_timer_add(timer, &sess2, 1000);
    EXPECT_TRUE(session_timer_next_expire_interval(timer) < UINT64_MAX);

    EXPECT_TRUE(session_timer_expire(timer, 900) == NULL);
    EXPECT_TRUE(session_timer_next_expire_interval(timer) <= 1000 - 900);

    EXPECT_TRUE(session_timer_expire(timer, 950) == NULL);
    EXPECT_TRUE(session_timer_next_expire_interval(timer) <= 1000 - 950);

    EXPECT_TRUE(session_timer_expire(timer, 980) == NULL);
    EXPECT_TRUE(session_timer_next_expire_interval(timer) <= 1000 - 980);

    EXPECT_TRUE(session_timer_expire(timer, 990) == NULL);
    EXPECT_TRUE(session_timer_next_expire_interval(timer) <= 1000 - 990);

    EXPECT_TRUE(session_timer_expire(timer, 1010));
    EXPECT_TRUE(session_timer_next_expire_interval(timer) == 0);

    EXPECT_TRUE(session_timer_expire(timer, 1010));
    EXPECT_TRUE(session_timer_next_expire_interval(timer) == UINT64_MAX);

    session_timer_free(timer);
}

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