| /** |
| * 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 <string> |
| #include <vector> |
| #include <deque> |
| |
| #include <errno.h> |
| #include <string.h> |
| |
| #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<HostEntry*> 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<int> 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<void*> 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_*/ |