// Copyright (c) 2019, 2021 by Robert Bosch GmbH. 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 "test.hpp"

#include "iceoryx_posh/capro/service_description.hpp"
#include "iceoryx_utils/cxx/serialization.hpp"
#include "iceoryx_utils/cxx/string.hpp"

#include <cstdint>

using namespace ::testing;
using ::testing::Return;

using namespace iox::capro;

class ServiceDescription_test : public Test
{
  public:
    IdString_t testService;
    IdString_t testInstance;
    IdString_t testEvent;
    void SetUp(){};
    void TearDown(){};
};

/// BEGIN CLASSHASH TESTS

TEST_F(ServiceDescription_test, ServiceDescriptionClassHashDefaultCtorCreatesClassHashWithDefaultValues)
{
    ServiceDescription::ClassHash testHash{};

    EXPECT_EQ(uint32_t(0), testHash[0]);
    EXPECT_EQ(uint32_t(0), testHash[1]);
    EXPECT_EQ(uint32_t(0), testHash[2]);
    EXPECT_EQ(uint32_t(0), testHash[3]);
}

TEST_F(ServiceDescription_test, ServiceDescriptionClassHashCtorCreatesClassHashWithValuesPassedToTheCtor)
{
    ServiceDescription::ClassHash testHash{1U, 2U, 3U, 4U};

    EXPECT_EQ(uint32_t(1), testHash[0]);
    EXPECT_EQ(uint32_t(2), testHash[1]);
    EXPECT_EQ(uint32_t(3), testHash[2]);
    EXPECT_EQ(uint32_t(4), testHash[3]);
}

TEST_F(ServiceDescription_test, ComparingTwoUnequalClassHashWithEqualityOperatorReturnsFalse)
{
    ServiceDescription::ClassHash testHash1{15U, 25U, 35U, 45U};
    ServiceDescription::ClassHash testHash2{55U, 65U, 75U, 85U};

    EXPECT_FALSE(testHash1 == testHash2);
}

TEST_F(ServiceDescription_test, ComparingTwoUnequalClassHashWithEqualityOperatorReturnsTrue)
{
    ServiceDescription::ClassHash testHash1{10U, 20U, 30U, 40U};
    ServiceDescription::ClassHash testHash2{10U, 20U, 30U, 40U};

    EXPECT_TRUE(testHash1 == testHash2);
}

TEST_F(ServiceDescription_test, ComparingTwoUnequalClassHashWithNotEqualOperatorReturnsTrue)
{
    ServiceDescription::ClassHash testHash1{12U, 24U, 36U, 48U};
    ServiceDescription::ClassHash testHash2{60U, 72U, 84U, 96U};

    EXPECT_TRUE(testHash1 != testHash2);
}

TEST_F(ServiceDescription_test, ComparingTwoEqualClassHashWithNotEqualOperatorReturnsFalse)
{
    ServiceDescription::ClassHash testHash1{11U, 22U, 33U, 44U};
    ServiceDescription::ClassHash testHash2{11U, 22U, 33U, 44U};

    EXPECT_FALSE(testHash1 != testHash2);
}

TEST_F(ServiceDescription_test, ClassHashWithValuesAssignedUsingAssignmentOperatorStoresTheValueInTheCorrespondingIndex)
{
    ServiceDescription::ClassHash testHash{};

    testHash[0] = 10U;
    testHash[1] = 20U;
    testHash[2] = 30U;
    testHash[3] = 40U;

    EXPECT_THAT(testHash[0], Eq(10U));
    EXPECT_THAT(testHash[1], Eq(20U));
    EXPECT_THAT(testHash[2], Eq(30U));
    EXPECT_THAT(testHash[3], Eq(40U));
}

TEST_F(ServiceDescription_test, ClassHashSubsriptOperatorOutOfBoundsFails)
{
    ServiceDescription::ClassHash testHash{1U, 2U, 3U, 4U};

    testHash[0] = 1U;
    testHash[1] = 2U;
    testHash[2] = 3U;
    testHash[3] = 4U;

    EXPECT_DEATH({ testHash[4] = 5U; }, ".*");
}

/// END CLASSHASH TESTS

/// BEGIN SERVICEDESCRIPTION TESTS

