<commit_before>// Copyright (c) 2020 by <NAME>. All rights reserved.
// Copyright (c) 2020 - 2021 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_binding_c/internal/cpp2c_publisher.hpp"
#include "iceoryx_posh/internal/popo/building_blocks/chunk_queue_popper.hpp"
#include "iceoryx_posh/internal/popo/ports/publisher_port_roudi.hpp"
#include "iceoryx_posh/internal/popo/ports/publisher_port_user.hpp"
#include "iceoryx_posh/mepoo/mepoo_config.hpp"

using namespace iox;
using namespace iox::popo;
using namespace iox::capro;
using namespace iox::mepoo;
using namespace iox::cxx;
using namespace iox::posix;

extern "C" {
#include "iceoryx_binding_c/chunk.h"
#include "iceoryx_binding_c/publisher.h"
}

#include "test.hpp"

using namespace ::testing;

class iox_pub_test : public Test
{
  protected:
    struct DummySample
    {
        uint64_t dummy{42};
    };

    iox_pub_test()
    {
        m_mempoolconf.addMemPool({CHUNK_SIZE, NUM_CHUNKS_IN_POOL});
        m_memoryManager.configureMemoryManager(m_mempoolconf, m_memoryAllocator, m_memoryAllocator);
    }

    ~iox_pub_test()
    {
    }

    void SetUp()
    {
        m_sut.m_portData = &m_publisherPortData;
        ::testing::internal::CaptureStderr();
    }

    void TearDown()
    {
        std::string output = ::testing::internal::GetCapturedStderr();
        if (Test::HasFailure())
        {
            std::cout << output << std::endl;
        }
    }

    void Subscribe(popo::PublisherPortData* ptr)
    {
        PublisherPortUser userPort(ptr);
        PublisherPortRouDi roudiPort(ptr);

        roudiPort.tryGetCaProMessage();
        iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::SUB,
                                              iox::capro::ServiceDescription("a", "b", "c"));
        caproMessage.m_chunkQueueData = &m_chunkQueueData;
        auto maybeCaProMessage = roudiPort.dispatchCaProMessageAndGetPossibleResponse(caproMessage);
    }

    void Unsubscribe(popo::PublisherPortData* ptr)
    {
        PublisherPortRouDi roudiPort(ptr);

        iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::UNSUB,
                                              iox::capro::ServiceDescription("a", "b", "c"));
        caproMessage.m_chunkQueueData = &m_chunkQueueData;
        auto maybeCaProMessage = roudiPort.dispatchCaProMessageAndGetPossibleResponse(caproMessage);
    }

    static constexpr size_t MEMORY_SIZE = 1024 * 1024;
    uint8_t m_memory[MEMORY_SIZE];
    static constexpr uint32_t NUM_CHUNKS_IN_POOL = 20;
    static constexpr uint32_t CHUNK_SIZE = 256;

    using ChunkQueueData_t = popo::ChunkQueueData<DefaultChunkQueueConfig, popo::ThreadSafePolicy>;
    ChunkQueueData_t m_chunkQueueData{iox::cxx::VariantQueueTypes::SoFi_SingleProducerSingleConsumer};

    GenericRAII m_uniqueRouDiId{[] { popo::internal::setUniqueRouDiId(0); },
                                [] { popo::internal::unsetUniqueRouDiId(); }};

    Allocator m_memoryAllocator{m_memory, MEMORY_SIZE};
    MePooConfig m_mempoolconf;
    MemoryManager m_memoryManager;

    // publisher port w/o history
    PublisherPortData m_publisherPortData{
        ServiceDescription("a", "b", "c"), "myApp", &m_memoryManager, PublisherOptions()};

    // publisher port w/ history
    PublisherOptions m_publisherOptions{MAX_PUBLISHER_HISTORY};
    PublisherPortData m_publisherPortDataHistory{
        capro::ServiceDescription("x", "y", "z"), "myApp", &m_memoryManager, m_publisherOptions};
    cpp2c_Publisher m_sut;
};

TEST_F(iox_pub_test, initialStateOfIsOfferedIsAsExpected)
{
    PublisherOptions iGotOptions;
    auto expectedIsOffered = iGotOptions.offerOnCreate;
    EXPECT_EQ(expectedIsOffered, iox_pub_is_offered(&m_sut));
}

