diff --git a/src/test/unittests/synergy/ProtocolUtilTests.cpp b/src/test/unittests/synergy/ProtocolUtilTests.cpp new file mode 100644 index 000000000..9fd56b353 --- /dev/null +++ b/src/test/unittests/synergy/ProtocolUtilTests.cpp @@ -0,0 +1,383 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2014-2020 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "test/global/gtest.h" +#include "test/mock/io/MockStream.h" +#include "synergy/ProtocolUtil.h" + +using ::testing::_; +using ::testing::Return; +using ::testing::DoAll; +using ::testing::SetArgPointee; +using ::testing::Eq; +using ::testing::StrEq; +using ::testing::TypedEq; + +ACTION_P2(SetValueToVoidPointerArg0, value, size) +{ + memcpy(arg0, value, size); +} + +ACTION(ThrowBadAlloc) +{ + throw std::bad_alloc(); +} + +TEST(ProtocolUtilTests, readf__XIOEndOfStream_exception) +{ + std::string Data; + MockStream stream; + ON_CALL(stream, read(_, _)).WillByDefault(Return(0)); + + EXPECT_FALSE(ProtocolUtil::readf(&stream, "%s", &Data)); + EXPECT_TRUE(Data.empty()); +} + +TEST(ProtocolUtilTests, readf_XIOReadMismatch_exception) +{ + std::string Data; + MockStream stream; + EXPECT_CALL(stream, read(_, _)) + .WillOnce(DoAll(SetValueToVoidPointerArg0("b", 1), Return(1))); + + EXPECT_FALSE(ProtocolUtil::readf(&stream, "a%s", &Data)); + EXPECT_TRUE(Data.empty()); +} + +TEST(ProtocolUtilTests, readf_bad_alloc_exception) +{ + std::string Data; + MockStream stream; + ON_CALL(stream, read(_, _)).WillByDefault(ThrowBadAlloc()); + + EXPECT_FALSE(ProtocolUtil::readf(&stream, "a%s", &Data)); + EXPECT_TRUE(Data.empty()); +} + +TEST(ProtocolUtilTests, readf_asserts) +{ + MockStream stream; + std::string Data; + ASSERT_DEBUG_DEATH( + {ProtocolUtil::readf(&stream, "%x", &Data);}, + "invalid format specifier" + ); + + ASSERT_DEBUG_DEATH( + {ProtocolUtil::readf(NULL, "%s", &Data);}, + "" + ); + + ASSERT_DEBUG_DEATH( + {ProtocolUtil::readf(&stream, NULL, &Data);}, + "" + ); + + ASSERT_DEBUG_DEATH( + {ProtocolUtil::readf(&stream, "%5i", &Data);}, + "length to be read is wrong:" + ); + + ASSERT_DEBUG_DEATH( + {ProtocolUtil::readf(&stream, "%5I", &Data);}, + "" + ); +} + +TEST(ProtocolUtilTests, readf_string) +{ + std::string Data; + const std::string Expected = "expected string"; + const UInt8 Length = Expected.length(); + UInt8 Size[4] = {0,0,0,Length}; + + MockStream stream; + EXPECT_CALL(stream, read(_, _)) + .WillOnce( + DoAll( + SetValueToVoidPointerArg0(&Size, sizeof(Size)), + Return(sizeof(Size)) + ) + ) + .WillOnce( + DoAll( + SetValueToVoidPointerArg0(Expected.c_str(), Expected.length()), + Return(Expected.length()) + ) + ); + + EXPECT_TRUE(ProtocolUtil::readf(&stream, "%s", &Data)); + EXPECT_EQ(Expected, Data); +} + +TEST(ProtocolUtilTests, readf_string_200) +{ + std::string Data; + const std::string Expected(200, 'x'); + const UInt8 Length = Expected.length(); + UInt8 Size[4] = {0,0,0,Length}; + + MockStream stream; + EXPECT_CALL(stream, read(_, _)) + .WillOnce( + DoAll( + SetValueToVoidPointerArg0(&Size, sizeof(Size)), + Return(sizeof(Size)) + ) + ) + .WillOnce( + DoAll( + SetValueToVoidPointerArg0(Expected.c_str(), Expected.length()), + Return(Expected.length()) + ) + ); + + EXPECT_TRUE(ProtocolUtil::readf(&stream, "%s", &Data)); + EXPECT_EQ(Expected, Data); +} + +class ReadfIntTestFixture : public ::testing::TestWithParam< std::tuple > +{ +protected: + UInt8 StreamData1Byte[1] = {10}; + UInt8 StreamData2Bytes[2] = {0, 10}; + UInt8 StreamData4Bytes[4] = {0, 0, 0, 10}; + + UInt8* getStreamData(int size) + { + UInt8* StreamData = nullptr; + switch(size){ + case 2: + StreamData = StreamData2Bytes; + break; + case 4: + StreamData = StreamData4Bytes; + break; + default: + StreamData = StreamData1Byte; + break; + } + return StreamData; + } +}; + +TEST_P(ReadfIntTestFixture, readf_int) +{ + int Actual = 0; + const int Expected = 10; + const char* Format = std::get<0>(GetParam()); + int StreamDataSize = std::get<1>(GetParam()); + UInt8* StreamData = getStreamData(StreamDataSize); + + MockStream stream; + ON_CALL(stream, read(_, _)) + .WillByDefault( + DoAll( + SetValueToVoidPointerArg0(StreamData, StreamDataSize), + Return(StreamDataSize) + ) + ); + + EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &Actual)); + EXPECT_EQ(Expected, Actual); +} + +INSTANTIATE_TEST_CASE_P( + ReadfIntTests, + ReadfIntTestFixture, + ::testing::Values( + std::make_tuple("%1i", 1), + std::make_tuple("%2i", 2), + std::make_tuple("%4i", 4))); + +class ReadfIntVectorTestFixture : public ReadfIntTestFixture +{ +}; + +TEST_P(ReadfIntVectorTestFixture, readf_int_vector) +{ + std::vector Actual1Byte = {}; + std::vector Actual2Bytes = {}; + std::vector Actual4Bytes = {}; + + const std::vector Expected1Byte = {10,10}; + const std::vector Expected2Bytes = {10,10}; + const std::vector Expected4Bytes = {10,10}; + UInt8 StreamVectorSize[4] = {0,0,0,2}; + + const char* Format = std::get<0>(GetParam()); + int StreamDataSize = std::get<1>(GetParam()); + UInt8* StreamData = getStreamData(StreamDataSize); + + MockStream stream; + EXPECT_CALL(stream, read(_, _)) + .WillOnce( + DoAll( + SetValueToVoidPointerArg0(&StreamVectorSize, sizeof (StreamVectorSize)), + Return(sizeof (StreamVectorSize)) + ) + ) + .WillRepeatedly( + DoAll( + SetValueToVoidPointerArg0(StreamData, StreamDataSize), + Return(StreamDataSize) + )); + + switch(StreamDataSize){ + case 2: + EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &Actual2Bytes)); + EXPECT_EQ(Expected2Bytes, Actual2Bytes); + break; + case 4: + EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &Actual4Bytes)); + EXPECT_EQ(Expected4Bytes, Actual4Bytes); + break; + default: + EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &Actual1Byte)); + EXPECT_EQ(Expected1Byte, Actual1Byte); + break; + } +} + +INSTANTIATE_TEST_CASE_P( + ReadfIntVectorTests, + ReadfIntVectorTestFixture, + ::testing::Values( + std::make_tuple("%1I", 1), + std::make_tuple("%2I", 2), + std::make_tuple("%4I", 4))); + +TEST(ProtocolUtilTests, readf_int1byte_and_string) +{ + std::string ActualString; + const std::string ExpectedString(200, 'x'); + const UInt8 StringLength = ExpectedString.length(); + UInt8 Size[4] = {0,0,0,StringLength}; + + UInt8 ActualInt = 0; + const int ExpectedInt = 10; + UInt8 StreamIntData = ExpectedInt; + + MockStream stream; + EXPECT_CALL(stream, read(_, _)) + .WillOnce( + DoAll( + SetValueToVoidPointerArg0(&StreamIntData, sizeof(StreamIntData)), + Return(sizeof(StreamIntData)) + ) + ) + .WillOnce( + DoAll( + SetValueToVoidPointerArg0(&Size, sizeof(Size)), + Return(sizeof(Size)) + ) + ) + .WillOnce( + DoAll( + SetValueToVoidPointerArg0(ExpectedString.c_str(), ExpectedString.length()), + Return(ExpectedString.length()) + ) + ); + + EXPECT_TRUE(ProtocolUtil::readf(&stream, "%1i%s", &ActualInt, &ActualString)); + EXPECT_EQ(ExpectedString, ActualString); + EXPECT_EQ(ExpectedInt, ActualInt); +} + +TEST(ProtocolUtilTests, readf_int2byte_and_string) +{ + std::string ActualString; + const std::string ExpectedString(200, 'x'); + const UInt8 StringLength = ExpectedString.length(); + UInt8 Size[4] = {0,0,0,StringLength}; + + UInt8 ActualInt = 0; + const int ExpectedInt = 10; + UInt8 StreamIntData[2] = {0, ExpectedInt}; + + MockStream stream; + EXPECT_CALL(stream, read(_, _)) + .WillOnce( + DoAll( + SetValueToVoidPointerArg0(&StreamIntData, sizeof(StreamIntData)), + Return(sizeof(StreamIntData)) + ) + ) + .WillOnce( + DoAll( + SetValueToVoidPointerArg0(&Size, sizeof(Size)), + Return(sizeof(Size)) + ) + ) + .WillOnce( + DoAll( + SetValueToVoidPointerArg0(ExpectedString.c_str(), ExpectedString.length()), + Return(ExpectedString.length()) + ) + ); + + EXPECT_TRUE(ProtocolUtil::readf(&stream, "%2i%s", &ActualInt, &ActualString)); + EXPECT_EQ(ExpectedString, ActualString); + EXPECT_EQ(ExpectedInt, ActualInt); +} + +TEST(ProtocolUtilTests, readf_int4byte_and_string) +{ + UInt8 ActualInt = 0; + const int ExpectedInt = 10; + UInt8 StreamIntData[4] = {0,0,0,ExpectedInt}; + + std::string ActualString; + const std::string ExpectedString(32768, 'x'); + UInt8 Size[4] = {0,0,128,0}; + + MockStream stream; + EXPECT_CALL(stream, read(_, _)) + .WillOnce( + DoAll( + SetValueToVoidPointerArg0(&StreamIntData, sizeof(StreamIntData)), + Return(sizeof(StreamIntData)) + ) + ) + .WillOnce( + DoAll( + SetValueToVoidPointerArg0(&Size, sizeof(Size)), + Return(sizeof(Size)) + ) + ) + .WillOnce( + DoAll( + SetValueToVoidPointerArg0(ExpectedString.c_str(), ExpectedString.length()), + Return(ExpectedString.length()) + ) + ); + + EXPECT_TRUE(ProtocolUtil::readf(&stream, "%4i%s", &ActualInt, &ActualString)); + EXPECT_EQ(ExpectedString, ActualString); + EXPECT_EQ(ExpectedInt, ActualInt); +} + + + + + + + + + + +