/*
 * SPDX-FileCopyrightText: 2024-2026 Sébastien Helleu <flashcode@flashtux.org>
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

/* Test event functions for relay remote */

#include "CppUTest/TestHarness.h"

#include "tests.h"

extern "C"
{
#include <limits.h>
#include <cjson/cJSON.h>
#include "src/core/core-config-file.h"
#include "src/core/core-string.h"
#include "src/gui/gui-buffer.h"
#include "src/gui/gui-hotlist.h"
#include "src/gui/gui-key.h"
#include "src/gui/gui-line.h"
#include "src/plugins/relay/relay.h"
#include "src/plugins/relay/relay-remote.h"
#include "src/plugins/relay/api/remote/relay-remote-event.h"

extern int relay_remote_event_line_is_already_read (struct t_gui_buffer *ptr_buffer,
                                                    long long line_id);
extern struct t_gui_buffer *relay_remote_event_search_buffer (struct t_relay_remote *remote,
                                                              long long id);
extern char **relay_remote_build_string_tags (cJSON *json_tags,
                                              struct t_gui_buffer *buffer,
                                              long long line_id, int highlight);
extern struct t_gui_line *relay_remote_event_search_line_by_id (struct t_gui_buffer *buffer,
                                                                long long id);
}

#define WEE_CHECK_TAGS(__result, __json_tags, __buffer, __line_id,      \
                       __highlight)                                     \
    json_tags = (__json_tags) ? cJSON_Parse (__json_tags) : NULL;       \
    tags = relay_remote_build_string_tags (json_tags, __buffer,         \
                                           __line_id, __highlight);     \
    CHECK(tags);                                                        \
    STRCMP_EQUAL(__result, *tags);                                      \
    string_dyn_free (tags, 1);                                          \
    cJSON_Delete (json_tags);

TEST_GROUP(RelayRemoteEvent)
{
};

/*
 * Test functions:
 *   relay_remote_event_line_is_already_read
 */

TEST(RelayRemoteEvent, LineIsAlreadyRead)
{
    struct t_gui_buffer *buffer;

    buffer = gui_buffer_new_user ("test_line_already_read",
                                  GUI_BUFFER_TYPE_FORMATTED);
    CHECK(buffer);

    /* Invalid arguments */
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (NULL, -1));
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (NULL, 123));
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, -1));

    /* Local variables not set on buffer */
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, 0));
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, 123));

    /* Only "last_read_line_id" set on buffer */
    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_last_read_line_id", "123");
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, 123));

    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_first_line_not_read", "0");

    /* Invalid local variable */
    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_last_read_line_id", "");
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, 123));
    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_last_read_line_id", "abc");
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, 123));
    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_last_read_line_id", "123abc");
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, 123));

    /* Read marker before the first line: nothing read on the remote. */
    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_last_read_line_id", "-1");
    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_first_line_not_read", "1");
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, 0));
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, 123));
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, INT_MAX));

    /* No read marker: all the lines have been read on the remote. */
    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_first_line_not_read", "0");
    LONGS_EQUAL(1, relay_remote_event_line_is_already_read (buffer, 0));
    LONGS_EQUAL(1, relay_remote_event_line_is_already_read (buffer, 123));
    LONGS_EQUAL(1, relay_remote_event_line_is_already_read (buffer, INT_MAX));

    /* Lines up to id 123 read on the remote. */
    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_last_read_line_id", "123");
    LONGS_EQUAL(1, relay_remote_event_line_is_already_read (buffer, 0));
    LONGS_EQUAL(1, relay_remote_event_line_is_already_read (buffer, 122));
    LONGS_EQUAL(1, relay_remote_event_line_is_already_read (buffer, 123));
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, 124));
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, INT_MAX));

    gui_buffer_close (buffer);

    /*
     * Buffer with free content: the identifier of a line is its number ("y"),
     * so a line is never considered as read.
     */
    buffer = gui_buffer_new_user ("test_line_is_already_read_free",
                                  GUI_BUFFER_TYPE_FREE);
    CHECK(buffer);

    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_last_read_line_id", "123");
    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_first_line_not_read", "0");
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, 0));
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, 122));
    LONGS_EQUAL(0, relay_remote_event_line_is_already_read (buffer, 123));

    gui_buffer_close (buffer);
}