/// @attention The purpose of the Serialization is not to be an alternative Constructor. It is intended to send/receive
/// the ServiceDescription over communication protocols which transfers strings like the MessageQueue. The testcase is
/// only intended to check the functionality by injecting the valus directly.
TEST_F(ServiceDescription_test, ServiceDescriptionSerializationCreatesServiceDescriptionWithValuesPassedToTheCtor)
{
    ServiceDescription::ClassHash testHash = {11U, 21U, 31U, 41U};
    testService = "Service";
    testInstance = "Instance";
    testEvent = "Event";
    uint16_t testServiceID = 1U;
    uint16_t testInstanceID = 2U;
    uint16_t testEventID = 3U;
    Scope testScope = Scope::INTERNAL;
    Interfaces testInterfaceSource = Interfaces::INTERNAL;
    auto serialObj = iox::cxx::Serialization::create(testService.c_str(),
                                                     testInstance.c_str(),
                                                     testEvent.c_str(),
                                                     testServiceID,
                                                     testInstanceID,
                                                     testEventID,
                                                     testHash[0],
                                                     testHash[1],
                                                     testHash[2],
                                                     testHash[3],
                                                     false,
                                                     static_cast<uint16_t>(testScope),
                                                     static_cast<uint16_t>(testInterfaceSource));

    ServiceDescription serviceDescription1 = ServiceDescription(serialObj);

    EXPECT_THAT(serviceDescription1.getServiceIDString(), Eq(testService));
    EXPECT_THAT(serviceDescription1.getInstanceIDString(), Eq(testInstance));
    EXPECT_THAT(serviceDescription1.getEventIDString(), Eq(testEvent));
    EXPECT_THAT(serviceDescription1.getServiceID(), Eq(testServiceID));
    EXPECT_THAT(serviceDescription1.getInstanceID(), Eq(testInstanceID));
    EXPECT_THAT(serviceDescription1.getEventID(), Eq(testEventID));
    EXPECT_THAT((serviceDescription1.getClassHash())[0], Eq(testHash[0]));
    EXPECT_THAT((serviceDescription1.getClassHash())[1], Eq(testHash[1]));
    EXPECT_THAT((serviceDescription1.getClassHash())[2], Eq(testHash[2]));
    EXPECT_THAT((serviceDescription1.getClassHash())[3], Eq(testHash[3]));
    EXPECT_THAT(serviceDescription1.hasServiceOnlyDescription(), Eq(false));
    EXPECT_THAT(serviceDescription1.getScope(), Eq(Scope::INTERNAL));
    EXPECT_THAT(serviceDescription1.getSourceInterface(), Eq(Interfaces::INTERNAL));
}

/// @attention The purpose of the Serialization is not to be an alternative Constructor. It is intended to send/receive
/// the ServiceDescription over communication protocols which transfers strings like the MessageQueue. The testcase is
/// only intended to check the functionality by injecting the valus directly.
TEST_F(ServiceDescription_test, ServiceDescriptionObjectInitialisationWithOutOfBoundaryScopeSetsTheScopeToInvalid)
{
    ServiceDescription::ClassHash testHash = {14U, 28U, 42U, 56U};
    testService = "Service";
    testInstance = "Instance";
    testEvent = "Event";
    uint16_t testServiceID = 1U;
    uint16_t testInstanceID = 2U;
    uint16_t testEventID = 3U;
    uint16_t invalidScope = 3U;
    auto serialObj = iox::cxx::Serialization::create(testService.c_str(),
                                                     testInstance.c_str(),
                                                     testEvent.c_str(),
                                                     testServiceID,
                                                     testInstanceID,
                                                     testEventID,
                                                     testHash[0],
                                                     testHash[1],
                                                     testHash[2],
                                                     testHash[3],
                                                     true,
                                                     invalidScope);

    ServiceDescription serviceDescription1 = ServiceDescription(serialObj);

    EXPECT_THAT(serviceDescription1.getScope(), Eq(Scope::INVALID));
}

