/*
 * Copyright (C) 2022 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "StreamClientConnectionBuffer.h"
#include "StreamServerConnectionBuffer.h"
#include "Test.h"

namespace TestWebKitAPI {

TEST(StreamConnectionBufferTests, CreateWorks)
{
    auto buffer = IPC::StreamClientConnectionBuffer::create(8);
    ASSERT_TRUE(buffer.has_value());
    auto& b = *buffer;
    EXPECT_NE(b.span().data(), nullptr);
    EXPECT_EQ(b.dataSize(), 256u);
    {
        auto server = IPC::StreamServerConnectionBuffer::map(b.createHandle());
        ASSERT_TRUE(server.has_value());
        EXPECT_EQ(b.dataSize(), server->dataSize());
    }
    auto buffer2 = IPC::StreamClientConnectionBuffer::create(24);
    ASSERT_TRUE(buffer2.has_value());
    auto& b2 = *buffer2;
    EXPECT_NE(b2.span().data(), nullptr);
    EXPECT_EQ(b2.dataSize(), 16777216u);
    {
        auto server = IPC::StreamServerConnectionBuffer::map(b2.createHandle());
        ASSERT_TRUE(server.has_value());
        EXPECT_EQ(b2.dataSize(), server->dataSize());
    }
}

class StreamConnectionBufferTest : public ::testing::TestWithParam<std::tuple<unsigned>> {
public:
    unsigned bufferSizeLog2() const
    {
        return std::get<0>(GetParam());
    }

    void SetUp() override
    {
        m_client = IPC::StreamClientConnectionBuffer::create(bufferSizeLog2());
        ASSERT(m_client);
        m_maybeServer = IPC::StreamServerConnectionBuffer::map(m_client->createHandle());
    }

    IPC::StreamClientConnectionBuffer& client() { return *m_client; }
    IPC::StreamServerConnectionBuffer& server() { return *m_maybeServer; }
    bool isValid() const { return m_maybeServer.has_value(); }

protected:
    static constexpr size_t minimumSize = IPC::StreamConnectionEncoder::minimumMessageSize;
    std::optional<IPC::StreamClientConnectionBuffer> m_client;
    std::optional<IPC::StreamServerConnectionBuffer> m_maybeServer;
};

static void fill(std::span<uint8_t> span)
{
    for (size_t i = 0; i < span.size(); ++i)
        span[i] = i;
}

static void expectFilled(std::span<uint8_t> span)
{
    size_t reportFailureCount = 5;
    for (size_t i = 0; i < span.size() && reportFailureCount; ++i) {
        EXPECT_EQ(static_cast<uint8_t>(i), span[i]);
        if (span[i] != static_cast<uint8_t>(i))
            reportFailureCount--;
    }
}

TEST_P(StreamConnectionBufferTest, ClientStartsFull)
{
    ASSERT_TRUE(isValid());
    auto span = client().tryAcquire(0_s);
    ASSERT_TRUE(span.has_value());
    EXPECT_EQ(span->size(), client().dataSize() - 1);
}

TEST_P(StreamConnectionBufferTest, ServerStartsEmpty)
{
    ASSERT_TRUE(isValid());
    auto span = server().tryAcquire();
    EXPECT_FALSE(span.has_value());
}

TEST_P(StreamConnectionBufferTest, ClientWritesFullVisibleInServer)
{
    ASSERT_TRUE(isValid());
    size_t expectedServerSize;
    {
        auto span = client().tryAcquire(0_s);
        ASSERT_TRUE(span.has_value());
        EXPECT_EQ(span->size(), client().dataSize() - 1);
        fill(*span);
        client().release(span->size());
        expectedServerSize = span->size();

        span = client().tryAcquire(0_s);
        ASSERT_FALSE(span.has_value());
    }
    auto serverSpan = server().tryAcquire();
    ASSERT_EQ(expectedServerSize, serverSpan->size());
    expectFilled(*serverSpan);
}

INSTANTIATE_TEST_SUITE_P(StreamConnectionBufferSizedTests,
    StreamConnectionBufferTest,
    testing::Values(6, 9, 14),
    TestParametersToStringFormatter());

}
