hunting/test/utils/LinuxApiMock/src/LinuxTestImpl.cpp
2024-06-17 23:43:39 +08:00

174 lines
8.1 KiB
C++

/*
* Copyright (c) 2023 Fancy Code.
* 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 "LinuxTestImpl.h"
#include "GtestUsing.h"
#include "ILog.h"
#include "LinuxApiMock.h"
#include "WrapApi.h"
#include <bits/types/struct_timeval.h>
#include <gmock/gmock-spec-builders.h>
#include <memory>
#include <stdio.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <termios.h>
#include <thread>
/**
* @brief The simulated interface has been subjected to lock serial processing to ensure that the return value can be
* safely returned through multiple threads. However, this may affect the timing of the test code, which is not very
* reasonable. If the behavior of the simulated interface is redefined, the impact can be ignored.
* @param mock
*/
void LinuxTestImpl::ApiInit(std::shared_ptr<LinuxTest> &mock)
{
LogInfo("ApiInit\n");
static int openFd = -1;
auto api_open = [=](const char *pathname, int flags) {
LogInfo("Call __real_fx_open, pathname = %s.\n", pathname);
openFd = __real_fx_open(pathname, flags);
LogInfo("openFd = %d\n", openFd);
};
EXPECT_CALL(*mock.get(), fx_open(_, _))
.WillRepeatedly(
DoAll(Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
WithArgs<0, 1>(Invoke(api_open)),
Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiUnlockThread),
ReturnPointee(&openFd)));
static int resultTcgetattr = -1;
auto api_tcgetattr = [=](int fd, struct termios *termios_p) {
resultTcgetattr = __real_fx_tcgetattr(fd, termios_p);
LogInfo("resultTcgetattr = %d\n", resultTcgetattr);
};
EXPECT_CALL(*mock.get(), fx_tcgetattr(_, _))
.WillRepeatedly(
DoAll(Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
WithArgs<0, 1>(Invoke(api_tcgetattr)),
Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiUnlockThread),
ReturnPointee(&resultTcgetattr)));
static int resultTcsetattr = -1;
auto api_tcsetattr = [=](int fd, int optional_actions, const struct termios *termios_p) {
resultTcsetattr = __real_fx_tcsetattr(fd, optional_actions, termios_p);
LogInfo("resultTcsetattr = %d\n", resultTcsetattr);
};
EXPECT_CALL(*mock.get(), fx_tcsetattr(_, _, _))
.WillRepeatedly(
DoAll(Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
WithArgs<0, 1, 2>(Invoke(api_tcsetattr)),
Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiUnlockThread),
ReturnPointee(&resultTcsetattr)));
static int writeLength = -1;
auto api_write = [=](int fd, const void *buf, size_t count) {
writeLength = __real_fx_write(fd, buf, count);
LogInfo("writeLength = %d\n", writeLength);
};
EXPECT_CALL(*mock.get(), fx_write(_, _, _))
.WillRepeatedly(
DoAll(Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
WithArgs<0, 1, 2>(Invoke(api_write)),
Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiUnlockThread),
ReturnPointee(&writeLength)));
static int readLength = -1;
auto api_read = [=](int fd, void *buf, size_t count) {
readLength = __real_fx_read(fd, buf, count);
LogInfo("readLength = %d\n", readLength);
};
EXPECT_CALL(*mock.get(), fx_read(_, _, _))
.WillRepeatedly(
DoAll(Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
WithArgs<0, 1, 2>(Invoke(api_read)),
Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiUnlockThread),
ReturnPointee(&readLength)));
static int selectResult = -1;
auto api_select = [=](int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) {
selectResult = __real_fx_select(nfds, readfds, writefds, exceptfds, timeout);
LogInfo("selectResult = %d\n", selectResult);
};
EXPECT_CALL(*mock.get(), fx_select(_, _, _, _, _))
.WillRepeatedly(
DoAll(Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
WithArgs<0, 1, 2, 3, 4>(Invoke(api_select)),
Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiUnlockThread),
ReturnPointee(&selectResult)));
static int fstatResult = -1;
auto api_fstat = [=](int fd, struct stat *statbuf) {
LogInfo("Call __real_fx_fstat, fd = %d.\n", fd);
fstatResult = __real_fx_fstat(fd, statbuf);
LogInfo("fstatResult = %d\n", fstatResult);
};
EXPECT_CALL(*mock.get(), fx_fstat(_, _))
.WillRepeatedly(
DoAll(Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
WithArgs<0, 1>(Invoke(api_fstat)),
Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiUnlockThread),
ReturnPointee(&fstatResult)));
static int accessResult = -1;
auto api_access = [=](const char *pathname, int mode) {
accessResult = __real_fx_access(pathname, mode);
LogInfo("accessResult = %d\n", accessResult);
};
EXPECT_CALL(*mock.get(), fx_access(_, _))
.WillRepeatedly(
DoAll(Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
WithArgs<0, 1>(Invoke(api_access)),
Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiUnlockThread),
ReturnPointee(&accessResult)));
static FILE *fopenResult = nullptr;
auto api_fopen = [=](const char *pathname, const char *mode) {
fopenResult = __real_fx_fopen(pathname, mode);
};
EXPECT_CALL(*mock.get(), fx_fopen(_, _))
.WillRepeatedly(
DoAll(Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
WithArgs<0, 1>(Invoke(api_fopen)),
Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiUnlockThread),
ReturnPointee(&fopenResult)));
}
void LinuxTestImpl::Init()
{
}
void LinuxTestImpl::UnInit()
{
if (mApiThread.joinable()) {
mApiThread.join();
}
}
void LinuxTestImpl::ApiLock(void)
{
/**
* @brief This has been optimized and does not require locking; Place the lock position in the WrapApi file, and
* lock the Mock function to ensure that it returns the value of the global variable before it can return, to avoid
* the problem of obtaining incorrect return values due to multithreading timing errors.
*/
// mApiMutex.lock();
// LogInfo("lock api.\n");
}
void LinuxTestImpl::ApiUnlock(void)
{
// mApiMutex.unlock();
// LogInfo("unlock api.\n");
}
void LinuxTestImpl::ApiUnlockThread(void)
{
// LogInfo("ApiUnlockThread\n");
// if (mApiThread.joinable()) {
// mApiThread.join();
// }
// auto api_unlock = [](std::shared_ptr<LinuxTestImpl> test) {
// std::this_thread::sleep_for(std::chrono::milliseconds(API_LOCK_TIME_MS));
// test->ApiUnlock();
// };
// std::shared_ptr<LinuxTestImpl> test = std::dynamic_pointer_cast<LinuxTestImpl>(LinuxTest::shared_from_this());
// mApiThread = std::thread(api_unlock, test);
}