blob: a763aa1bdd79dfc1e68e715ccda1860cb7076532 [file] [log] [blame]
// Copyright 2024 Google LLC
//
// 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.
#include "message_file_unittest.hpp"
#include <cstring>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace std::literals;
using ::testing::_;
using ::testing::Args;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::SetErrnoAndReturn;
using ::testing::StrEq;
using ::testing::WithArgs;
using google::hoth::MessageFile;
auto static const test_str = "Hello, world!"s;
std::vector<uint8_t> static const test_buf(test_str.begin(), test_str.end());
auto static const test2_str = "Good morning, world!"s;
std::vector<uint8_t> static const test2_buf(test2_str.begin(), test2_str.end());
auto static const test3_str = "Creative test string"s;
std::vector<uint8_t> static const test3_buf(test3_str.begin(), test3_str.end());
MATCHER_P(BufEq, buf, "")
{
return std::get<1>(arg) == buf.size() &&
!memcmp(std::get<0>(arg), buf.data(), buf.size());
}
ACTION_P(BufSet, buf)
{
size_t count = std::min(arg1, buf.size());
memcpy(arg0, buf.data(), count);
return count;
}
TEST_F(MessageFileTest, open)
{}
TEST_F(MessageFileTest, openFail)
{
EXPECT_CALL(sys, open(StrEq(TEST_PATH), O_RDWR))
.WillOnce(SetErrnoAndReturn(ENOENT, -1));
EXPECT_THROW(MessageFile(std::string(TEST_PATH), &sys), std::exception);
}
TEST_F(MessageFileTest, sendBuf)
{
EXPECT_CALL(sys, lseek(TEST_FD, 0, SEEK_SET));
EXPECT_CALL(sys, write(TEST_FD, NotNull(), _))
.With(Args<1, 2>(BufEq(test_buf)))
.WillOnce(Return(test_buf.size()));
file->send(test_buf.data(), test_buf.size(), 0);
}
TEST_F(MessageFileTest, sendLseekFail)
{
EXPECT_CALL(sys, lseek(TEST_FD, 0, SEEK_SET))
.WillOnce(SetErrnoAndReturn(EBADF, -1));
EXPECT_THROW(file->send(test_buf.data(), test_buf.size(), 0),
std::exception);
}
TEST_F(MessageFileTest, sendWriteFail)
{
EXPECT_CALL(sys, lseek(TEST_FD, 0, SEEK_SET));
EXPECT_CALL(sys, write(TEST_FD, NotNull(), _))
.With(Args<1, 2>(BufEq(test_buf)))
.WillOnce(SetErrnoAndReturn(EIO, -1));
EXPECT_THROW(file->send(test_buf.data(), test_buf.size(), 0),
std::exception);
}
TEST_F(MessageFileTest, sendWriteTooSmall)
{
EXPECT_CALL(sys, lseek(TEST_FD, 0, SEEK_SET));
EXPECT_CALL(sys, write(TEST_FD, NotNull(), _))
.With(Args<1, 2>(BufEq(test_buf)))
.WillOnce(Return(test_buf.size() - 1));
EXPECT_THROW(file->send(test_buf.data(), test_buf.size(), 0),
std::exception);
}
TEST_F(MessageFileTest, sendInterrupted)
{
EXPECT_CALL(sys, lseek(TEST_FD, 0, SEEK_SET));
EXPECT_CALL(sys, write(TEST_FD, NotNull(), _))
.With(Args<1, 2>(BufEq(test_buf)))
.WillOnce(SetErrnoAndReturn(EINTR, -1))
.WillOnce(SetErrnoAndReturn(EINTR, -1))
.WillOnce(SetErrnoAndReturn(EINTR, -1))
.WillOnce(Return(test_buf.size()));
file->send(test_buf.data(), test_buf.size(), 0);
}
TEST_F(MessageFileTest, recvBuf)
{
EXPECT_CALL(sys, lseek(TEST_FD, 0, SEEK_SET));
EXPECT_CALL(sys, read(TEST_FD, NotNull(), _))
.WillOnce(WithArgs<1, 2>(BufSet(test_buf)));
std::vector<uint8_t> result(test_buf.size());
file->recv(result.data(), result.size(), 0);
EXPECT_EQ(test_buf, result);
}
TEST_F(MessageFileTest, recvSeek)
{
size_t seek = 1;
std::vector<uint8_t> trunc_buf(test_buf.cbegin() + static_cast<int64_t>(seek), test_buf.cend());
EXPECT_CALL(sys, lseek(TEST_FD, seek, SEEK_SET));
EXPECT_CALL(sys, read(TEST_FD, NotNull(), _))
.WillOnce(WithArgs<1, 2>(BufSet(trunc_buf)));
std::vector<uint8_t> result(trunc_buf.size());
file->recv(result.data(), result.size(), seek);
EXPECT_EQ(trunc_buf, result);
}
TEST_F(MessageFileTest, recvLseekFail)
{
EXPECT_CALL(sys, lseek(TEST_FD, 0, SEEK_SET))
.WillOnce(SetErrnoAndReturn(EBADF, -1));
EXPECT_THROW(file->recv(nullptr, 10, 0), std::exception);
}
TEST_F(MessageFileTest, recvReadFail)
{
EXPECT_CALL(sys, lseek(TEST_FD, 0, SEEK_SET));
EXPECT_CALL(sys, read(TEST_FD, NotNull(), _))
.WillOnce(SetErrnoAndReturn(EIO, -1));
std::vector<uint8_t> result(1);
EXPECT_THROW(file->recv(result.data(), result.size(), 0), std::exception);
}
TEST_F(MessageFileTest, recvInterrupted)
{
EXPECT_CALL(sys, lseek(TEST_FD, 0, SEEK_SET));
EXPECT_CALL(sys, read(TEST_FD, NotNull(), _))
.WillOnce(SetErrnoAndReturn(EINTR, -1))
.WillOnce(SetErrnoAndReturn(EINTR, -1))
.WillOnce(SetErrnoAndReturn(EINTR, -1))
.WillOnce(WithArgs<1, 2>(BufSet(test_buf)));
std::vector<uint8_t> result(test_buf.size());
file->recv(result.data(), result.size(), 0);
EXPECT_EQ(test_buf, result);
}
TEST_F(MessageFileTest, recvSplit)
{
std::vector<uint8_t> expected = test_buf;
expected.insert(expected.end(), test2_buf.begin(), test2_buf.end());
expected.insert(expected.end(), test3_buf.begin(), test3_buf.end());
EXPECT_CALL(sys, lseek(TEST_FD, 0, SEEK_SET));
EXPECT_CALL(sys, read(TEST_FD, NotNull(), _))
.WillOnce(WithArgs<1, 2>(BufSet(test_buf)))
.WillOnce(WithArgs<1, 2>(BufSet(test2_buf)))
.WillOnce(WithArgs<1, 2>(BufSet(test3_buf)));
std::vector<uint8_t> result(expected.size());
file->recv(result.data(), result.size(), 0);
EXPECT_EQ(expected, result);
}