/*
 * Test functions:
 *   relay_remote_event_search_buffer
 */

TEST(RelayRemoteEvent, SearchBuffer)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_get_buffer_id
 */

TEST(RelayRemoteEvent, GetBufferId)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_build_string_tags
 */

TEST(RelayRemoteEvent, BuildStringTags)
{
    struct t_gui_buffer *buffer;
    cJSON *json_tags;
    char **tags;

    buffer = gui_buffer_new_user ("test_build_string_tags",
                                  GUI_BUFFER_TYPE_FORMATTED);
    CHECK(buffer);

    /* No buffer: the line can not be read on the remote. */
    WEE_CHECK_TAGS("relay_remote_line_id_42", NULL, NULL, 42, 0);
    WEE_CHECK_TAGS("relay_remote_line_id_42", "[]", NULL, 42, 0);
    WEE_CHECK_TAGS("relay_remote_line_id_42", "{}", NULL, 42, 0);
    WEE_CHECK_TAGS("irc_privmsg,relay_remote_line_id_42",
                   "[\"irc_privmsg\", 123, null]", NULL, 42, 0);
    WEE_CHECK_TAGS("irc_privmsg,nick_alice,relay_remote_line_id_42",
                   "[\"irc_privmsg\", \"nick_alice\"]", NULL, 42, 0);
    WEE_CHECK_TAGS("irc_privmsg,notify_message,relay_remote_line_id_42",
                   "[\"irc_privmsg\", \"notify_message\"]", NULL, 42, 0);

    /* Highlight: any "notify_xxx" tag is replaced by "notify_highlight". */
    WEE_CHECK_TAGS("irc_privmsg,notify_highlight,relay_remote_line_id_42",
                   "[\"irc_privmsg\", \"notify_message\"]", NULL, 42, 1);

    /* Highlight without any "notify_xxx" tag: the tag is added. */
    WEE_CHECK_TAGS("irc_privmsg,notify_highlight,relay_remote_line_id_42",
                   "[\"irc_privmsg\"]", NULL, 42, 1);

    /* Buffer without the local variable: the line is not read. */
    WEE_CHECK_TAGS("irc_privmsg,notify_message,relay_remote_line_id_42",
                   "[\"irc_privmsg\", \"notify_message\"]", buffer, 42, 0);

    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_last_read_line_id", "100");
    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_first_line_not_read", "0");

    /* Line not read yet on the remote (id greater than last read line id). */
    WEE_CHECK_TAGS("irc_privmsg,notify_message,relay_remote_line_id_101",
                   "[\"irc_privmsg\", \"notify_message\"]", buffer, 101, 0);
    WEE_CHECK_TAGS("irc_privmsg,notify_highlight,relay_remote_line_id_101",
                   "[\"irc_privmsg\", \"notify_message\"]", buffer, 101, 1);

    /* Negative line id: the line can not be read on the remote. */
    WEE_CHECK_TAGS("irc_privmsg,notify_message,relay_remote_line_id_-1",
                   "[\"irc_privmsg\", \"notify_message\"]", buffer, -1, 0);

    /*
     * Line already read on the remote: any "notify_xxx" tag is removed and
     * the tag "notify_none" is added.
     */
    WEE_CHECK_TAGS("notify_none,relay_remote_line_id_42", NULL, buffer, 42, 0);
    WEE_CHECK_TAGS("notify_none,relay_remote_line_id_42", "[]", buffer, 42, 0);
    WEE_CHECK_TAGS("notify_none,relay_remote_line_id_42",
                   "[\"notify_message\"]", buffer, 42, 0);
    WEE_CHECK_TAGS("irc_privmsg,notify_none,relay_remote_line_id_42",
                   "[\"irc_privmsg\"]", buffer, 42, 0);
    WEE_CHECK_TAGS("irc_privmsg,notify_none,relay_remote_line_id_100",
                   "[\"irc_privmsg\", \"notify_message\"]", buffer, 100, 0);

    /* The tag "notify_highlight" is not added when the line is already read. */
    WEE_CHECK_TAGS("irc_privmsg,notify_none,relay_remote_line_id_42",
                   "[\"irc_privmsg\", \"notify_message\"]", buffer, 42, 1);
    WEE_CHECK_TAGS("irc_privmsg,notify_none,relay_remote_line_id_42",
                   "[\"irc_privmsg\"]", buffer, 42, 1);

    /*
     * Non-regression tests: no empty tag must be left when a "notify_xxx" tag
     * is removed, wherever it is in the list of tags.
     */
    WEE_CHECK_TAGS("irc_privmsg,nick_alice,notify_none,"
                   "relay_remote_line_id_42",
                   "[\"notify_message\", \"irc_privmsg\", \"nick_alice\"]",
                   buffer, 42, 0);
    WEE_CHECK_TAGS("irc_privmsg,nick_alice,notify_none,"
                   "relay_remote_line_id_42",
                   "[\"irc_privmsg\", \"notify_message\", \"nick_alice\"]",
                   buffer, 42, 0);
    WEE_CHECK_TAGS("irc_privmsg,nick_alice,notify_none,"
                   "relay_remote_line_id_42",
                   "[\"irc_privmsg\", \"nick_alice\", \"notify_message\"]",
                   buffer, 42, 0);
    WEE_CHECK_TAGS("irc_privmsg,notify_none,relay_remote_line_id_42",
                   "[\"notify_message\", \"irc_privmsg\", \"notify_private\"]",
                   buffer, 42, 0);

    /*
     * No read marker on the remote and it is not before the first line: all
     * the lines have been read.
     */
    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_last_read_line_id", "-1");
    WEE_CHECK_TAGS("irc_privmsg,notify_none,relay_remote_line_id_42",
                   "[\"irc_privmsg\", \"notify_message\"]", buffer, 42, 0);

    /* Read marker before the first line on the remote: nothing has been read. */
    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_first_line_not_read", "1");
    WEE_CHECK_TAGS("irc_privmsg,notify_message,relay_remote_line_id_42",
                   "[\"irc_privmsg\", \"notify_message\"]", buffer, 42, 0);

    gui_buffer_close (buffer);

    /*
     * Buffer with free content: the identifier of a line is its number ("y"),
     * so the tags are never changed, even with a local variable set.
     */
    buffer = gui_buffer_new_user ("test_build_string_tags_free",
                                  GUI_BUFFER_TYPE_FREE);
    CHECK(buffer);
    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_last_read_line_id", "100");
    gui_buffer_set (buffer,
                    "localvar_set_relay_remote_first_line_not_read", "0");

    WEE_CHECK_TAGS("irc_privmsg,notify_message,relay_remote_line_id_42",
                   "[\"irc_privmsg\", \"notify_message\"]", buffer, 42, 0);
    WEE_CHECK_TAGS("irc_privmsg,notify_highlight,relay_remote_line_id_42",
                   "[\"irc_privmsg\", \"notify_message\"]", buffer, 42, 1);

    gui_buffer_close (buffer);
}