TEST_F(iox_pub_test, is_offeredAfterOffer)
{
    iox_pub_offer(&m_sut);
    EXPECT_TRUE(iox_pub_is_offered(&m_sut));
}

TEST_F(iox_pub_test, isNotOfferedAfterStopOffer)
{
    iox_pub_offer(&m_sut);
    iox_pub_stop_offer(&m_sut);
    EXPECT_FALSE(iox_pub_is_offered(&m_sut));
}

TEST_F(iox_pub_test, initialStateIsNoSubscribers)
{
    EXPECT_FALSE(iox_pub_has_subscribers(&m_sut));
}

TEST_F(iox_pub_test, has_subscribersAfterSubscription)
{
    iox_pub_offer(&m_sut);
    this->Subscribe(&m_publisherPortData);
    EXPECT_TRUE(iox_pub_has_subscribers(&m_sut));
}

TEST_F(iox_pub_test, noSubscribersAfterUnsubscribe)
{
    iox_pub_offer(&m_sut);
    this->Subscribe(&m_publisherPortData);
    this->Unsubscribe(&m_publisherPortData);
    EXPECT_FALSE(iox_pub_has_subscribers(&m_sut));
}

TEST_F(iox_pub_test, allocateChunkForOneChunkIsSuccessful)
{
    void* chunk = nullptr;
    EXPECT_EQ(AllocationResult_SUCCESS, iox_pub_loan_chunk(&m_sut, &chunk, sizeof(DummySample)));
}

TEST_F(iox_pub_test, chunkHeaderCanBeObtainedFromChunk)
{
    void* chunk = nullptr;
    ASSERT_EQ(AllocationResult_SUCCESS, iox_pub_loan_chunk(&m_sut, &chunk, sizeof(DummySample)));
    auto header = iox_chunk_payload_to_header(chunk);
    EXPECT_NE(header, nullptr);
}

TEST_F(iox_pub_test, chunkHeaderCanBeConvertedBackToPayload)
{
    void* chunk = nullptr;
    ASSERT_EQ(AllocationResult_SUCCESS, iox_pub_loan_chunk(&m_sut, &chunk, sizeof(DummySample)));
    auto header = iox_chunk_payload_to_header(chunk);
    auto payload = iox_chunk_header_to_payload(header);
    EXPECT_EQ(payload, chunk);
}