/// @attention The purpose of the Serialization is not to be an alternative Constructor. It is intended to send/receive
/// the ServiceDescription over communication protocols which transfers strings like the MessageQueue. The testcase is
/// only intended to check the functionality by injecting the valus directly.
TEST_F(ServiceDescription_test,
       ServiceDescriptionObjectInitialisationWithOutOfBoundaryInterfaceSourceSetsTheInterfaceSourceToInterfaceEnd)
{
    ServiceDescription::ClassHash testHash = {17U, 34U, 51U, 68U};
    testService = "Service";
    testInstance = "Instance";
    testEvent = "Event";
    uint16_t testServiceID = 1U;
    uint16_t testInstanceID = 2U;
    uint16_t testEventID = 3U;
    uint16_t testScope = 2U;
    uint16_t invalidInterfaceSource = 10U;
    auto serialObj = iox::cxx::Serialization::create(testService.c_str(),
                                                     testInstance.c_str(),
                                                     testEvent.c_str(),
                                                     testServiceID,
                                                     testInstanceID,
                                                     testEventID,
                                                     testHash[0],
                                                     testHash[1],
                                                     testHash[2],
                                                     testHash[3],
                                                     true,
                                                     static_cast<uint16_t>(testScope),
                                                     invalidInterfaceSource);

    ServiceDescription serviceDescription1 = ServiceDescription(serialObj);

    EXPECT_THAT(serviceDescription1.getSourceInterface(), Eq(Interfaces::INTERFACE_END));
}

TEST_F(ServiceDescription_test,
       ServiceDescriptionCtorWithOnlyIDsCreatesServiceDescriptionWithTheSameServiceEventAndInstanceStringsAsIDs)
{
    uint16_t testServiceID = 1U;
    uint16_t testEventID = 2U;
    uint16_t testInstanceID = 3U;

    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testEventID, testInstanceID);

    EXPECT_THAT(std::to_string(serviceDescription1.getServiceID()), serviceDescription1.getServiceIDString());
    EXPECT_THAT(std::to_string(serviceDescription1.getEventID()), serviceDescription1.getEventIDString());
    EXPECT_THAT(std::to_string(serviceDescription1.getInstanceID()), serviceDescription1.getInstanceIDString());
}

TEST_F(ServiceDescription_test, ServiceDescriptionDefaultCtorInitializesTheIDsAndStringsToZero)
{
    ServiceDescription serviceDescription1 = ServiceDescription();

    EXPECT_EQ(serviceDescription1.getServiceID(), 0U);
    EXPECT_EQ(serviceDescription1.getEventID(), 0U);
    EXPECT_EQ(serviceDescription1.getInstanceID(), 0U);
    EXPECT_THAT(serviceDescription1.getServiceIDString(), StrEq("0"));
    EXPECT_THAT(serviceDescription1.getEventIDString(), StrEq("0"));
    EXPECT_THAT(serviceDescription1.getInstanceIDString(), StrEq("0"));
}

TEST_F(ServiceDescription_test, ServiceDescriptionDefaultCtorInitializesTheScopeToWorldWide)
{
    ServiceDescription serviceDescription1 = ServiceDescription();

    EXPECT_THAT(serviceDescription1.getScope(), Eq(Scope::WORLDWIDE));
}

TEST_F(ServiceDescription_test, ServiceDescriptionDefaultCtorInitializesTheInterfaceToInternal)
{
    ServiceDescription serviceDescription1 = ServiceDescription();

    EXPECT_THAT(serviceDescription1.getSourceInterface(), Eq(Interfaces::INTERNAL));
}

TEST_F(ServiceDescription_test, ServiceDescriptionStringCtorCreatesServiceDescriptionWithValuesPassedToTheCtor)
{
    testService = "1";
    testInstance = "2";
    testEvent = "3";
    ServiceDescription::ClassHash testHash = {12U, 23U, 34U, 45U};

    ServiceDescription serviceDescription1 = ServiceDescription(testService, testInstance, testEvent, testHash);

    EXPECT_THAT(serviceDescription1.getServiceIDString(), StrEq("1"));
    EXPECT_THAT(serviceDescription1.getInstanceIDString(), StrEq("2"));
    EXPECT_THAT(serviceDescription1.getEventIDString(), StrEq("3"));
    EXPECT_EQ(uint16_t(1), serviceDescription1.getServiceID());
    EXPECT_EQ(uint16_t(2), serviceDescription1.getInstanceID());
    EXPECT_EQ(uint16_t(3), serviceDescription1.getEventID());
    EXPECT_EQ(uint32_t(12), serviceDescription1.getClassHash()[0]);
    EXPECT_EQ(uint32_t(23), serviceDescription1.getClassHash()[1]);
    EXPECT_EQ(uint32_t(34), serviceDescription1.getClassHash()[2]);
    EXPECT_EQ(uint32_t(45), serviceDescription1.getClassHash()[3]);
}
TEST_F(ServiceDescription_test, ServiceDescriptionStringCtorWithNonIntegerStringValuesSetTheIDsToInvalid)
{
    testService = "Service";
    testInstance = "Instance";
    testEvent = "Event";
    ServiceDescription::ClassHash testHash = {01U, 02U, 03U, 04U};

    ServiceDescription serviceDescription1 = ServiceDescription(testService, testInstance, testEvent, testHash);

    EXPECT_EQ(InvalidID, serviceDescription1.getServiceID());
    EXPECT_EQ(InvalidID, serviceDescription1.getInstanceID());
    EXPECT_EQ(InvalidID, serviceDescription1.getEventID());
}

