/*
* Copyright (C) 2017 The Android Open Source Project
*
* 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 <cstdint>
#include <gtest/gtest.h>
#include "netdutils/MockSyscalls.h"
#include "netdutils/Status.h"
#include "netdutils/Syscalls.h"
using testing::Mock;
using testing::Return;
using testing::StrictMock;
namespace android {
namespace netdutils {
namespace {
// Force implicit conversion from UniqueFd -> Fd
inline Fd toFd(const UniqueFd& fd) {
return fd;
}
} // namespace
TEST(Fd, smoke) {
// Expect the following lines to compile
Fd fd1(1);
Fd fd2(fd1);
Fd fd3 = fd1;
const Fd fd4(8);
const Fd fd5(fd4);
const Fd fd6 = fd4;
EXPECT_TRUE(isWellFormed(fd3));
EXPECT_TRUE(isWellFormed(fd6));
// Corner case
Fd zero(0);
EXPECT_TRUE(isWellFormed(zero));
// Invalid file descriptors
Fd bad(-1);
Fd weird(-9);
EXPECT_FALSE(isWellFormed(bad));
EXPECT_FALSE(isWellFormed(weird));
// Default constructor
EXPECT_EQ(Fd(-1), Fd());
std::stringstream ss;
ss << fd3 << " " << fd6 << " " << bad << " " << weird;
EXPECT_EQ("Fd[1] Fd[8] Fd[-1] Fd[-9]", ss.str());
}
class UniqueFdTest : public testing::Test {
protected:
StrictMock<ScopedMockSyscalls> mSyscalls;
};
TEST_F(UniqueFdTest, operatorOstream) {
UniqueFd u(97);
EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok));
std::stringstream ss;
ss << u;
EXPECT_EQ("UniqueFd[Fd[97]]", ss.str());
u.reset();
}
TEST_F(UniqueFdTest, destructor) {
{
UniqueFd u(98);
EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok));
}
// Expectation above should be upon leaving nested scope
Mock::VerifyAndClearExpectations(&mSyscalls);
}
TEST_F(UniqueFdTest, reset) {
UniqueFd u(99);
EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok));
u.reset();
// Expectation above should be upon reset
Mock::VerifyAndClearExpectations(&mSyscalls);
}
TEST_F(UniqueFdTest, moveConstructor) {
constexpr Fd kFd(101);
UniqueFd u1(kFd);
{
UniqueFd u2(std::move(u1));
EXPECT_FALSE(isWellFormed(u1));
EXPECT_TRUE(isWellFormed(u2));
EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok));
}
// Expectation above should be upon leaving nested scope
Mock::VerifyAndClearExpectations(&mSyscalls);
}
TEST_F(UniqueFdTest, moveAssignment) {
constexpr Fd kFd(102);
UniqueFd u1(kFd);
{
UniqueFd u2 = std::move(u1);
EXPECT_FALSE(isWellFormed(u1));
EXPECT_TRUE(isWellFormed(u2));
UniqueFd u3;
u3 = std::move(u2);
EXPECT_FALSE(isWellFormed(u2));
EXPECT_TRUE(isWellFormed(u3));
EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok));
}
// Expectation above should be upon leaving nested scope
Mock::VerifyAndClearExpectations(&mSyscalls);
}
TEST_F(UniqueFdTest, constConstructor) {
constexpr Fd kFd(103);
const UniqueFd u(kFd);
EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok));
}
TEST_F(UniqueFdTest, closeFailure) {
constexpr Fd kFd(103);
UniqueFd u(kFd);
EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(statusFromErrno(EINTR, "test")));
EXPECT_DEBUG_DEATH(u.reset(), "");
}
} // namespace netdutils
} // namespace android