TEST_F(iox_pub_test, allocate_chunkFailsWhenHoldingToManyChunksInParallel)
{
    void* chunk = nullptr;
    for (uint32_t i = 0U; i < iox::MAX_CHUNKS_ALLOCATED_PER_PUBLISHER_SIMULTANEOUSLY; ++i)
    {
        EXPECT_EQ(AllocationResult_SUCCESS, iox_pub_loan_chunk(&m_sut, &chunk, 100));
    }

    EXPECT_EQ(AllocationResult_TOO_MANY_CHUNKS_ALLOCATED_IN_PARALLEL, iox_pub_loan_chunk(&m_sut, &chunk, 100));<commit_msg>iox-#14 readd some tests for the publisher C API<commit_after>// Copyright (c) 2020 by <NAME>. All rights reserved.
// Copyright (c) 2020 - 2021 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_binding_c/internal/cpp2c_publisher.hpp"
#include "iceoryx_posh/internal/popo/building_blocks/chunk_queue_popper.hpp"
#include "iceoryx_posh/internal/popo/ports/publisher_port_roudi.hpp"
#include "iceoryx_posh/internal/popo/ports/publisher_port_user.hpp"
#include "iceoryx_posh/mepoo/mepoo_config.hpp"

using namespace iox;
using namespace iox::popo;
using namespace iox::capro;
using namespace iox::mepoo;
using namespace iox::cxx;
using namespace iox::posix;

extern "C" {
#include "iceoryx_binding_c/chunk.h"
#include "iceoryx_binding_c/publisher.h"
}

#include "test.hpp"

using namespace ::testing;

class iox_pub_test : public Test
{
  protected:
    struct DummySample
    {
        uint64_t dummy{42};
    };

    iox_pub_test()
    {
        m_mempoolconf.addMemPool({CHUNK_SIZE, NUM_CHUNKS_IN_POOL});
        m_memoryManager.configureMemoryManager(m_mempoolconf, m_memoryAllocator, m_memoryAllocator);
    }

    ~iox_pub_test()
    {
    }

    void SetUp()
    {
        m_sut.m_portData = &m_publisherPortData;
        ::testing::internal::CaptureStderr();
    }

    void TearDown()
    {
        std::string output = ::testing::internal::GetCapturedStderr();
        if (Test::HasFailure())
        {
            std::cout << output << std::endl;
        }
    }

    void Subscribe(popo::PublisherPortData* ptr)
    {
        PublisherPortUser userPort(ptr);
        PublisherPortRouDi roudiPort(ptr);

        roudiPort.tryGetCaProMessage();
        iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::SUB,
                                              iox::capro::ServiceDescription("a", "b", "c"));
        caproMessage.m_chunkQueueData = &m_chunkQueueData;
        auto maybeCaProMessage = roudiPort.dispatchCaProMessageAndGetPossibleResponse(caproMessage);
    }

    void Unsubscribe(popo::PublisherPortData* ptr)
    {
        PublisherPortRouDi roudiPort(ptr);

        iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::UNSUB,
                                              iox::capro::ServiceDescription("a", "b", "c"));
        caproMessage.m_chunkQueueData = &m_chunkQueueData;
        auto maybeCaProMessage = roudiPort.dispatchCaProMessageAndGetPossibleResponse(caproMessage);
    }

    static constexpr size_t MEMORY_SIZE = 1024 * 1024;
    uint8_t m_memory[MEMORY_SIZE];
    static constexpr uint32_t NUM_CHUNKS_IN_POOL = 20;
    static constexpr uint32_t CHUNK_SIZE = 256;

    using ChunkQueueData_t = popo::ChunkQueueData<DefaultChunkQueueConfig, popo::ThreadSafePolicy>;
    ChunkQueueData_t m_chunkQueueData{iox::cxx::VariantQueueTypes::SoFi_SingleProducerSingleConsumer};

    GenericRAII m_uniqueRouDiId{[] { popo::internal::setUniqueRouDiId(0); },
                                [] { popo::internal::unsetUniqueRouDiId(); }};

    Allocator m_memoryAllocator{m_memory, MEMORY_SIZE};
    MePooConfig m_mempoolconf;
    MemoryManager m_memoryManager;

    // publisher port w/o history
    PublisherPortData m_publisherPortData{
        ServiceDescription("a", "b", "c"), "myApp", &m_memoryManager, PublisherOptions()};

    // publisher port w/ history
    PublisherOptions m_publisherOptions{MAX_PUBLISHER_HISTORY};
    PublisherPortData m_publisherPortDataHistory{
        capro::ServiceDescription("x", "y", "z"), "myApp", &m_memoryManager, m_publisherOptions};
    cpp2c_Publisher m_sut;
};

TEST_F(iox_pub_test, initialStateOfIsOfferedIsAsExpected)
{
    PublisherOptions iGotOptions;
    auto expectedIsOffered = iGotOptions.offerOnCreate;
    EXPECT_EQ(expectedIsOffered, iox_pub_is_offered(&m_sut));
}

TEST_F(iox_pub_test, is_offeredAfterOffer)
{
    iox_pub_offer(&m_sut);
    EXPECT_TRUE(iox_pub_is_offered(&m_sut));
}

TEST_F(iox_pub_test, isNotOfferedAfterStopOffer)
{
    iox_pub_offer(&m_sut);
    iox_pub_stop_offer(&m_sut);
    EXPECT_FALSE(iox_pub_is_offered(&m_sut));
}

TEST_F(iox_pub_test, initialStateIsNoSubscribers)
{
    EXPECT_FALSE(iox_pub_has_subscribers(&m_sut));
}

TEST_F(iox_pub_test, has_subscribersAfterSubscription)
{
    iox_pub_offer(&m_sut);
    this->Subscribe(&m_publisherPortData);
    EXPECT_TRUE(iox_pub_has_subscribers(&m_sut));
}

TEST_F(iox_pub_test, noSubscribersAfterUnsubscribe)
{
    iox_pub_offer(&m_sut);
    this->Subscribe(&m_publisherPortData);
    this->Unsubscribe(&m_publisherPortData);
    EXPECT_FALSE(iox_pub_has_subscribers(&m_sut));
}