/*
 * Test functions:
 *   relay_remote_event_line_add
 */

TEST(RelayRemoteEvent, LineAdd)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_search_line_by_id
 */

TEST(RelayRemoteEvent, SearchLineById)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_line_update
 */

TEST(RelayRemoteEvent, LineUpdate)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_cb_line
 */

TEST(RelayRemoteEvent, CbLine)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_handle_nick
 */

TEST(RelayRemoteEvent, HandleNick)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_handle_nick_group
 */

TEST(RelayRemoteEvent, HandleNickGroup)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_cb_nick_group
 */

TEST(RelayRemoteEvent, CbNickGroup)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_cb_nick
 */

TEST(RelayRemoteEvent, CbNick)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_apply_props
 */

TEST(RelayRemoteEvent, ApplyProps)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_buffer_input_cb
 */

TEST(RelayRemoteEvent, BufferInputCb)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_check_local_var
 */

TEST(RelayRemoteEvent, CheckLocalVar)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_remove_localvar_cb
 */

TEST(RelayRemoteEvent, RemoveLocalVarCb)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_initial_sync_buffers
 */

TEST(RelayRemoteEvent, InitialSyncBuffers)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_cb_buffer
 */

TEST(RelayRemoteEvent, CbBuffer)
{
    struct t_relay_remote *remote;
    struct t_gui_buffer *buffer;

    remote = relay_remote_new ("testcbbuffer",
                               "https://localhost:9000",
                               NULL, NULL, NULL, NULL, NULL, NULL);
    CHECK(remote);

    /* The buffer is created with the properties received from the remote. */
    relay_remote_event_recv (
        remote,
        "{\"code\": 200, "
        "\"body_type\": \"buffer\", "
        "\"body\": {\"id\": 123, \"name\": \"irc.libera.#test\", "
        "\"short_name\": \"#test\", "
        "\"number\": 4, "
        "\"type\": \"formatted\", "
        "\"hidden\": false, "
        "\"title\": \"the title\", "
        "\"modes\": \"+nt\", "
        "\"input_prompt\": \"alice\", "
        "\"nicklist\": true, "
        "\"nicklist_case_sensitive\": false, "
        "\"nicklist_display_groups\": true, "
        "\"time_displayed\": true, "
        "\"prefix_displayed\": true, "
        "\"last_read_line_id\": 5, "
        "\"first_line_not_read\": false, "
        "\"local_variables\": {\"plugin\": \"irc\", "
        "\"name\": \"libera.#test\", \"channel\": \"#test\"}, "
        "\"keys\": [{\"key\": \"meta-A\", \"command\": \"/test\"}]}}");

    buffer = relay_remote_event_search_buffer (remote, 123);
    CHECK(buffer);
    STRCMP_EQUAL("remote.testcbbuffer.irc.libera.#test",
                 gui_buffer_get_string (buffer, "name"));
    STRCMP_EQUAL("#test", gui_buffer_get_string (buffer, "short_name"));
    STRCMP_EQUAL("the title", gui_buffer_get_string (buffer, "title"));
    STRCMP_EQUAL("+nt", gui_buffer_get_string (buffer, "modes"));
    STRCMP_EQUAL("alice", gui_buffer_get_string (buffer, "input_prompt"));
    LONGS_EQUAL(GUI_BUFFER_TYPE_FORMATTED, buffer->type);
    LONGS_EQUAL(0, gui_buffer_get_integer (buffer, "hidden"));
    LONGS_EQUAL(1, gui_buffer_get_integer (buffer, "nicklist"));
    LONGS_EQUAL(0, gui_buffer_get_integer (buffer, "nicklist_case_sensitive"));
    LONGS_EQUAL(1, gui_buffer_get_integer (buffer, "nicklist_display_groups"));
    LONGS_EQUAL(1, gui_buffer_get_integer (buffer, "time_for_each_line"));
    LONGS_EQUAL(1, gui_buffer_get_integer (buffer, "prefix_for_each_line"));

    /* Extra local variables set for the remote. */
    STRCMP_EQUAL("testcbbuffer",
                 gui_buffer_get_string (buffer, "localvar_relay_remote"));
    STRCMP_EQUAL("123",
                 gui_buffer_get_string (buffer, "localvar_relay_remote_id"));
    STRCMP_EQUAL("4",
                 gui_buffer_get_string (buffer,
                                        "localvar_relay_remote_number"));
    STRCMP_EQUAL("5",
                 gui_buffer_get_string (
                     buffer, "localvar_relay_remote_last_read_line_id"));
    STRCMP_EQUAL("0",
                 gui_buffer_get_string (
                     buffer, "localvar_relay_remote_first_line_not_read"));

    /*
     * The local variables received are set in the buffer, except the reserved
     * ones ("plugin" and "name"), which keep their local value.
     */
    STRCMP_EQUAL("#test", gui_buffer_get_string (buffer, "localvar_channel"));
    STRCMP_EQUAL("relay", gui_buffer_get_string (buffer, "localvar_plugin"));
    STRCMP_EQUAL("remote.testcbbuffer.irc.libera.#test",
                 gui_buffer_get_string (buffer, "localvar_name"));

    /* The keys received are added in the buffer. */
    LONGS_EQUAL(1, buffer->keys_count);
    CHECK(buffer->keys);
    STRCMP_EQUAL("meta-A", buffer->keys->key);
    STRCMP_EQUAL("/test", buffer->keys->command);

    /* The same buffer is updated with the new properties received. */
    relay_remote_event_recv (
        remote,
        "{\"code\": 200, "
        "\"body_type\": \"buffer\", "
        "\"body\": {\"id\": 123, \"name\": \"irc.libera.#test\", "
        "\"short_name\": \"#test2\", "
        "\"title\": \"new title\", "
        "\"time_displayed\": false, "
        "\"prefix_displayed\": false}}");

    POINTERS_EQUAL(buffer, relay_remote_event_search_buffer (remote, 123));
    STRCMP_EQUAL("#test2", gui_buffer_get_string (buffer, "short_name"));
    STRCMP_EQUAL("new title", gui_buffer_get_string (buffer, "title"));
    LONGS_EQUAL(0, gui_buffer_get_integer (buffer, "time_for_each_line"));
    LONGS_EQUAL(0, gui_buffer_get_integer (buffer, "prefix_for_each_line"));

    /*
     * The time and the prefix are displayed when the fields "time_displayed"
     * and "prefix_displayed" are not received from the remote.
     */
    relay_remote_event_recv (
        remote,
        "{\"code\": 200, "
        "\"body_type\": \"buffer\", "
        "\"body\": {\"id\": 123, \"name\": \"irc.libera.#test\"}}");

    LONGS_EQUAL(1, gui_buffer_get_integer (buffer, "time_for_each_line"));
    LONGS_EQUAL(1, gui_buffer_get_integer (buffer, "prefix_for_each_line"));

    gui_buffer_close (buffer);

    /* Buffer created without the fields "time_displayed"/"prefix_displayed". */
    relay_remote_event_recv (
        remote,
        "{\"code\": 200, "
        "\"body_type\": \"buffer\", "
        "\"body\": {\"id\": 456, \"name\": \"irc.libera.#test2\", "
        "\"type\": \"formatted\"}}");

    buffer = relay_remote_event_search_buffer (remote, 456);
    CHECK(buffer);
    LONGS_EQUAL(1, gui_buffer_get_integer (buffer, "time_for_each_line"));
    LONGS_EQUAL(1, gui_buffer_get_integer (buffer, "prefix_for_each_line"));

    gui_buffer_close (buffer);

    /*
     * Buffer with free content created without the fields "time_displayed"
     * and "prefix_displayed": neither the time nor the prefix are displayed.
     */
    relay_remote_event_recv (
        remote,
        "{\"code\": 200, "
        "\"body_type\": \"buffer\", "
        "\"body\": {\"id\": 789, \"name\": \"core.free\", "
        "\"type\": \"free\"}}");

    buffer = relay_remote_event_search_buffer (remote, 789);
    CHECK(buffer);
    LONGS_EQUAL(GUI_BUFFER_TYPE_FREE, buffer->type);
    LONGS_EQUAL(0, gui_buffer_get_integer (buffer, "time_for_each_line"));
    LONGS_EQUAL(0, gui_buffer_get_integer (buffer, "prefix_for_each_line"));

    gui_buffer_close (buffer);
    relay_remote_free (remote);
}