TEST_F(ServiceDescription_test, ServiceDescriptionStringCtorWithZeroAsStringValuesSetTheIDsToInvalid)
{
    testService = "0";
    testInstance = "0";
    testEvent = "0";
    ServiceDescription::ClassHash testHash = {19U, 29U, 39U, 49U};

    ServiceDescription serviceDescription1 = ServiceDescription(testService, testInstance, testEvent, testHash);

    EXPECT_EQ(InvalidID, serviceDescription1.getServiceID());
    EXPECT_EQ(InvalidID, serviceDescription1.getInstanceID());
    EXPECT_EQ(InvalidID, serviceDescription1.getEventID());
}

TEST_F(ServiceDescription_test, ServiceDescriptionStringCtorWithOutOfBoundaryIntegerStringValuesSetTheIDsToInvalid)
{
    IdString_t outOfBoundaryTestService(iox::cxx::TruncateToCapacity,
                                        std::to_string(uint32_t(1) + std::numeric_limits<uint16_t>::max()));
    IdString_t outOfBoundaryTestInstance(iox::cxx::TruncateToCapacity,
                                         std::to_string(uint32_t(1) + std::numeric_limits<uint16_t>::max()));
    IdString_t outOfBoundaryTestEvent(iox::cxx::TruncateToCapacity,
                                      std::to_string(uint32_t(1) + std::numeric_limits<uint16_t>::max()));
    ServiceDescription::ClassHash testHash = {1U, 2U, 3U, 4U};

    ServiceDescription serviceDescription1 =
        ServiceDescription(outOfBoundaryTestService, outOfBoundaryTestInstance, outOfBoundaryTestEvent, testHash);

    EXPECT_EQ(InvalidID, serviceDescription1.getServiceID());
    EXPECT_EQ(InvalidID, serviceDescription1.getInstanceID());
    EXPECT_EQ(InvalidID, serviceDescription1.getEventID());
}

TEST_F(ServiceDescription_test, ServiceDescriptionCtorWithServiceIDAndInstanceIDSetsHasServiceDescriptionTrue)
{
    uint16_t testService = 1U;
    uint16_t testInstance = 2U;

    ServiceDescription serviceDescription1 = ServiceDescription(testService, testInstance);

    EXPECT_TRUE(serviceDescription1.hasServiceOnlyDescription());
}

TEST_F(ServiceDescription_test, ServiceDescriptionCtorWithServiceStringAndInstanceStringSetsHasServiceDescriptionTrue)
{
    testService = "Service";
    testInstance = "Instance";

    ServiceDescription serviceDescription1 = ServiceDescription(testService, testInstance);

    EXPECT_TRUE(serviceDescription1.hasServiceOnlyDescription());
}

TEST_F(ServiceDescription_test, TwoServiceDescriptionsWithAnyServiceAnyInstanceAnyEventIDsAreEqual)
{
    uint16_t testServiceID = iox::capro::AnyService;
    uint16_t testEventID = iox::capro::AnyEvent;
    uint16_t testInstanceID = iox::capro::AnyInstance;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testEventID, testInstanceID);
    ServiceDescription serviceDescription2 = ServiceDescription(testServiceID, testEventID, testInstanceID);

    EXPECT_TRUE(serviceDescription1 == serviceDescription2);
}