TEST_F(iox_pub_test, allocateChunkForOneChunkIsSuccessful)
{
    void* chunk = nullptr;
    EXPECT_EQ(AllocationResult_SUCCESS, iox_pub_loan_chunk(&m_sut, &chunk, sizeof(DummySample)));
}

TEST_F(iox_pub_test, allocateChunkWithCustomHeaderIsSuccessful)
{
    m_sut.m_customHeaderSize = 4U;
    m_sut.m_customHeaderAlignment = 2U;

    void* chunk = nullptr;
    ASSERT_EQ(AllocationResult_SUCCESS, iox_pub_loan_chunk(&m_sut, &chunk, sizeof(DummySample)));

    auto header = iox_chunk_payload_to_header(chunk);
    auto spaceBetweenChunkHeaderAndPaylod = reinterpret_cast<uint64_t>(chunk) - reinterpret_cast<uint64_t>(header);
    EXPECT_GT(spaceBetweenChunkHeaderAndPaylod, sizeof(iox::mepoo::ChunkHeader));
}

TEST_F(iox_pub_test, allocateChunkWithCustomHeaderAndPayloadAlignmentIsSuccessful)
{
    m_sut.m_customHeaderSize = 4U;
    m_sut.m_customHeaderAlignment = 2U;

    constexpr uint32_t PAYLOAD_ALIGNMENT{128U};
    void* chunk = nullptr;
    ASSERT_EQ(AllocationResult_SUCCESS,
              iox_pub_loan_aligned_chunk(&m_sut, &chunk, sizeof(DummySample), PAYLOAD_ALIGNMENT));

    EXPECT_TRUE(reinterpret_cast<uint64_t>(chunk) % PAYLOAD_ALIGNMENT == 0U);
}

TEST_F(iox_pub_test, allocateChunkWithCustomHeaderAndPayloadAlignmentFails)
{
    m_sut.m_customHeaderSize = 4U;
    m_sut.m_customHeaderAlignment = 3U;

    constexpr uint32_t PAYLOAD_ALIGNMENT{128U};
    void* chunk = nullptr;
    ASSERT_EQ(AllocationResult_INVALID_PARAMETER_FOR_CHUNK,
              iox_pub_loan_aligned_chunk(&m_sut, &chunk, sizeof(DummySample), PAYLOAD_ALIGNMENT));
}

TEST_F(iox_pub_test, chunkHeaderCanBeObtainedFromChunk)
{
    void* chunk = nullptr;
    ASSERT_EQ(AllocationResult_SUCCESS, iox_pub_loan_chunk(&m_sut, &chunk, sizeof(DummySample)));
    auto header = iox_chunk_payload_to_header(chunk);
    EXPECT_NE(header, nullptr);
}

TEST_F(iox_pub_test, chunkHeaderCanBeConvertedBackToPayload)
{
    void* chunk = nullptr;
    ASSERT_EQ(AllocationResult_SUCCESS, iox_pub_loan_chunk(&m_sut, &chunk, sizeof(DummySample)));
    auto header = iox_chunk_payload_to_header(chunk);
    auto payload = iox_chunk_header_to_payload(header);
    EXPECT_EQ(payload, chunk);
}

TEST_F(iox_pub_test, allocate_chunkFailsWhenHoldingToManyChunksInParallel)
{
    void* chunk = nullptr;
    for (uint32_t i = 0U; i < iox::MAX_CHUNKS_ALLOCATED_PER_PUBLISHER_SIMULTANEOUSLY; ++i)
    {
        EXPECT_EQ(AllocationResult_SUCCESS, iox_pub_loan_chunk(&m_sut, &chunk, 100));
    }

    EXPECT_EQ(AllocationResult_TOO_MANY_CHUNKS_ALLOCATED_IN_PARALLEL, iox_pub_loan_chunk(&m_sut, &chunk, 100));
{'fraction_non_alphanumeric': 0.10436203466894003, 'fraction_numerical': 0.009164535379369138, 'mean_word_length': 4.5464933018124505, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7386971', 'n_tokens_mistral': 5067, 'n_tokens_neox': 4810, 'n_words': 780}