BareGit
#include <string>
#include <vector>

#include <agent_smith/detail/sse_parser.hpp>
#include <gtest/gtest.h>

namespace agent_smith::internal
{
namespace
{

TEST(SseFrameParserTest, EmitsDataPayloadsAndIgnoresOtherFields)
{
    SseFrameParser parser;

    const auto payloads = parser.feed("event: completion\n"
                                      "id: 7\n"
                                      "data: {\"first\":true}\n"
                                      "\n"
                                      ": keepalive\n"
                                      "data: {\"second\":true}\n"
                                      "\n");

    EXPECT_EQ(payloads, (std::vector<std::string>{"{\"first\":true}",
                                                  "{\"second\":true}"}));
    EXPECT_FALSE(parser.finished());
}

TEST(SseFrameParserTest, RetainsIncompleteFramesAcrossChunks)
{
    SseFrameParser parser;

    EXPECT_TRUE(parser.feed("data: {\"choi").empty());
    const auto payloads = parser.feed("ces\":[1]}\n\n");

    EXPECT_EQ(payloads, (std::vector<std::string>{"{\"choices\":[1]}"}));
}

TEST(SseFrameParserTest, JoinsMultipleDataLinesWithNewlines)
{
    SseFrameParser parser;

    const auto payloads = parser.feed("data: first\n"
                                      "data: second\n"
                                      "\n");

    EXPECT_EQ(payloads, (std::vector<std::string>{"first\nsecond"}));
}

TEST(SseFrameParserTest, HandlesCarriageReturnLineEndings)
{
    SseFrameParser parser;

    const auto payloads = parser.feed("data: one\r\n\r\n");

    EXPECT_EQ(payloads, (std::vector<std::string>{"one"}));
}

TEST(SseFrameParserTest, StopsAtDoneAndDiscardsLaterPayloads)
{
    SseFrameParser parser;

    const auto payloads = parser.feed("data: before\n\n"
                                      "data: [DONE]\n\n"
                                      "data: after\n\n");

    EXPECT_EQ(payloads, (std::vector<std::string>{"before"}));
    EXPECT_TRUE(parser.finished());
    EXPECT_TRUE(parser.feed("data: ignored\n\n").empty());
}

TEST(SseFrameParserTest, ProducesIdenticalPayloadsAtEveryByteSplit)
{
    const std::string stream = "event: completion\n"
                               "data: {\"choices\":[1]}\n"
                               "\n"
                               "data: {\"usage\":{\"total_tokens\":4}}\n"
                               "\n";
    const std::vector<std::string> expected{
        "{\"choices\":[1]}",
        "{\"usage\":{\"total_tokens\":4}}",
    };

    for(std::size_t split = 0; split <= stream.size(); ++split)
    {
        SseFrameParser parser;
        std::vector<std::string> payloads =
            parser.feed(stream.substr(0, split));
        const auto suffix_payloads = parser.feed(stream.substr(split));
        payloads.insert(payloads.end(), suffix_payloads.begin(),
                        suffix_payloads.end());

        EXPECT_EQ(payloads, expected) << "split at byte " << split;
    }
}

} // namespace
} // namespace agent_smith::internal