TEST_F(ServiceDescription_test,
       ServiceDescriptionWithAnyServiceAnyInstanceAnyEventIDAndServiceDescriptionWithValidIDsAreEqual)
{
    uint16_t testServiceID1 = 1U;
    uint16_t testEventID1 = 2U;
    uint16_t testInstanceID1 = 3U;
    uint16_t testServiceID2 = iox::capro::AnyService;
    uint16_t testEventID2 = iox::capro::AnyEvent;
    uint16_t testInstanceID2 = iox::capro::AnyInstance;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID1, testEventID1, testInstanceID1);
    ServiceDescription serviceDescription2 = ServiceDescription(testServiceID2, testEventID2, testInstanceID2);

    EXPECT_TRUE(serviceDescription1 == serviceDescription2);
}

TEST_F(ServiceDescription_test, TwoServiceDescriptionsWithDifferentButValidServiceIDsAreNotEqual)
{
    uint16_t testServiceID1 = 1U;
    uint16_t testEventID1 = 2U;
    uint16_t testInstanceID1 = 3U;
    uint16_t testServiceID2 = 4U;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID1, testEventID1, testInstanceID1);
    ServiceDescription serviceDescription2 = ServiceDescription(testServiceID2, testEventID1, testInstanceID1);

    EXPECT_FALSE(serviceDescription1 == serviceDescription2);
}

TEST_F(ServiceDescription_test, TwoServiceDescriptionsWithDifferentButValidEventIDsAreNotEqual)
{
    uint16_t testServiceID1 = 1U;
    uint16_t testEventID1 = 2U;
    uint16_t testInstanceID1 = 3U;
    uint16_t testEventID2 = 4U;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID1, testEventID1, testInstanceID1);
    ServiceDescription serviceDescription2 = ServiceDescription(testServiceID1, testEventID2, testInstanceID1);

    EXPECT_FALSE(serviceDescription1 == serviceDescription2);
}

TEST_F(ServiceDescription_test, TwoServiceDescriptionsWithDifferentButValidInstanceIDsAreNotEqual)
{
    uint16_t testServiceID1 = 1U;
    uint16_t testEventID1 = 2U;
    uint16_t testInstanceID1 = 3U;
    uint16_t testInstanceID2 = 4U;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID1, testEventID1, testInstanceID1);
    ServiceDescription serviceDescription2 = ServiceDescription(testServiceID1, testEventID1, testInstanceID2);

    EXPECT_FALSE(serviceDescription1 == serviceDescription2);
}

TEST_F(ServiceDescription_test, TwoServiceDescriptionsWithDifferentAndValidServiceInstanceEventIDsAreNotEqual)
{
    uint16_t testServiceID1 = 1U;
    uint16_t testEventID1 = 2U;
    uint16_t testInstanceID1 = 3U;
    uint16_t testServiceID2 = 4U;
    uint16_t testEventID2 = 5U;
    uint16_t testInstanceID2 = 6U;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID1, testEventID1, testInstanceID1);
    ServiceDescription serviceDescription2 = ServiceDescription(testServiceID2, testEventID2, testInstanceID2);

    EXPECT_FALSE(serviceDescription1 == serviceDescription2);
}

TEST_F(ServiceDescription_test, TwoServiceDescriptionsWithDifferentInstanceStringsAreNotEqual)
{
    uint16_t testServiceID = 1U;
    uint16_t testEventID = 2U;
    uint16_t testInstanceID = InvalidID;
    testService = "1";
    testEvent = "2";
    testInstance = "instance";

    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testEventID, testInstanceID);
    ServiceDescription serviceDescription2 = ServiceDescription(testService, testInstance, testEvent);

    EXPECT_FALSE(serviceDescription1 == serviceDescription2);
}

TEST_F(ServiceDescription_test, TwoServiceDescriptionsWithDifferentEventStringsAreNotEqual)
{
    uint16_t testServiceID = 1U;
    uint16_t testEventID = InvalidID;
    uint16_t testInstanceID = 3U;
    testService = "1";
    testEvent = "event";
    testInstance = "3";

    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testEventID, testInstanceID);
    ServiceDescription serviceDescription2 = ServiceDescription(testService, testInstance, testEvent);

    EXPECT_FALSE(serviceDescription1 == serviceDescription2);
}