/*
 * Test functions:
 *   relay_remote_event_cb_buffer_cleared
 */

TEST(RelayRemoteEvent, CbBufferCleared)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_cb_buffer_closed
 */

TEST(RelayRemoteEvent, CbBufferClosed)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_cb_vinput
 */

TEST(RelayRemoteEvent, CbInput)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_clear_buffers
 */

TEST(RelayRemoteEvent, ClearBuffers)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_sync_with_remote
 */

TEST(RelayRemoteEvent, SyncWithRemote)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_cb_version
 */

TEST(RelayRemoteEvent, CbVersion)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_cb_upgrade
 */

TEST(RelayRemoteEvent, CbUpgrade)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_cb_quit
 */

TEST(RelayRemoteEvent, CbQuit)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_recv
 */

TEST(RelayRemoteEvent, Recv)
{
    /* TODO: write tests */
}

/*
 * Test functions:
 *   relay_remote_event_recv
 *
 * Non-regression test: an event received with an array as body calls the
 * callback once per array item, and the callback for event "buffer_closed"
 * closes the buffer, so the buffer must be searched again before each call
 * (otherwise the pointer is used after the buffer has been freed).
 */

TEST(RelayRemoteEvent, RecvBufferClosedArray)
{
    struct t_relay_remote *remote;

    remote = relay_remote_new ("testbufclosed",
                               "https://localhost:9000",
                               NULL, NULL, NULL, NULL, NULL, NULL);
    CHECK(remote);

    relay_remote_event_recv (
        remote,
        "{\"code\": 200, "
        "\"body_type\": \"buffer\", "
        "\"body\": {\"id\": 123, \"name\": \"core.weechat\"}}");
    CHECK(relay_remote_event_search_buffer (remote, 123));

    relay_remote_event_recv (
        remote,
        "{\"event_name\": \"buffer_closed\", "
        "\"buffer_id\": 123, "
        "\"body_type\": \"buffer\", "
        "\"body\": [{}, {}]}");
    POINTERS_EQUAL(NULL, relay_remote_event_search_buffer (remote, 123));

    relay_remote_free (remote);
}

