/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ #ifndef LIBCMOCKS_H_ #define LIBCMOCKS_H_ #include #include #include #include #include #include "MocksBase.h" #include "LibCSymTable.h" #include "ThreadingUtil.h" // ***************************************************************************** // gethostbyname class Mock_gethostbyname: public Mock { public: struct HostEntry: public hostent { HostEntry(const char* hostName,short addrtype); ~HostEntry(); HostEntry& addAlias(const char* alias); HostEntry& addAddress(const char* addr4); }; Mock_gethostbyname():current(0){mock_=this;} virtual ~Mock_gethostbyname(); HostEntry& addHostEntry(const char* hostName,short addrtype=AF_INET); virtual hostent* call(const char* name); typedef std::vector HostEntryCollection; HostEntryCollection gethostbynameReturns; int current; static Mock_gethostbyname* mock_; }; class MockFailed_gethostbyname: public Mock_gethostbyname { public: MockFailed_gethostbyname():h_errnoReturn(HOST_NOT_FOUND) {} int h_errnoReturn; virtual hostent* call(const char* name) { h_errno=h_errnoReturn; return 0; } }; // ***************************************************************************** // calloc class Mock_calloc: public Mock { public: Mock_calloc():errnoOnFailure(ENOMEM),callsBeforeFailure(-1),counter(0) { mock_=this; } virtual ~Mock_calloc() {mock_=0;} int errnoOnFailure; int callsBeforeFailure; int counter; virtual void* call(size_t p1, size_t p2); static Mock_calloc* mock_; }; // ***************************************************************************** // realloc class Mock_realloc: public Mock { public: Mock_realloc():errnoOnFailure(ENOMEM),callsBeforeFailure(-1),counter(0) { mock_=this; } virtual ~Mock_realloc() {mock_=0;} int errnoOnFailure; int callsBeforeFailure; int counter; virtual void* call(void* p, size_t s); static Mock_realloc* mock_; }; // ***************************************************************************** // random class Mock_random: public Mock { public: Mock_random():currentIdx(0) {mock_=this;} virtual ~Mock_random() {mock_=0;} int currentIdx; std::vector randomReturns; virtual int call(); void setSeed(unsigned long){currentIdx=0;} static Mock_random* mock_; }; // ***************************************************************************** // no-op free; keeps track of all deallocation requests class Mock_free_noop: public Mock { Mutex mx; std::vector requested; public: Mock_free_noop():nested(0),callCounter(0){mock_=this;} virtual ~Mock_free_noop(){ mock_=0; freeRequested(); } int nested; int callCounter; virtual void call(void* p); void freeRequested(); void disable(){mock_=0;} // returns number of times the pointer was freed int getFreeCount(void*); bool isFreed(void*); static Mock_free_noop* mock_; }; // ***************************************************************************** // socket and related system calls class Mock_socket: public Mock { public: static const int FD=63; Mock_socket():socketReturns(FD),closeReturns(0),getsocketoptReturns(0), optvalSO_ERROR(0), setsockoptReturns(0),connectReturns(0),connectErrno(0), sendErrno(0),recvErrno(0) { mock_=this; } virtual ~Mock_socket(){mock_=0;} int socketReturns; virtual int callSocket(int domain, int type, int protocol){ return socketReturns; } int closeReturns; virtual int callClose(int fd){ return closeReturns; } int getsocketoptReturns; int optvalSO_ERROR; virtual int callGet(int s,int level,int optname,void *optval,socklen_t *len){ if(level==SOL_SOCKET && optname==SO_ERROR){ setSO_ERROR(optval,*len); } return getsocketoptReturns; } virtual void setSO_ERROR(void *optval,socklen_t len){ memcpy(optval,&optvalSO_ERROR,len); } int setsockoptReturns; virtual int callSet(int s,int level,int optname,const void *optval,socklen_t len){ return setsockoptReturns; } int connectReturns; int connectErrno; virtual int callConnect(int s,const struct sockaddr *addr,socklen_t len){ errno=connectErrno; return connectReturns; } virtual void notifyBufferSent(const std::string& buffer){} int sendErrno; std::string sendBuffer; virtual ssize_t callSend(int s,const void *buf,size_t len,int flags){ if(sendErrno!=0){ errno=sendErrno; return -1; } // first call to send() is always the length of the buffer to follow bool sendingLength=sendBuffer.size()==0; // overwrite the length bytes sendBuffer.assign((const char*)buf,len); if(!sendingLength){ notifyBufferSent(sendBuffer); sendBuffer.erase(); } return len; } int recvErrno; std::string recvReturnBuffer; virtual ssize_t callRecv(int s,void *buf,size_t len,int flags){ if(recvErrno!=0){ errno=recvErrno; return -1; } int k=std::min(len,recvReturnBuffer.length()); if(k==0) return 0; memcpy(buf,recvReturnBuffer.data(),k); recvReturnBuffer.erase(0,k); return k; } virtual bool hasMoreRecv() const{ return recvReturnBuffer.size()!=0; } static Mock_socket* mock_; }; // ***************************************************************************** // fcntl class Mock_fcntl: public Mock { public: Mock_fcntl():callReturns(0),trapFD(-1){mock_=this;} ~Mock_fcntl(){mock_=0;} int callReturns; int trapFD; virtual int call(int fd, int cmd, void* arg){ if(trapFD==-1) return LIBC_SYMBOLS.fcntl(fd,cmd,arg); return callReturns; } static Mock_fcntl* mock_; }; // ***************************************************************************** // select class Mock_select: public Mock { public: Mock_select(Mock_socket* s,int fd):sock(s), callReturns(0),myFD(fd),timeout(50) { mock_=this; } ~Mock_select(){mock_=0;} Mock_socket* sock; int callReturns; int myFD; int timeout; //in millis virtual int call(int nfds,fd_set *rfds,fd_set *wfds,fd_set *efds,struct timeval *tv){ bool isWritableRequested=(wfds && FD_ISSET(myFD,wfds)); if(rfds) FD_CLR(myFD,rfds); if(wfds) FD_CLR(myFD,wfds); // this timeout is only to prevent a tight loop timeval myTimeout={0,0}; if(!isWritableRequested && !isFDReadable()){ myTimeout.tv_sec=timeout/1000; myTimeout.tv_usec=(timeout%1000)*1000; } LIBC_SYMBOLS.select(nfds,rfds,wfds,efds,&myTimeout); // myFD is always writable if(isWritableRequested) FD_SET(myFD,wfds); // myFD is only readable if the socket has anything to read if(isFDReadable() && rfds) FD_SET(myFD,rfds); return callReturns; } virtual bool isFDReadable() const { return sock->hasMoreRecv(); } static Mock_select* mock_; }; // ***************************************************************************** // poll // the last element of the pollfd array is expected to be test FD class Mock_poll: public Mock { public: Mock_poll(Mock_socket* s,int fd):sock(s), callReturns(1),myFD(fd),timeout(50) { mock_=this; } ~Mock_poll(){mock_=0;} Mock_socket* sock; int callReturns; int myFD; int timeout; //in millis virtual int call(struct pollfd *fds, POLL_NFDS_TYPE nfds, int to) { pollfd* myPoll=0; if(fds[nfds-1].fd==myFD) myPoll=&fds[nfds-1]; bool isWritableRequested=false; if(myPoll!=0){ isWritableRequested=myPoll->events&POLLOUT; nfds--; } LIBC_SYMBOLS.poll(fds,nfds,(!isWritableRequested&&!isFDReadable())?timeout:0); if(myPoll!=0){ // myFD is always writable if requested myPoll->revents=isWritableRequested?POLLOUT:0; // myFD is only readable if the socket has anything to read myPoll->revents|=isFDReadable()?POLLIN:0; } return callReturns; } virtual bool isFDReadable() const { return sock->hasMoreRecv(); } static Mock_poll* mock_; }; // ***************************************************************************** // gettimeofday class Mock_gettimeofday: public Mock { public: Mock_gettimeofday(){ LIBC_SYMBOLS.gettimeofday(&tv,0); mock_=this; } Mock_gettimeofday(const Mock_gettimeofday& other):tv(other.tv){} Mock_gettimeofday(int32_t sec,int32_t usec){ tv.tv_sec=sec; tv.tv_usec=usec; } ~Mock_gettimeofday(){mock_=0;} timeval tv; virtual int call(struct timeval *tp, GETTIMEOFDAY_ARG2_TYPE tzp){ *tp=tv; return 0; } operator timeval() const{ return tv; } // advance secs virtual void tick(int howmuch=1){tv.tv_sec+=howmuch;} // advance milliseconds // can move the clock forward as well as backward by providing a negative // number virtual void millitick(int howmuch=1){ int ms=tv.tv_usec/1000+howmuch; tv.tv_sec+=ms/1000; // going backward? if(ms<0){ ms=1000-(-ms%1000); //wrap millis around } tv.tv_usec=(ms%1000)*1000; } virtual void tick(const timeval& howmuch){ // add milliseconds (discarding microsecond portion) long ms=tv.tv_usec/1000+howmuch.tv_usec/1000; tv.tv_sec+=howmuch.tv_sec+ms/1000; tv.tv_usec=(ms%1000)*1000; } static Mock_gettimeofday* mock_; }; // discard microseconds! inline bool operator==(const timeval& lhs, const timeval& rhs){ return rhs.tv_sec==lhs.tv_sec && rhs.tv_usec/1000==lhs.tv_usec/1000; } // simplistic implementation: no normalization, assume lhs >= rhs, // discarding microseconds inline timeval operator-(const timeval& lhs, const timeval& rhs){ timeval res; res.tv_sec=lhs.tv_sec-rhs.tv_sec; res.tv_usec=(lhs.tv_usec/1000-rhs.tv_usec/1000)*1000; if(res.tv_usec<0){ res.tv_sec--; res.tv_usec=1000000+res.tv_usec%1000000; // wrap the millis around } return res; } inline int32_t toMilliseconds(const timeval& tv){ return tv.tv_sec*1000+tv.tv_usec/1000; } #endif /*LIBCMOCKS_H_*/