TEST_F(ServiceDescription_test, TwoServiceDescriptionsWithSameIDsComparedWithInequalityOperatorReturnsFalse)
{
    uint16_t testServiceID = 1U;
    uint16_t testEventID = 2U;
    uint16_t testInstanceID = 3U;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testEventID, testInstanceID);
    ServiceDescription serviceDescription2 = ServiceDescription(testServiceID, testEventID, testInstanceID);

    EXPECT_FALSE(serviceDescription1 != serviceDescription2);
}

TEST_F(ServiceDescription_test, ServiceMatchMethodReturnsTrueIfTheServiceIDsAreSame)
{
    uint16_t sameserviceID = 1U;
    ServiceDescription description1 = ServiceDescription(sameserviceID, iox::capro::AnyEvent, iox::capro::AnyInstance);
    ServiceDescription description2 = ServiceDescription(sameserviceID, iox::capro::AnyEvent, iox::capro::AnyInstance);

    EXPECT_TRUE(iox::capro::serviceMatch(description1, description2));
}

TEST_F(ServiceDescription_test, ServiceMatchMethodReturnsFalseIfTheServiceIDsAreDifferent)
{
    uint16_t serviceID1 = 1U;
    uint16_t serviceID2 = 2U;
    ServiceDescription description1 = ServiceDescription(serviceID1, iox::capro::AnyEvent, iox::capro::AnyInstance);
    ServiceDescription description2 = ServiceDescription(serviceID2, iox::capro::AnyEvent, iox::capro::AnyInstance);

    EXPECT_FALSE(iox::capro::serviceMatch(description1, description2));
}

TEST_F(ServiceDescription_test, IsInternalMethodReturnsTrueWhenTheScopeIsSetToInternal)
{
    uint16_t testServiceID = 1U;
    uint16_t testEventID = 2U;
    uint16_t testInstanceID = 3U;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testEventID, testInstanceID);

    serviceDescription1.setInternal();

    EXPECT_TRUE(serviceDescription1.isInternal());
}

TEST_F(ServiceDescription_test, GetScopeMethodReturnsTheCorrespondingValueOfScope)
{
    uint16_t testServiceID = 1U;
    uint16_t testEventID = 2U;
    uint16_t testInstanceID = 3U;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testEventID, testInstanceID);

    serviceDescription1.setInternal();

    EXPECT_EQ(serviceDescription1.getScope(), Scope::INTERNAL);
}

TEST_F(ServiceDescription_test,
       ServiceDescriptionIsInvalidWhen_m_hasServiceOnlyDescriptionIsTrueAndServiceStringIsInvalid)
{
    testService = iox::capro::InvalidIDString;
    testInstance = "validinstance";

    ServiceDescription serviceDescription1 = ServiceDescription(testService, testInstance);

    EXPECT_FALSE(serviceDescription1.isValid());
}

TEST_F(ServiceDescription_test,
       ServiceDescriptionIsInvalidWhen_m_hasServiceOnlyDescriptionIsTrueAndServiceIDIsAnyService)
{
    uint16_t testServiceID = iox::capro::AnyService;
    uint16_t testInstanceID = iox::capro::AnyInstance;

    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testInstanceID);

    EXPECT_FALSE(serviceDescription1.isValid());
}

TEST_F(ServiceDescription_test,
       ServiceDescriptionIsInvalidWhen_m_hasServiceOnlyDescriptionIsTrueAndInstanceStringIsInvalid)
{
    testService = "validservice";
    testInstance = iox::capro::InvalidIDString;

    ServiceDescription serviceDescription1 = ServiceDescription(testService, testInstance);

    EXPECT_FALSE(serviceDescription1.isValid());
}

TEST_F(ServiceDescription_test,
       ServiceDescriptionIsInvalidWhen_m_hasServiceOnlyDescriptionIsTrueAndInstanceIDIsAnyInstance)
{
    uint16_t testServiceID = 1U;
    uint16_t testInstanceID = iox::capro::AnyInstance;

    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testInstanceID);

    EXPECT_FALSE(serviceDescription1.isValid());
}

TEST_F(ServiceDescription_test,
       ServiceDescriptionIsValidWhen_m_hasServiceOnlyDescriptionIsTrueAndServiceAndInstanceAreValid)
{
    uint16_t testServiceID = 1U;
    uint16_t testInstanceID = 2U;

    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testInstanceID);

    EXPECT_TRUE(serviceDescription1.isValid());
}