/*
 * Test functions:
 *   relay_remote_event_cb_buffer
 *   relay_remote_event_cb_line
 *   relay_remote_event_line_add
 *   relay_remote_event_recv
 *
 * Test that lines already read on the remote are received with the tag
 * "notify_none" and therefore have no notify level.
 */

TEST(RelayRemoteEvent, RecvBufferLinesAlreadyRead)
{
    struct t_relay_remote *remote;
    struct t_gui_buffer *buffer;
    struct t_gui_line *line;

    remote = relay_remote_new ("testlinesread",
                               "https://localhost:9000",
                               NULL, NULL, NULL, NULL, NULL, NULL);
    CHECK(remote);

    relay_remote_event_recv (
        remote,
        "{\"code\": 200, "
        "\"body_type\": \"buffer\", "
        "\"body\": {\"id\": 123, \"name\": \"irc.libera.#test\", "
        "\"last_read_line_id\": 5, "
        "\"lines\": ["
        "{\"id\": 4, \"message\": \"line read\", "
        "\"tags\": [\"irc_privmsg\", \"notify_message\"]}, "
        "{\"id\": 5, \"message\": \"line read\", "
        "\"tags\": [\"irc_privmsg\", \"notify_message\"]}, "
        "{\"id\": 6, \"message\": \"line not read\", "
        "\"tags\": [\"irc_privmsg\", \"notify_message\"]}]}}");

    buffer = relay_remote_event_search_buffer (remote, 123);
    CHECK(buffer);
    STRCMP_EQUAL(
        "5",
        gui_buffer_get_string (buffer,
                               "localvar_relay_remote_last_read_line_id"));

    /* Lines 4 and 5 have been read on the remote. */
    line = relay_remote_event_search_line_by_id (buffer, 4);
    CHECK(line);
    LONGS_EQUAL(3, line->data->tags_count);
    STRCMP_EQUAL("irc_privmsg", line->data->tags_array[0]);
    STRCMP_EQUAL("notify_none", line->data->tags_array[1]);
    STRCMP_EQUAL("relay_remote_line_id_4", line->data->tags_array[2]);
    LONGS_EQUAL(-1, line->data->notify_level);
    line = relay_remote_event_search_line_by_id (buffer, 5);
    CHECK(line);
    LONGS_EQUAL(-1, line->data->notify_level);

    /* Line 6 has not been read on the remote. */
    line = relay_remote_event_search_line_by_id (buffer, 6);
    CHECK(line);
    LONGS_EQUAL(3, line->data->tags_count);
    STRCMP_EQUAL("irc_privmsg", line->data->tags_array[0]);
    STRCMP_EQUAL("notify_message", line->data->tags_array[1]);
    STRCMP_EQUAL("relay_remote_line_id_6", line->data->tags_array[2]);
    LONGS_EQUAL(GUI_HOTLIST_MESSAGE, line->data->notify_level);

    gui_buffer_close (buffer);
    relay_remote_free (remote);
}

