|  | /* | 
|  | * 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 = fd2; | 
|  | const Fd fd4(8); | 
|  | const Fd fd5(fd4); | 
|  | const Fd fd6 = fd5; | 
|  | 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)); | 
|  | // NOLINTNEXTLINE bugprone-use-after-move | 
|  | 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); | 
|  | // NOLINTNEXTLINE bugprone-use-after-move | 
|  | EXPECT_FALSE(isWellFormed(u1)); | 
|  | EXPECT_TRUE(isWellFormed(u2)); | 
|  | UniqueFd u3; | 
|  | u3 = std::move(u2); | 
|  | // NOLINTNEXTLINE bugprone-use-after-move | 
|  | 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 |