TEST_F(ServiceDescription_test, ServiceDescriptionIsInvalidWhen_m_hasServiceOnlyDescriptionIsFalseAndServiceIDIsInvalid)
{
    uint16_t testServiceID = 0U;
    uint16_t testEventID = 1U;
    uint16_t testInstanceID = 1U;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testEventID, testInstanceID);

    EXPECT_FALSE(serviceDescription1.isValid());
}

TEST_F(ServiceDescription_test,
       ServiceDescriptionIsInvalidWhen_m_hasServiceOnlyDescriptionIsFalseAndServiceIDIsAnyService)
{
    uint16_t testServiceID = iox::capro::AnyService;
    uint16_t testEventID = 1U;
    uint16_t testInstanceID = 1U;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testEventID, testInstanceID);

    EXPECT_FALSE(serviceDescription1.isValid());
}

TEST_F(ServiceDescription_test,
       ServiceDescriptionIsInvalidWhen_m_hasServiceOnlyDescriptionIsFalseAndInstanceIDIsInvalid)
{
    uint16_t testServiceID = 1U;
    uint16_t testEventID = 1U;
    uint16_t testInstanceID = 0U;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testEventID, testInstanceID);

    EXPECT_FALSE(serviceDescription1.isValid());
}

TEST_F(ServiceDescription_test,
       ServiceDescriptionIsInvalidWhen_m_hasServiceOnlyDescriptionIsFalseAndInstanceIDIsAnyInstance)
{
    uint16_t testServiceID = 1U;
    uint16_t testEventID = 1U;
    uint16_t testInstanceID = iox::capro::AnyInstance;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testEventID, testInstanceID);

    EXPECT_FALSE(serviceDescription1.isValid());
}

TEST_F(ServiceDescription_test, ServiceDescriptionIsInvalidWhen_m_hasServiceOnlyDescriptionIsFalseAndEventIDIsInvalid)
{
    uint16_t testServiceID = 1U;
    uint16_t testEventID = 0U;
    uint16_t testInstanceID = 1U;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testEventID, testInstanceID);

    EXPECT_FALSE(serviceDescription1.isValid());
}

TEST_F(ServiceDescription_test, ServiceDescriptionIsInvalidWhen_m_hasServiceOnlyDescriptionIsFalseAndEventIDIsAnyEvent)
{
    uint16_t testServiceID = 1U;
    uint16_t testEventID = iox::capro::AnyEvent;
    uint16_t testInstanceID = 1U;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testEventID, testInstanceID);

    EXPECT_FALSE(serviceDescription1.isValid());
}

TEST_F(ServiceDescription_test,
       ServiceDescriptionIsValidWhen_m_hasServiceOnlyDescriptionIsFalseAndServiceInstanceAndEventIDsAreValid)
{
    uint16_t testServiceID = 1U;
    uint16_t testEventID = 1U;
    uint16_t testInstanceID = 1U;
    ServiceDescription serviceDescription1 = ServiceDescription(testServiceID, testEventID, testInstanceID);

    EXPECT_TRUE(serviceDescription1.isValid());
}

TEST_F(ServiceDescription_test, LessThanOperatorReturnsFalseIfServiceStringOfFirstServiceDescriptionIsLessThanSecond)
{
    ServiceDescription serviceDescription1("TestService1", "TestInstance", "TestEvent");
    ServiceDescription serviceDescription2("TestService2", "TestInstance", "TestEvent");

    EXPECT_FALSE(serviceDescription1 < serviceDescription2);
}

TEST_F(ServiceDescription_test, LessThanOperatorReturnsFalseIfInstanceStringOfFirstServiceDescriptionIsLessThanSecond)
{
    ServiceDescription serviceDescription1("TestService", "TestInstance1", "TestEvent");
    ServiceDescription serviceDescription2("TestService", "TestInstance2", "TestEvent");

    EXPECT_FALSE(serviceDescription1 < serviceDescription2);
}

TEST_F(ServiceDescription_test, LessThanOperatorReturnsFalseIfEventStringOfFirstServiceDescriptionIsLessThanSecond)
{
    ServiceDescription serviceDescription1("TestService", "TestInstance", "TestEvent1");
    ServiceDescription serviceDescription2("TestService", "TestInstance", "TestEvent2");

    EXPECT_FALSE(serviceDescription1 < serviceDescription2);
}

/// END SERVICEDESCRIPTION TESTS