/*
 * Test functions:
 *   relay_remote_event_cb_buffer
 *   relay_remote_event_cb_line
 *   relay_remote_event_line_add
 *   relay_remote_event_recv
 *
 * Test that all the lines of a buffer without read marker are received with the
 * tag "notify_none", unless the marker is before the first line: the remote
 * sends "last_read_line_id" == -1 in both cases, so the field
 * "first_line_not_read" is used to distinguish them.
 */

TEST(RelayRemoteEvent, RecvBufferNoReadMarker)
{
    struct t_relay_remote *remote;
    struct t_gui_buffer *buffer;
    struct t_gui_line *line;

    /* No read marker: all the lines have been read on the remote. */
    remote = relay_remote_new ("testnomarker",
                               "https://localhost:9000",
                               NULL, NULL, NULL, NULL, NULL, NULL);
    CHECK(remote);

    relay_remote_event_recv (
        remote,
        "{\"code\": 200, "
        "\"body_type\": \"buffer\", "
        "\"body\": {\"id\": 123, \"name\": \"irc.libera.#test\", "
        "\"last_read_line_id\": -1, "
        "\"first_line_not_read\": false, "
        "\"lines\": ["
        "{\"id\": 4, \"message\": \"line read\", "
        "\"tags\": [\"irc_privmsg\", \"notify_message\"]}]}}");

    buffer = relay_remote_event_search_buffer (remote, 123);
    CHECK(buffer);
    STRCMP_EQUAL(
        "0",
        gui_buffer_get_string (buffer,
                               "localvar_relay_remote_first_line_not_read"));

    line = relay_remote_event_search_line_by_id (buffer, 4);
    CHECK(line);
    LONGS_EQUAL(3, line->data->tags_count);
    STRCMP_EQUAL("irc_privmsg", line->data->tags_array[0]);
    STRCMP_EQUAL("notify_none", line->data->tags_array[1]);
    STRCMP_EQUAL("relay_remote_line_id_4", line->data->tags_array[2]);
    LONGS_EQUAL(-1, line->data->notify_level);

    gui_buffer_close (buffer);
    relay_remote_free (remote);

    /* Read marker before the first line: nothing has been read on the remote. */
    remote = relay_remote_new ("testfirstnotread",
                               "https://localhost:9000",
                               NULL, NULL, NULL, NULL, NULL, NULL);
    CHECK(remote);

    relay_remote_event_recv (
        remote,
        "{\"code\": 200, "
        "\"body_type\": \"buffer\", "
        "\"body\": {\"id\": 456, \"name\": \"irc.libera.#test2\", "
        "\"last_read_line_id\": -1, "
        "\"first_line_not_read\": true, "
        "\"lines\": ["
        "{\"id\": 4, \"message\": \"line not read\", "
        "\"tags\": [\"irc_privmsg\", \"notify_message\"]}]}}");

    buffer = relay_remote_event_search_buffer (remote, 456);
    CHECK(buffer);
    STRCMP_EQUAL(
        "1",
        gui_buffer_get_string (buffer,
                               "localvar_relay_remote_first_line_not_read"));

    line = relay_remote_event_search_line_by_id (buffer, 4);
    CHECK(line);
    LONGS_EQUAL(3, line->data->tags_count);
    STRCMP_EQUAL("irc_privmsg", line->data->tags_array[0]);
    STRCMP_EQUAL("notify_message", line->data->tags_array[1]);
    STRCMP_EQUAL("relay_remote_line_id_4", line->data->tags_array[2]);
    LONGS_EQUAL(GUI_HOTLIST_MESSAGE, line->data->notify_level);

    gui_buffer_close (buffer);
    relay_remote_free (remote);
}
