<commit_before>/*
 * Copyright (c) 2007-2010 Digital Bazaar, Inc. All rights reserved.
 */
#define __STDC_CONSTANT_MACROS

#include "monarch/net/SocketTools.h"

#include "monarch/net/WindowsSupport.h"
#include "monarch/rt/Thread.h"
#include "monarch/rt/System.h"

#include <limits.h>
#ifndef WIN32
#include <poll.h>
#endif

using namespace monarch::net;
using namespace monarch::rt;

#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 255
#endif

int SocketTools::poll(bool read, int fd, int64_t timeout)
{
#ifdef WIN32
   return select(read, fd, timeout);
#else
   int rval = 0;

   // create poll set
   struct pollfd fds;
   fds.fd = fd;
   fds.events = read ? POLLIN : POLLOUT;

   // "n" parameter is the highest numbered descriptor plus 1
   int n = fd + 1;

   // set 20 millisecond interrupt check timeout (currently necessary to
   // enable thread interruptions)
   int intck = INT32_C(20);

   // keep selecting (polling) until timeout is reached
   int64_t remaining = (timeout <= 0) ? intck : timeout;

   int to;
   if(timeout < 0)
   {
      // create instant timeout (polling)
      to = 0;
   }
   else
   {
      // create intck millisecond timeout
      to = (remaining < intck ? (int)remaining : intck);
   }

   uint64_t start = System::getCurrentMilliseconds();
   uint64_t end;

   Thread* t = Thread::currentThread();
   while(remaining > 0 && rval == 0 && !t->isInterrupted())
   {
      // wait for file descriptors to be updated
      rval = ::poll(&fds, n, to);

      // check for error events
      if(rval > 0)
      {
         // remote side hung up
         if(fds.revents & POLLHUP)
         {
            rval = -1;
            errno = EPIPE;
         }
         // file descriptor not open
         else if(fds.events & POLLNVAL)
         {
            rval = -1;
            errno = EBADF;
         }
         // error
         else if(fds.events & POLLERR)
         {
            // some kind of IO error
            rval = -1;
            errno = EIO;
         }
      }
      else if(rval == -1 && errno == EINTR)
      {
         // no error, syscall interrupted
         rval = 0;
      }

      // decrement timeout
      if(rval == 0 && timeout != 0)
      {
         // decrement remaining time
         end = System::getCurrentMilliseconds();
         remaining -= (end - start);
         start = end;
         to = (remaining < intck ? (int)remaining : intck);
      }
   }

   if(rval > 0)
   {
      if(t->isInterrupted())
      {
         rval = -1;
         errno = EINTR;

         // set interrupted exception
         ExceptionRef e = t->createInterruptedException();
         Exception::set(e);
      }
   }

   return rval;
#endif
}

#ifdef WIN32
int SocketTools::select(bool read, unsigned int fd, int64_t timeout)
#else
int SocketTools::select(bool read, int fd, int64_t timeout)
#endif
{
   int rval = 0;

   // create a file descriptor set to read on
   fd_set rfds;
   FD_ZERO(&rfds);

   // create a file descriptor set to write on
   fd_set wfds;
   FD_ZERO(&wfds);

   // create a file descriptor set to check for exceptions on
   fd_set exfds;
   FD_ZERO(&exfds);

   // add file descriptor to sets
   FD_SET(fd, &rfds);
   FD_SET(fd, &wfds);
   FD_SET(fd, &exfds);

   // "n" parameter is the highest numbered descriptor plus 1
#ifdef WIN32
   unsigned int n = fd + 1;
#else
   int n = fd + 1;
#endif

   // set 20 millisecond interrupt check timeout (necessary because
   // windows lacks SIGNAL support to do interruptions properly)
   int64_t intck = INT64_C(20);

   // keep selecting (polling) until timeout is reached
   int64_t remaining = (timeout <= 0) ? intck : timeout;

   struct timeval to;
   to.tv_sec = 0;
   if(timeout < 0)
   {
      // create instant timeout (polling)
      to.tv_usec = 0;
   }
   else
   {
      // create intck millisecond timeout (1 millisecond is 1000 microseconds)
      to.tv_usec = (remaining < intck ? remaining : intck) * INT64_C(1000);
   }

   uint64_t start = System::getCurrentMilliseconds();
   uint64_t end;

   Thread* t = Thread::currentThread();
   while(remaining > 0 && rval == 0 && !t->isInterrupted())
   {
      // wait for file descriptors to be updated
      if(read)
      {
         // wait for readability
         rval = ::select(n, &rfds, NULL, &exfds, &to);
      }
      else
      {
         // wait for readability and writability
         //
         // Note: We must test to see if the pipe is broken by
         // testing for readability -- as it will occur if the
         // connection closes due to TCP sending an RST to the
         // socket ... and this will cause recv() to return 0
         rval = ::select(n, &rfds, &wfds, &exfds, &to);
         if(rval > 0 && !FD_ISSET(fd, &wfds) && FD_ISSET(fd, &rfds))
         {
            // readability flag switched, check to see if the connection has
            // been shutdown, by seeing if recv() will return 0 (do a peek so
            // as not to disturb real data)
            char buf;
            int flags = MSG_PEEK;
#ifdef MSG_DONTWAIT
            flags |= MSG_DONTWAIT;
#endif
            rval = SOCKET_MACRO_recv(fd, &buf, 1, flags);
            if(rval == 0)
            {
               // connection closed
               rval = -1;
               errno = EPIPE;
            }
            else if(rval > 0)
            {
               // connection not closed, but write timed out/was not detected
               // (bytes are readable but we weren't looking for that)
               rval = 0;
            }
         }
      }

      if(rval < 0 && (errno == 0 || errno == EINPROGRESS || errno == EINTR))
      {
         // no error, just timed out, operation in progress,
         // or syscall interrupted
         rval = 0;

         // Note: handling EINTR could be changed to interrupt the current
         // thread if appropriate
      }

      // select() implementation may alter sets or timeout, so reset them
      // if calling select() again (not interrupted and timeout >= 0)
      if(rval == 0)
      {
         // clear sets and re-add file descriptor
         FD_ZERO(&rfds);
         FD_ZERO(&wfds);
         FD_ZERO(&exfds);
         FD_SET(fd, &rfds);
         FD_SET(fd, &wfds);
         FD_SET(fd, &exfds);

         // reset timeout
         to.tv_sec = 0;
         if(timeout < 0)
         {
            to.tv_usec = 0;
         }
         else
         {
            to.tv_usec = intck * INT64_C(1000);
         }
      }

      if(timeout != 0)
      {
         // decrement remaining time
         end = System::getCurrentMilliseconds();
         remaining -= (end - start);
         start = end;
         to.tv_usec = (remaining < intck ? remaining : intck) * INT64_C(1000);
      }
   }

   if(rval > 0)
   {
      if(t->isInterrupted())
      {
         rval = -1;
         errno = EINTR;

         // set interrupted exception
         ExceptionRef e = t->createInterruptedException();
         Exception::set(e);
      }
      else if(FD_ISSET(fd, &exfds) != 0)
      {
         // exception occurred with file descriptor, consider pipe broken,
         // cannot mark it as a bad file descriptor here or else it won't
         // be closed
         rval = -1;
         errno = EPIPE;
      }
   }

   return rval;
}

int SocketTools::select(
   int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds,
   int64_t timeout, const sigset_t* sigmask)
{
   int rval = 0;

// Note: disabled due to a lack of support in windows
//   // create timeout
//   struct timeval* tv = NULL;
//   struct timeval to;
//   if(timeout > 0)
//   {
//      // set timeout (1 millisecond is 1000 microseconds)
//      to.tv_sec = timeout / INT64_C(1000);
//      to.tv_usec = (timeout % INT64_C(1000)) * INT64_C(1000);
//      tv = &to;
//   }
//
//   // FIXME: signals supposedly don't make select() return in windows
//   // this needs to be tested and potentially remedied somehow
//
//   // FIXME: furthermore, even if we block SIGINT (interruption signal) up
//   // until we reach the select call -- and then unblock right before it
//   // the signal could still sneak in right before select() is called and
//   // control is transferred to the kernel, and therefore we'd handle the
//   // SIGINT before the select() call and select() wouldn't get interrupted
//   // (there is pselect() for doing that unblocking atomically, but
//   // it's UNIX only) -- this may be solved by writing to another file
//   // descriptor when we receive SIGINTs and checking that file descriptor
//   // as well as the one we are waiting on -- but this might not be a
//   // viable solution for windows
//
//   // block SIGINTs
//   blockSignal(SIGINT);
//
//   Thread* t = Thread::currentThread();
//   if(!t->isInterrupted())
//   {
//      // FIXME: pselect() required here to do atomic unblocking & selecting
//
//      // wait for file descriptors to be updated
//      unblockSignal(SIGINT);
//      rval = ::select(nfds, readfds, writefds, exceptfds, timeout);
//      if(rval < 0)
//      {
//         if(errno == EINTR)
//         {
//            // interrupt thread
//            t->interrupt();
//         }
//      }
//   }
//   else
//   {
//      rval = -1;
//      errno = EINTR;
//   }

   // clone file descriptor sets
   fd_set readfds2;
   fd_set writefds2;
   fd_set exceptfds2;

   if(readfds != NULL)
   {
      readfds2 = *readfds;
   }

   if(writefds != NULL)
   {
      writefds2 = *writefds;
   }

   if(exceptfds != NULL)
   {
      exceptfds2 = *exceptfds;
   }

   // set 20 millisecond interrupt check timeout (necessary because
   // windows lacks SIGNAL support to do interruptions properly)
   int64_t intck = INT64_C(20);

   // keep selecting (polling) until timeout is reached
   int64_t remaining = (timeout <= 0) ? intck : timeout;

   struct timeval to;
   if(timeout < 0)
   {
      // create instant timeout (polling)
      to.tv_sec = 0;
      to.tv_usec = 0;
   }
   else
   {
      // create 20 millisecond timeout (1 millisecond is 1000 microseconds)
      to.tv_sec = 0;
      to.tv_usec = (remaining < intck ? remaining : intck) * INT64_C(1000);
   }

   uint64_t start = System::getCurrentMilliseconds();
   uint64_t end;

   Thread* t = Thread::currentThread();
   while(remaining > 0 && rval == 0 && !t->isInterrupted())
   {
      // wait for file descriptors to be updated
      rval = ::select(nfds, readfds, writefds, exceptfds, &to);

      if(rval < 0 && (errno == 0 || errno == EINPROGRESS || errno == EINTR))
      {
         // no error, just timed out, operation in progress,
         // or syscall interrupted
         rval = 0;

         // Note: handling EINTR could be changed to interrupt the current
         // thread if appropriate
      }

      // select() implementation may alter sets or timeout, so reset them
      // if calling select() again (not interrupted and timeout >= 0)
      if(rval == 0 && timeout >= 0)
      {
         // reset file descriptor sets
         if(readfds != NULL)
         {
            *readfds = readfds2;
         }

         if(writefds != NULL)
         {
            *writefds = writefds2;
         }

         if(exceptfds != NULL)
         {
            *exceptfds = exceptfds2;
         }

         // reset timeout
         to.tv_sec = 0;
         to.tv_usec = intck * INT64_C(1000);
      }

      if(timeout != 0)
      {
         // decrement remaining time
         end = System::getCurrentMilliseconds();
         remaining -= (end - start);
         start = end;
         to.tv_usec = (remaining < intck ? remaining : intck) * INT64_C(1000);
      }
   }

   if(t->isInterrupted())
   {
      rval = -1;
      errno = EINTR;

      // set interrupted exception
      ExceptionRef e = t->createInterruptedException();
      Exception::set(e);
   }

   return rval;
}

std::string SocketTools::getHostname()
{
   char tmp[HOST_NAME_MAX + 1];
   memset(tmp, 0, HOST_NAME_MAX + 1);
   gethostname(tmp, HOST_NAME_MAX);
   return tmp;
}
<commit_msg>Made sure to check revents, not events.<commit_after>/*
 * Copyright (c) 2007-2010 Digital Bazaar, Inc. All rights reserved.
 */
#define __STDC_CONSTANT_MACROS

#include "monarch/net/SocketTools.h"

#include "monarch/net/WindowsSupport.h"
#include "monarch/rt/Thread.h"
#include "monarch/rt/System.h"

#include <limits.h>
#ifndef WIN32
#include <poll.h>
#endif

using namespace monarch::net;
using namespace monarch::rt;

#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 255
#endif

int SocketTools::poll(bool read, int fd, int64_t timeout)
{
#ifdef WIN32
   return select(read, fd, timeout);
#else
   int rval = 0;

   // create poll set
   struct pollfd fds;
   fds.fd = fd;
   fds.events = read ? POLLIN : POLLOUT;

   // "n" parameter is the highest numbered descriptor plus 1
   int n = fd + 1;

   // set 20 millisecond interrupt check timeout (currently necessary to
   // enable thread interruptions)
   int intck = INT32_C(20);

   // keep selecting (polling) until timeout is reached
   int64_t remaining = (timeout <= 0) ? intck : timeout;

   int to;
   if(timeout < 0)
   {
      // create instant timeout (polling)
      to = 0;
   }
   else
   {
      // create intck millisecond timeout
      to = (remaining < intck ? (int)remaining : intck);
   }

   uint64_t start = System::getCurrentMilliseconds();
   uint64_t end;

   Thread* t = Thread::currentThread();
   while(remaining > 0 && rval == 0 && !t->isInterrupted())
   {
      // wait for file descriptors to be updated
      rval = ::poll(&fds, n, to);

      // check for error events
      if(rval > 0)
      {
         // remote side hung up
         if(fds.revents & POLLHUP)
         {
            rval = -1;
            errno = EPIPE;
         }
         // file descriptor not open
         else if(fds.revents & POLLNVAL)
         {
            rval = -1;
            errno = EBADF;
         }
         // error
         else if(fds.revents & POLLERR)
         {
            // some kind of IO error
            rval = -1;
            errno = EIO;
         }
      }
      else if(rval == -1 && errno == EINTR)
      {
         // no error, syscall interrupted
         rval = 0;
      }

      // decrement timeout
      if(rval == 0 && timeout != 0)
      {
         // decrement remaining time
         end = System::getCurrentMilliseconds();
         remaining -= (end - start);
         start = end;
         to = (remaining < intck ? (int)remaining : intck);
      }
   }

   if(rval > 0)
   {
      if(t->isInterrupted())
      {
         rval = -1;
         errno = EINTR;

         // set interrupted exception
         ExceptionRef e = t->createInterruptedException();
         Exception::set(e);
      }
   }

   return rval;
#endif
}

#ifdef WIN32
int SocketTools::select(bool read, unsigned int fd, int64_t timeout)
#else
int SocketTools::select(bool read, int fd, int64_t timeout)
#endif
{
   int rval = 0;

   // create a file descriptor set to read on
   fd_set rfds;
   FD_ZERO(&rfds);

   // create a file descriptor set to write on
   fd_set wfds;
   FD_ZERO(&wfds);

   // create a file descriptor set to check for exceptions on
   fd_set exfds;
   FD_ZERO(&exfds);

   // add file descriptor to sets
   FD_SET(fd, &rfds);
   FD_SET(fd, &wfds);
   FD_SET(fd, &exfds);

   // "n" parameter is the highest numbered descriptor plus 1
#ifdef WIN32
   unsigned int n = fd + 1;
#else
   int n = fd + 1;
#endif

   // set 20 millisecond interrupt check timeout (necessary because
   // windows lacks SIGNAL support to do interruptions properly)
   int64_t intck = INT64_C(20);

   // keep selecting (polling) until timeout is reached
   int64_t remaining = (timeout <= 0) ? intck : timeout;

   struct timeval to;
   to.tv_sec = 0;
   if(timeout < 0)
   {
      // create instant timeout (polling)
      to.tv_usec = 0;
   }
   else
   {
      // create intck millisecond timeout (1 millisecond is 1000 microseconds)
      to.tv_usec = (remaining < intck ? remaining : intck) * INT64_C(1000);
   }

   uint64_t start = System::getCurrentMilliseconds();
   uint64_t end;

   Thread* t = Thread::currentThread();
   while(remaining > 0 && rval == 0 && !t->isInterrupted())
   {
      // wait for file descriptors to be updated
      if(read)
      {
         // wait for readability
         rval = ::select(n, &rfds, NULL, &exfds, &to);
      }
      else
      {
         // wait for readability and writability
         //
         // Note: We must test to see if the pipe is broken by
         // testing for readability -- as it will occur if the
         // connection closes due to TCP sending an RST to the
         // socket ... and this will cause recv() to return 0
         rval = ::select(n, &rfds, &wfds, &exfds, &to);
         if(rval > 0 && !FD_ISSET(fd, &wfds) && FD_ISSET(fd, &rfds))
         {
            // readability flag switched, check to see if the connection has
            // been shutdown, by seeing if recv() will return 0 (do a peek so
            // as not to disturb real data)
            char buf;
            int flags = MSG_PEEK;
#ifdef MSG_DONTWAIT
            flags |= MSG_DONTWAIT;
#endif
            rval = SOCKET_MACRO_recv(fd, &buf, 1, flags);
            if(rval == 0)
            {
               // connection closed
               rval = -1;
               errno = EPIPE;
            }
            else if(rval > 0)
            {
               // connection not closed, but write timed out/was not detected
               // (bytes are readable but we weren't looking for that)
               rval = 0;
            }
         }
      }

      if(rval < 0 && (errno == 0 || errno == EINPROGRESS || errno == EINTR))
      {
         // no error, just timed out, operation in progress,
         // or syscall interrupted
         rval = 0;

         // Note: handling EINTR could be changed to interrupt the current
         // thread if appropriate
      }

      // select() implementation may alter sets or timeout, so reset them
      // if calling select() again (not interrupted and timeout >= 0)
      if(rval == 0)
      {
         // clear sets and re-add file descriptor
         FD_ZERO(&rfds);
         FD_ZERO(&wfds);
         FD_ZERO(&exfds);
         FD_SET(fd, &rfds);
         FD_SET(fd, &wfds);
         FD_SET(fd, &exfds);

         // reset timeout
         to.tv_sec = 0;
         if(timeout < 0)
         {
            to.tv_usec = 0;
         }
         else
         {
            to.tv_usec = intck * INT64_C(1000);
         }
      }

      if(timeout != 0)
      {
         // decrement remaining time
         end = System::getCurrentMilliseconds();
         remaining -= (end - start);
         start = end;
         to.tv_usec = (remaining < intck ? remaining : intck) * INT64_C(1000);
      }
   }

   if(rval > 0)
   {
      if(t->isInterrupted())
      {
         rval = -1;
         errno = EINTR;

         // set interrupted exception
         ExceptionRef e = t->createInterruptedException();
         Exception::set(e);
      }
      else if(FD_ISSET(fd, &exfds) != 0)
      {
         // exception occurred with file descriptor, consider pipe broken,
         // cannot mark it as a bad file descriptor here or else it won't
         // be closed
         rval = -1;
         errno = EPIPE;
      }
   }

   return rval;
}

int SocketTools::select(
   int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds,
   int64_t timeout, const sigset_t* sigmask)
{
   int rval = 0;

// Note: disabled due to a lack of support in windows
//   // create timeout
//   struct timeval* tv = NULL;
//   struct timeval to;
//   if(timeout > 0)
//   {
//      // set timeout (1 millisecond is 1000 microseconds)
//      to.tv_sec = timeout / INT64_C(1000);
//      to.tv_usec = (timeout % INT64_C(1000)) * INT64_C(1000);
//      tv = &to;
//   }
//
//   // FIXME: signals supposedly don't make select() return in windows
//   // this needs to be tested and potentially remedied somehow
//
//   // FIXME: furthermore, even if we block SIGINT (interruption signal) up
//   // until we reach the select call -- and then unblock right before it
//   // the signal could still sneak in right before select() is called and
//   // control is transferred to the kernel, and therefore we'd handle the
//   // SIGINT before the select() call and select() wouldn't get interrupted
//   // (there is pselect() for doing that unblocking atomically, but
//   // it's UNIX only) -- this may be solved by writing to another file
//   // descriptor when we receive SIGINTs and checking that file descriptor
//   // as well as the one we are waiting on -- but this might not be a
//   // viable solution for windows
//
//   // block SIGINTs
//   blockSignal(SIGINT);
//
//   Thread* t = Thread::currentThread();
//   if(!t->isInterrupted())
//   {
//      // FIXME: pselect() required here to do atomic unblocking & selecting
//
//      // wait for file descriptors to be updated
//      unblockSignal(SIGINT);
//      rval = ::select(nfds, readfds, writefds, exceptfds, timeout);
//      if(rval < 0)
//      {
//         if(errno == EINTR)
//         {
//            // interrupt thread
//            t->interrupt();
//         }
//      }
//   }
//   else
//   {
//      rval = -1;
//      errno = EINTR;
//   }

   // clone file descriptor sets
   fd_set readfds2;
   fd_set writefds2;
   fd_set exceptfds2;

   if(readfds != NULL)
   {
      readfds2 = *readfds;
   }

   if(writefds != NULL)
   {
      writefds2 = *writefds;
   }

   if(exceptfds != NULL)
   {
      exceptfds2 = *exceptfds;
   }

   // set 20 millisecond interrupt check timeout (necessary because
   // windows lacks SIGNAL support to do interruptions properly)
   int64_t intck = INT64_C(20);

   // keep selecting (polling) until timeout is reached
   int64_t remaining = (timeout <= 0) ? intck : timeout;

   struct timeval to;
   if(timeout < 0)
   {
      // create instant timeout (polling)
      to.tv_sec = 0;
      to.tv_usec = 0;
   }
   else
   {
      // create 20 millisecond timeout (1 millisecond is 1000 microseconds)
      to.tv_sec = 0;
      to.tv_usec = (remaining < intck ? remaining : intck) * INT64_C(1000);
   }

   uint64_t start = System::getCurrentMilliseconds();
   uint64_t end;

   Thread* t = Thread::currentThread();
   while(remaining > 0 && rval == 0 && !t->isInterrupted())
   {
      // wait for file descriptors to be updated
      rval = ::select(nfds, readfds, writefds, exceptfds, &to);

      if(rval < 0 && (errno == 0 || errno == EINPROGRESS || errno == EINTR))
      {
         // no error, just timed out, operation in progress,
         // or syscall interrupted
         rval = 0;

         // Note: handling EINTR could be changed to interrupt the current
         // thread if appropriate
      }

      // select() implementation may alter sets or timeout, so reset them
      // if calling select() again (not interrupted and timeout >= 0)
      if(rval == 0 && timeout >= 0)
      {
         // reset file descriptor sets
         if(readfds != NULL)
         {
            *readfds = readfds2;
         }

         if(writefds != NULL)
         {
            *writefds = writefds2;
         }

         if(exceptfds != NULL)
         {
            *exceptfds = exceptfds2;
         }

         // reset timeout
         to.tv_sec = 0;
         to.tv_usec = intck * INT64_C(1000);
      }

      if(timeout != 0)
      {
         // decrement remaining time
         end = System::getCurrentMilliseconds();
         remaining -= (end - start);
         start = end;
         to.tv_usec = (remaining < intck ? remaining : intck) * INT64_C(1000);
      }
   }

   if(t->isInterrupted())
   {
      rval = -1;
      errno = EINTR;

      // set interrupted exception
      ExceptionRef e = t->createInterruptedException();
      Exception::set(e);
   }

   return rval;
}

std::string SocketTools::getHostname()
{
   char tmp[HOST_NAME_MAX + 1];
   memset(tmp, 0, HOST_NAME_MAX + 1);
   gethostname(tmp, HOST_NAME_MAX);
   return tmp;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "test.hpp"
#include "setup_transfer.hpp"

#include "libtorrent/file_storage.hpp"

using namespace libtorrent;

void setup_test_storage(file_storage& st)
{
	st.add_file("test/a", 10000);
	st.add_file("test/b", 20000);
	st.add_file("test/c/a", 30000);
	st.add_file("test/c/b", 40000);

	st.set_piece_length(0x4000);
	st.set_num_pieces((st.total_size() + st.piece_length() - 1) / 0x4000);

	TEST_EQUAL(st.file_name(0), "a");
	TEST_EQUAL(st.file_name(1), "b");
	TEST_EQUAL(st.file_name(2), "a");
	TEST_EQUAL(st.file_name(3), "b");
	TEST_EQUAL(st.name(), "test");

	TEST_EQUAL(st.file_path(0), "test/a");
	TEST_EQUAL(st.file_path(1), "test/b");
	TEST_EQUAL(st.file_path(2), "test/c/a");
	TEST_EQUAL(st.file_path(3), "test/c/b");

	TEST_EQUAL(st.file_size(0), 10000);
	TEST_EQUAL(st.file_size(1), 20000);
	TEST_EQUAL(st.file_size(2), 30000);
	TEST_EQUAL(st.file_size(3), 40000);

	TEST_EQUAL(st.file_offset(0), 0);
	TEST_EQUAL(st.file_offset(1), 10000);
	TEST_EQUAL(st.file_offset(2), 30000);
	TEST_EQUAL(st.file_offset(3), 60000);

	TEST_EQUAL(st.total_size(), 100000);
	TEST_EQUAL(st.piece_length(), 0x4000);
	printf("%d\n", st.num_pieces());
	TEST_EQUAL(st.num_pieces(), (100000 + 0x3fff) / 0x4000);
}

int test_main()
{
	{
		file_storage st;
		setup_test_storage(st);

		st.rename_file(0, "test/c/d");
		TEST_EQUAL(st.file_path(0, "./"), "./test/c/d");

#ifdef TORRENT_WINDOWS
		st.rename_file(0, "c:\\tmp\\a");
		TEST_EQUAL(st.file_path(0, "."), "c:\\tmp\\a");
#else
		st.rename_file(0, "/tmp/a");
		TEST_EQUAL(st.file_path(0, "."), "/tmp/a");
#endif
	}

	{
		file_storage st;
		st.add_file("a", 10000);

		st.rename_file(0, "test/c/d");
		TEST_EQUAL(st.file_path(0, "./"), "./test/c/d");

#ifdef TORRENT_WINDOWS
		st.rename_file(0, "c:\\tmp\\a");
		TEST_EQUAL(st.file_path(0, "."), "c:\\tmp\\a");
#else
		st.rename_file(0, "/tmp/a");
		TEST_EQUAL(st.file_path(0, "."), "/tmp/a");
#endif
	}

	{
		file_storage fs;
		fs.set_piece_length(512);
		fs.add_file(combine_path("temp_storage", "test1.tmp"), 17);
		fs.add_file(combine_path("temp_storage", "test2.tmp"), 612);
		fs.add_file(combine_path("temp_storage", "test3.tmp"), 0);
		fs.add_file(combine_path("temp_storage", "test4.tmp"), 0);
		fs.add_file(combine_path("temp_storage", "test5.tmp"), 3253);
		// size: 3882
		fs.add_file(combine_path("temp_storage", "test6.tmp"), 841);
		// size: 4723

		peer_request rq = fs.map_file(0, 0, 10);
		TEST_EQUAL(rq.piece, 0);
		TEST_EQUAL(rq.start, 0);
		TEST_EQUAL(rq.length, 10);
		rq = fs.map_file(5, 0, 10);
		TEST_EQUAL(rq.piece, 7);
		TEST_EQUAL(rq.start, 298);
		TEST_EQUAL(rq.length, 10);
		rq = fs.map_file(5, 0, 1000);
		TEST_EQUAL(rq.piece, 7);
		TEST_EQUAL(rq.start, 298);
		TEST_EQUAL(rq.length, 841);
	}

	return 0;
}

<commit_msg>fix windows build of test_file_storage<commit_after>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "test.hpp"
#include "setup_transfer.hpp"

#include "libtorrent/file_storage.hpp"

using namespace libtorrent;

void setup_test_storage(file_storage& st)
{
	st.add_file("test/a", 10000);
	st.add_file("test/b", 20000);
	st.add_file("test/c/a", 30000);
	st.add_file("test/c/b", 40000);

	st.set_piece_length(0x4000);
	st.set_num_pieces((st.total_size() + st.piece_length() - 1) / 0x4000);

	TEST_EQUAL(st.file_name(0), "a");
	TEST_EQUAL(st.file_name(1), "b");
	TEST_EQUAL(st.file_name(2), "a");
	TEST_EQUAL(st.file_name(3), "b");
	TEST_EQUAL(st.name(), "test");

	TEST_EQUAL(st.file_path(0), combine_path("test", "a"));
	TEST_EQUAL(st.file_path(1), combine_path("test", "b"));
	TEST_EQUAL(st.file_path(2), combine_path("test", combine_path("c", "a")));
	TEST_EQUAL(st.file_path(3), combine_path("test", combine_path("c", "b")));

	TEST_EQUAL(st.file_size(0), 10000);
	TEST_EQUAL(st.file_size(1), 20000);
	TEST_EQUAL(st.file_size(2), 30000);
	TEST_EQUAL(st.file_size(3), 40000);

	TEST_EQUAL(st.file_offset(0), 0);
	TEST_EQUAL(st.file_offset(1), 10000);
	TEST_EQUAL(st.file_offset(2), 30000);
	TEST_EQUAL(st.file_offset(3), 60000);

	TEST_EQUAL(st.total_size(), 100000);
	TEST_EQUAL(st.piece_length(), 0x4000);
	printf("%d\n", st.num_pieces());
	TEST_EQUAL(st.num_pieces(), (100000 + 0x3fff) / 0x4000);
}

int test_main()
{
	{
		file_storage st;
		setup_test_storage(st);

		st.rename_file(0, combine_path("test", combine_path("c", "d")));
		TEST_EQUAL(st.file_path(0, "."), combine_path(".", combine_path("test", combine_path("c", "d"))));

#ifdef TORRENT_WINDOWS
		st.rename_file(0, "c:\\tmp\\a");
		TEST_EQUAL(st.file_path(0, "."), "c:\\tmp\\a");
#else
		st.rename_file(0, "/tmp/a");
		TEST_EQUAL(st.file_path(0, "."), "/tmp/a");
#endif
	}

	{
		file_storage st;
		st.add_file("a", 10000);

		st.rename_file(0, combine_path("test", combine_path("c", "d")));
		TEST_EQUAL(st.file_path(0, "."), combine_path(".", combine_path("test", combine_path("c", "d"))));

#ifdef TORRENT_WINDOWS
		st.rename_file(0, "c:\\tmp\\a");
		TEST_EQUAL(st.file_path(0, "."), "c:\\tmp\\a");
#else
		st.rename_file(0, "/tmp/a");
		TEST_EQUAL(st.file_path(0, "."), "/tmp/a");
#endif
	}

	{
		file_storage fs;
		fs.set_piece_length(512);
		fs.add_file(combine_path("temp_storage", "test1.tmp"), 17);
		fs.add_file(combine_path("temp_storage", "test2.tmp"), 612);
		fs.add_file(combine_path("temp_storage", "test3.tmp"), 0);
		fs.add_file(combine_path("temp_storage", "test4.tmp"), 0);
		fs.add_file(combine_path("temp_storage", "test5.tmp"), 3253);
		// size: 3882
		fs.add_file(combine_path("temp_storage", "test6.tmp"), 841);
		// size: 4723

		peer_request rq = fs.map_file(0, 0, 10);
		TEST_EQUAL(rq.piece, 0);
		TEST_EQUAL(rq.start, 0);
		TEST_EQUAL(rq.length, 10);
		rq = fs.map_file(5, 0, 10);
		TEST_EQUAL(rq.piece, 7);
		TEST_EQUAL(rq.start, 298);
		TEST_EQUAL(rq.length, 10);
		rq = fs.map_file(5, 0, 1000);
		TEST_EQUAL(rq.piece, 7);
		TEST_EQUAL(rq.start, 298);
		TEST_EQUAL(rq.length, 841);
	}

	return 0;
}

<|endoftext|>


<commit_before>// ******************************************************************************************
// * This project is licensed under the GNU Affero GPL v3. Copyright © 2014 A3Wasteland.com *
// ******************************************************************************************
#include "player_sys.sqf"

class playerSettings {

	idd = playersys_DIALOG;
	movingEnable = true;
	enableSimulation = true;
	onLoad = "[] execVM 'client\systems\playerMenu\item_list.sqf'";

	class controlsBackground {

		class MainBG : IGUIBack {
			idc = -1;
			colorText[] = {1, 1, 1, 1};
			colorBackground[] = {0,0,0,0.6};

			moving = true;
			x = 0.0; y = 0.1;
			w = .745; h = 0.65;
		};

		class TopBar: IGUIBack
		{
			idc = -1;
			colorText[] = {1, 1, 1, 1};
			colorBackground[] = {A3W_UICOLOR_R, A3W_UICOLOR_G, A3W_UICOLOR_B, 0.8};

			x = 0;
			y = 0.1;
			w = 0.745;
			h = 0.05;
		};

		class MainTitle : w_RscText {
			idc = -1;
			text = "Player Inventory";
			sizeEx = 0.04;
			shadow = 2;
			x = 0.260; y = 0.1;
			w = 0.3; h = 0.05;
		};

		class waterIcon : w_RscPicture {
			idc = -1;
			text = "client\icons\water.paa";
			x = 0.022; y = 0.2;
			w = 0.04 / (4/3); h = 0.04;
		};

		class foodIcon : w_RscPicture {
			idc = -1;
			text = "client\icons\food.paa";
			x = 0.022; y = 0.26;
			w = 0.04 / (4/3); h = 0.04;
		};

		class moneyIcon : w_RscPicture {
			idc = -1;
			text = "client\icons\money.paa";
			x = 0.022; y = 0.32;
			w = 0.04 / (4/3); h = 0.04;
		};

		class waterText : w_RscText {
			idc = water_text;
			text = "";
			sizeEx = 0.03;
			x = 0.06; y = 0.193;
			w = 0.3; h = 0.05;
		};

		class foodText : w_RscText {
			idc = food_text;
			sizeEx = 0.03;
			text = "";
			x = 0.06; y = 0.254;
			w = 0.3; h = 0.05;
		};

		class moneyText : w_RscText {
			idc = money_text;
			text = "";
			sizeEx = 0.03;
			x = 0.06; y = 0.313;
			w = 0.3; h = 0.05;
		};

		class distanceText : w_RscText {
			idc = view_range_text;
			text = "View range:";
			sizeEx = 0.025;
			x = 0.03; y = 0.40;
			w = 0.3; h = 0.02;
		};

		class uptimeText : w_RscText {
			idc = uptime_text;
			text = "";
			sizeEx = 0.030;
			x = 0.52; y = 0.69;
			w = 0.225; h = 0.03;
		};
	};

	class controls {

		class itemList : w_Rsclist {
			idc = item_list;
			x = 0.49; y = 0.185;
			w = 0.235; h = 0.325;
		};

		class DropButton : w_RscButton {
			idc = -1;
			text = "Drop";
			onButtonClick = "[1] execVM 'client\systems\playerMenu\itemfnc.sqf'";
			x = 0.610; y = 0.525;
			w = 0.116; h = 0.033 * safezoneH;
		};

		class UseButton : w_RscButton {
			idc = -1;
			text = "Use";
			onButtonClick = "[0] execVM 'client\systems\playerMenu\itemfnc.sqf'";
			x = 0.489; y = 0.525;
			w = 0.116; h = 0.033 * safezoneH;
		};

		class moneyInput: w_RscCombo {
			idc = money_value;
			x = 0.610; y = 0.618;
			w = .116; h = .030;
		};

		class DropcButton : w_RscButton {
			idc = -1;
			text = "Drop";
			onButtonClick = "[] execVM 'client\systems\playerMenu\dropMoney.sqf'";
			x = 0.489; y = 0.60;
			w = 0.116; h = 0.033 * safezoneH;
		};

		class CloseButton : w_RscButton {
			idc = close_button;
			text = "Close";
			onButtonClick = "[] execVM 'client\systems\playerMenu\closePlayerMenu.sqf'";
			x = 0.02; y = 0.66;
			w = 0.125; h = 0.033 * safezoneH;
		};

		class GroupsButton : w_RscButton {
			idc = groupButton;
			text = "Group Management";
			onButtonClick = "[] execVM 'client\systems\groups\loadGroupManagement.sqf'";
			x = 0.158; y = 0.66;
			w = 0.225; h = 0.033 * safezoneH;
		};

		class btnDistanceNear : w_RscButton {
			idc = -1;
			text = "Near";
			onButtonClick = "setViewDistance 1100;";
			x = 0.02; y = 0.43;
			w = 0.125; h = 0.033 * safezoneH;
		};

		class btnDistanceMedium : w_RscButton {
			idc = -1;
			text = "Medium";
			onButtonClick = "setViewDistance 2200;";
			x = 0.02; y = 0.5;
			w = 0.125; h = 0.033 * safezoneH;
		};

		class btnDistanceFar : w_RscButton {
			idc = -1;
			text = "Far";
			onButtonClick = "setViewDistance 3300;";
			x = 0.02; y = 0.57;
			w = 0.125; h = 0.033 * safezoneH;
		};

		class btnDistanceInsane : w_RscButton {
			text = "Insane";
			onButtonClick = "setViewDistance 5000;";
			x = 0.02; y = 0.60;
			w = 0.125; h = 0.033 * safezoneH;
		};
	};
};
<commit_msg>adjusted view distances for close medium and far<commit_after>// ******************************************************************************************
// * This project is licensed under the GNU Affero GPL v3. Copyright © 2014 A3Wasteland.com *
// ******************************************************************************************
#include "player_sys.sqf"

class playerSettings {

	idd = playersys_DIALOG;
	movingEnable = true;
	enableSimulation = true;
	onLoad = "[] execVM 'client\systems\playerMenu\item_list.sqf'";

	class controlsBackground {

		class MainBG : IGUIBack {
			idc = -1;
			colorText[] = {1, 1, 1, 1};
			colorBackground[] = {0,0,0,0.6};

			moving = true;
			x = 0.0; y = 0.1;
			w = .745; h = 0.65;
		};

		class TopBar: IGUIBack
		{
			idc = -1;
			colorText[] = {1, 1, 1, 1};
			colorBackground[] = {A3W_UICOLOR_R, A3W_UICOLOR_G, A3W_UICOLOR_B, 0.8};

			x = 0;
			y = 0.1;
			w = 0.745;
			h = 0.05;
		};

		class MainTitle : w_RscText {
			idc = -1;
			text = "Player Inventory";
			sizeEx = 0.04;
			shadow = 2;
			x = 0.260; y = 0.1;
			w = 0.3; h = 0.05;
		};

		class waterIcon : w_RscPicture {
			idc = -1;
			text = "client\icons\water.paa";
			x = 0.022; y = 0.2;
			w = 0.04 / (4/3); h = 0.04;
		};

		class foodIcon : w_RscPicture {
			idc = -1;
			text = "client\icons\food.paa";
			x = 0.022; y = 0.26;
			w = 0.04 / (4/3); h = 0.04;
		};

		class moneyIcon : w_RscPicture {
			idc = -1;
			text = "client\icons\money.paa";
			x = 0.022; y = 0.32;
			w = 0.04 / (4/3); h = 0.04;
		};

		class waterText : w_RscText {
			idc = water_text;
			text = "";
			sizeEx = 0.03;
			x = 0.06; y = 0.193;
			w = 0.3; h = 0.05;
		};

		class foodText : w_RscText {
			idc = food_text;
			sizeEx = 0.03;
			text = "";
			x = 0.06; y = 0.254;
			w = 0.3; h = 0.05;
		};

		class moneyText : w_RscText {
			idc = money_text;
			text = "";
			sizeEx = 0.03;
			x = 0.06; y = 0.313;
			w = 0.3; h = 0.05;
		};

		class distanceText : w_RscText {
			idc = view_range_text;
			text = "View range:";
			sizeEx = 0.025;
			x = 0.03; y = 0.40;
			w = 0.3; h = 0.02;
		};

		class uptimeText : w_RscText {
			idc = uptime_text;
			text = "";
			sizeEx = 0.030;
			x = 0.52; y = 0.69;
			w = 0.225; h = 0.03;
		};
	};

	class controls {

		class itemList : w_Rsclist {
			idc = item_list;
			x = 0.49; y = 0.185;
			w = 0.235; h = 0.325;
		};

		class DropButton : w_RscButton {
			idc = -1;
			text = "Drop";
			onButtonClick = "[1] execVM 'client\systems\playerMenu\itemfnc.sqf'";
			x = 0.610; y = 0.525;
			w = 0.116; h = 0.033 * safezoneH;
		};

		class UseButton : w_RscButton {
			idc = -1;
			text = "Use";
			onButtonClick = "[0] execVM 'client\systems\playerMenu\itemfnc.sqf'";
			x = 0.489; y = 0.525;
			w = 0.116; h = 0.033 * safezoneH;
		};

		class moneyInput: w_RscCombo {
			idc = money_value;
			x = 0.610; y = 0.618;
			w = .116; h = .030;
		};

		class DropcButton : w_RscButton {
			idc = -1;
			text = "Drop";
			onButtonClick = "[] execVM 'client\systems\playerMenu\dropMoney.sqf'";
			x = 0.489; y = 0.60;
			w = 0.116; h = 0.033 * safezoneH;
		};

		class CloseButton : w_RscButton {
			idc = close_button;
			text = "Close";
			onButtonClick = "[] execVM 'client\systems\playerMenu\closePlayerMenu.sqf'";
			x = 0.02; y = 0.66;
			w = 0.125; h = 0.033 * safezoneH;
		};

		class GroupsButton : w_RscButton {
			idc = groupButton;
			text = "Group Management";
			onButtonClick = "[] execVM 'client\systems\groups\loadGroupManagement.sqf'";
			x = 0.158; y = 0.66;
			w = 0.225; h = 0.033 * safezoneH;
		};

		class btnDistanceNear : w_RscButton {
			idc = -1;
			text = "Near";
			onButtonClick = "setViewDistance 1000;";
			x = 0.02; y = 0.43;
			w = 0.125; h = 0.033 * safezoneH;
		};

		class btnDistanceMedium : w_RscButton {
			idc = -1;
			text = "Medium";
			onButtonClick = "setViewDistance 3000;";
			x = 0.02; y = 0.5;
			w = 0.125; h = 0.033 * safezoneH;
		};

		class btnDistanceFar : w_RscButton {
			idc = -1;
			text = "Far";
			onButtonClick = "setViewDistance 5000;";
			x = 0.02; y = 0.57;
			w = 0.125; h = 0.033 * safezoneH;
		};

		class btnDistanceInsane : w_RscButton {
			text = "Insane";
			onButtonClick = "setViewDistance 5000;";
			x = 0.02; y = 0.60;
			w = 0.125; h = 0.033 * safezoneH;
		};
	};
};
<|endoftext|>


<commit_before>
/*
 * var_len_pool_test.cpp - Test suite for varrable lengthed allocation pool
 */

#include "test_suite.h"
#include "../src/VarLenPool.h"

/*
 * VarLenPoolBasicTest() - This function allocates a series of memory
 *                         using an increasing sequence and then check
 *                         for correctness
 */
void VarLenPoolBasicTest() {
  PrintTestName("VarLenPoolBasicTest");

  static const int iter = 10;

  void *p_list[iter];

  // Chunk size = 64
  VarLenPool vlp{64};
  for(int i = 1;i <= 10;i++) {
    p_list[i - 1] = vlp.Allocate(i);
    memset(p_list[i - 1], i, i);

    dbg_printf("Allocating mem of size = %d\n", i);
  }

  // Verify for correctness
  for(int i = 1;i <= 10;i++) {
    char *p = reinterpret_cast<char *>(p_list[i - 1]);
    for(int j = 0;j < i;j++) {
      assert(p[j] == static_cast<char>(i));
    }

    dbg_printf("Checking content of size = %d\n", i);
  }

  return;
}

int main() {
  VarLenPoolBasicTest();

  return 0;
}
<commit_msg>Fix iter variable not used problem; Adding framweork for multiuthreaded test of VarLenPool<commit_after>
/*
 * var_len_pool_test.cpp - Test suite for varrable lengthed allocation pool
 */

#include "test_suite.h"
#include "../src/VarLenPool.h"

/*
 * VarLenPoolBasicTest() - This function allocates a series of memory
 *                         using an increasing sequence and then check
 *                         for correctness
 */
void VarLenPoolBasicTest() {
  PrintTestName("VarLenPoolBasicTest");

  static const int iter = 10;

  void *p_list[iter];

  // Chunk size = 64
  VarLenPool vlp{64};
  for(int i = 1;i <= iter;i++) {
    p_list[i - 1] = vlp.Allocate(i);
    memset(p_list[i - 1], i, i);

    dbg_printf("Allocating mem of size = %d\n", i);
  }

  // Verify for correctness
  for(int i = 1;i <= iter;i++) {
    char *p = reinterpret_cast<char *>(p_list[i - 1]);
    for(int j = 0;j < i;j++) {
      assert(p[j] == static_cast<char>(i));
    }

    dbg_printf("Checking content of size = %d\n", i);
  }

  return;
}

/*
 * VarLenPoolThreadTest() - Multithreaded test of VarLenPool
 */
void VarLenPoolThreadTest(int thread_num, int iter) {

}

int main() {
  VarLenPoolBasicTest();

  return 0;
}
<|endoftext|>


<commit_before>/*
   Copyright 2015 Rachael Harding

   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 "global.h"
#include "helper.h"
#include "wl.h"
#include "row.h"
#include "table.h"
#include "index_hash.h"
#include "index_btree.h"
#include "catalog.h"
#include "mem_alloc.h"

RC Workload::init() {
	return RCOK;
}

RC Workload::init_schema(const char * schema_file) {
    assert(sizeof(uint64_t) == 8);
    assert(sizeof(double) == 8);
	string line;
  uint32_t id = 0;
	ifstream fin(schema_file);
    Catalog * schema;
    while (getline(fin, line)) {
		if (line.compare(0, 6, "TABLE=") == 0) {
			string tname(&line[6]);
			void * tmp = new char[CL_SIZE * 2 + sizeof(Catalog)];
            schema = (Catalog *) ((UInt64)tmp + CL_SIZE);
			getline(fin, line);
			int col_count = 0;
			// Read all fields for this table.
			vector<string> lines;
			while (line.length() > 1) {
				lines.push_back(line);
				getline(fin, line);
			}
			schema->init( tname.c_str(), id++, lines.size() );
			for (UInt32 i = 0; i < lines.size(); i++) {
				string line = lines[i];
				vector<string> items;

        char * line_cstr = new char [line.length()+1];
        strcpy(line_cstr,line.c_str());
        int size = atoi(strtok(line_cstr,","));
        char * type = strtok(NULL,",");
        char * name = strtok(NULL,",");

        schema->add_col(name, size, type);
				col_count ++;
			}
			tmp = new char[CL_SIZE * 2 + sizeof(table_t)];
            table_t * cur_tab = (table_t *) ((UInt64)tmp + CL_SIZE);
			cur_tab->init(schema);
			tables[tname] = cur_tab;
        } else if (!line.compare(0, 6, "INDEX=")) {
			string iname(&line[6]);
			getline(fin, line);

			vector<string> items;
			string token;
			size_t pos;
			while (line.length() != 0) {
				pos = line.find(","); // != std::string::npos) {
				if (pos == string::npos)
					pos = line.length();
	    		token = line.substr(0, pos);
				items.push_back(token);
		    	line.erase(0, pos + 1);
			}

			string tname(items[0]);
			int field_cnt = items.size() - 1;
			uint64_t * fields = new uint64_t [field_cnt];
			for (int i = 0; i < field_cnt; i++)
				fields[i] = atoi(items[i + 1].c_str());
			INDEX * index = new INDEX;
	    int part_cnt __attribute__ ((unused));
			part_cnt = (CENTRAL_INDEX)? 1 : g_part_cnt;

      uint64_t table_size = g_synth_table_size;
#if WORKLOAD == TPCC
      if ( !tname.compare(1, 9, "WAREHOUSE") ) {
        table_size = g_num_wh;
        printf("WAREHOUSE size %ld\n",table_size);
      } else if ( !tname.compare(1, 8, "DISTRICT") ) {
        table_size = g_num_wh * g_dist_per_wh;
        printf("DISTRICT size %ld\n",table_size);
      } else if ( !tname.compare(1, 8, "CUSTOMER") ) {
        table_size = g_num_wh * g_dist_per_wh * g_cust_per_dist;
        printf("CUSTOMER size %ld\n",table_size);
      } else if ( !tname.compare(1, 7, "HISTORY") ) {
        table_size = g_num_wh * g_dist_per_wh * g_cust_per_dist;
        printf("HISTORY size %ld\n",table_size);
      } else if ( !tname.compare(1, 5, "ORDER") ) {
        table_size = g_num_wh * g_dist_per_wh * g_cust_per_dist;
        printf("ORDER size %ld\n",table_size);
      } else if ( !tname.compare(1, 4, "ITEM") ) {
        table_size = g_max_items;
        printf("ITEM size %ld\n",table_size);
      } else if ( !tname.compare(1, 5, "STOCK") ) {
        table_size = g_num_wh * g_max_items;
        printf("STOCK size %ld\n",table_size);
      }
#else
      table_size = g_synth_table_size;
#endif

#if INDEX_STRUCT == IDX_HASH
			index->init(1024, tables[tname], table_size);
			//index->init(part_cnt*1024, tables[tname], table_size);
#else
			index->init(part_cnt, tables[tname]);
#endif
			indexes[iname] = index;
		}
    }
	fin.close();
	return RCOK;
}

void Workload::index_insert(string index_name, uint64_t key, row_t * row) {
	assert(false);
	INDEX * index = (INDEX *) indexes[index_name];
	index_insert(index, key, row);
}

void Workload::index_insert(INDEX * index, uint64_t key, row_t * row, int64_t part_id) {
	uint64_t pid = part_id;
	if (part_id == -1)
		pid = get_part_id(row);
	itemid_t * m_item =
		(itemid_t *) mem_allocator.alloc( sizeof(itemid_t));
	m_item->init();
	m_item->type = DT_row;
	m_item->location = row;
	m_item->valid = true;

    assert( index->index_insert(key, m_item, pid) == RCOK );
}

<commit_msg>Only initialize hash index buckets for one partition of data<commit_after>/*
   Copyright 2015 Rachael Harding

   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 "global.h"
#include "helper.h"
#include "wl.h"
#include "row.h"
#include "table.h"
#include "index_hash.h"
#include "index_btree.h"
#include "catalog.h"
#include "mem_alloc.h"

RC Workload::init() {
	return RCOK;
}

RC Workload::init_schema(const char * schema_file) {
    assert(sizeof(uint64_t) == 8);
    assert(sizeof(double) == 8);
	string line;
  uint32_t id = 0;
	ifstream fin(schema_file);
    Catalog * schema;
    while (getline(fin, line)) {
		if (line.compare(0, 6, "TABLE=") == 0) {
			string tname(&line[6]);
			void * tmp = new char[CL_SIZE * 2 + sizeof(Catalog)];
            schema = (Catalog *) ((UInt64)tmp + CL_SIZE);
			getline(fin, line);
			int col_count = 0;
			// Read all fields for this table.
			vector<string> lines;
			while (line.length() > 1) {
				lines.push_back(line);
				getline(fin, line);
			}
			schema->init( tname.c_str(), id++, lines.size() );
			for (UInt32 i = 0; i < lines.size(); i++) {
				string line = lines[i];
				vector<string> items;

        char * line_cstr = new char [line.length()+1];
        strcpy(line_cstr,line.c_str());
        int size = atoi(strtok(line_cstr,","));
        char * type = strtok(NULL,",");
        char * name = strtok(NULL,",");

        schema->add_col(name, size, type);
				col_count ++;
			}
			tmp = new char[CL_SIZE * 2 + sizeof(table_t)];
            table_t * cur_tab = (table_t *) ((UInt64)tmp + CL_SIZE);
			cur_tab->init(schema);
			tables[tname] = cur_tab;
        } else if (!line.compare(0, 6, "INDEX=")) {
			string iname(&line[6]);
			getline(fin, line);

			vector<string> items;
			string token;
			size_t pos;
			while (line.length() != 0) {
				pos = line.find(","); // != std::string::npos) {
				if (pos == string::npos)
					pos = line.length();
	    		token = line.substr(0, pos);
				items.push_back(token);
		    	line.erase(0, pos + 1);
			}

			string tname(items[0]);
			int field_cnt = items.size() - 1;
			uint64_t * fields = new uint64_t [field_cnt];
			for (int i = 0; i < field_cnt; i++)
				fields[i] = atoi(items[i + 1].c_str());
			INDEX * index = new INDEX;
	    int part_cnt __attribute__ ((unused));
			part_cnt = (CENTRAL_INDEX)? 1 : g_part_cnt;

      uint64_t table_size = g_synth_table_size;
#if WORKLOAD == TPCC
      if ( !tname.compare(1, 9, "WAREHOUSE") ) {
        table_size = g_num_wh / g_part_cnt;
        printf("WAREHOUSE size %ld\n",table_size);
      } else if ( !tname.compare(1, 8, "DISTRICT") ) {
        table_size = g_num_wh / g_part_cnt * g_dist_per_wh;
        printf("DISTRICT size %ld\n",table_size);
      } else if ( !tname.compare(1, 8, "CUSTOMER") ) {
        table_size = g_num_wh / g_part_cnt * g_dist_per_wh * g_cust_per_dist;
        printf("CUSTOMER size %ld\n",table_size);
      } else if ( !tname.compare(1, 7, "HISTORY") ) {
        table_size = g_num_wh / g_part_cnt * g_dist_per_wh * g_cust_per_dist;
        printf("HISTORY size %ld\n",table_size);
      } else if ( !tname.compare(1, 5, "ORDER") ) {
        table_size = g_num_wh / g_part_cnt * g_dist_per_wh * g_cust_per_dist;
        printf("ORDER size %ld\n",table_size);
      } else if ( !tname.compare(1, 4, "ITEM") ) {
        table_size = g_max_items;
        printf("ITEM size %ld\n",table_size);
      } else if ( !tname.compare(1, 5, "STOCK") ) {
        table_size = g_num_wh / g_part_cnt * g_max_items;
        printf("STOCK size %ld\n",table_size);
      }
#else
      table_size = g_synth_table_size / g_part_cnt;
#endif

#if INDEX_STRUCT == IDX_HASH
			index->init(1024, tables[tname], table_size);
			//index->init(part_cnt*1024, tables[tname], table_size);
#else
			index->init(part_cnt, tables[tname]);
#endif
			indexes[iname] = index;
		}
    }
	fin.close();
	return RCOK;
}

void Workload::index_insert(string index_name, uint64_t key, row_t * row) {
	assert(false);
	INDEX * index = (INDEX *) indexes[index_name];
	index_insert(index, key, row);
}

void Workload::index_insert(INDEX * index, uint64_t key, row_t * row, int64_t part_id) {
	uint64_t pid = part_id;
	if (part_id == -1)
		pid = get_part_id(row);
	itemid_t * m_item =
		(itemid_t *) mem_allocator.alloc( sizeof(itemid_t));
	m_item->init();
	m_item->type = DT_row;
	m_item->location = row;
	m_item->valid = true;

    assert( index->index_insert(key, m_item, pid) == RCOK );
}

<|endoftext|>


<commit_before>/*
 * Copyright 2013 KanMemo 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 "tabwidget.h"
#include "webpage.h"
#include "kanmusumemory_global.h"

#include <QSettings>
#include <QDebug>

class TabWidget::Private
{
public:
    Private(TabWidget *parent);

    void newTab(const QUrl &url, bool mobilemode = true);
    void newTab(WebPage *webpage, bool mobilemode = true);

private:
    TabWidget *q;

};

TabWidget::Private::Private(TabWidget *parent)
    : q(parent)
{

}
//新しいタブ
void TabWidget::Private::newTab(const QUrl &url, bool mobilemode)
{
//    qDebug() << "newTab:" << url << " : mobile=" << mobilemode;

    WebPageForm *web = new WebPageForm(q);
    web->setMobileMode(mobilemode);
    web->setCache(q->cache());
    web->setUrl(url);
    q->addTab(web, QStringLiteral("(untitled)"));
    q->setCurrentWidget(web);

    //タブの追加
    connect(web, &WebPageForm::addTabRequested, [this](WebPage *webpage){
        newTab(webpage);
    });
    //タブを閉じる
    connect(web, &WebPageForm::removeTabRequested, [this](WebPageForm *form) {
        q->closeTab(form);
    });
    //お気に入りの更新
    connect(web, &WebPageForm::updateFavorite, [this]() { emit q->updateFavorite(); });
}

void TabWidget::Private::newTab(WebPage *webpage, bool mobilemode)
{
//    qDebug() << "newTab: webpage";

    WebPageForm *web = new WebPageForm(q);
    web->setMobileMode(mobilemode);
    web->setWebPage(webpage);
    web->setCache(q->cache());
    q->addTab(web, QStringLiteral("(untitled)"));
    q->setCurrentWidget(web);

    //タブの追加
    connect(web, &WebPageForm::addTabRequested, [this](WebPage *webpage){
        newTab(webpage);
    });
    //タブを閉じる
    connect(web, &WebPageForm::removeTabRequested, [this](WebPageForm *form) {
        q->closeTab(form);
    });
    //お気に入りの更新
    connect(web, &WebPageForm::updateFavorite, [this]() { emit q->updateFavorite(); });
}

TabWidget::TabWidget(QWidget* parent)
    : QTabWidget(parent)
    , d(new Private(this))
    , m_saveOpenPage(true)
    , m_openAndNewTab(true)
    , m_cache(NULL)
{
    connect(this, &QObject::destroyed, [this]() { delete d; });

    //タブの閉じる要求
    connect(this, &QTabWidget::tabCloseRequested, [this](int index) {
        WebPageForm *form = reinterpret_cast<WebPageForm *>(widget(index));
//        qDebug() << "close tab(" << index << "):" << form->url();
        delete form;
    });
}

//タブの状態を保存する
bool TabWidget::saveOpenPage() const
{
    return m_saveOpenPage;
}
void TabWidget::setSaveOpenPage(bool saveOpenPage)
{
    m_saveOpenPage = saveOpenPage;
}
//新しいURLを開くとき新しいタブ
bool TabWidget::openAndNewTab() const
{
    return m_openAndNewTab;
}
void TabWidget::setOpenAndNewTab(bool openAndNewTab)
{
    m_openAndNewTab = openAndNewTab;
}

//リンクを開く
void TabWidget::openUrl(const QUrl &url, bool mobilemode)
{
    if(openAndNewTab() || count() == 0){
        //設定が新規タブとタブが無いとき
        newTab(url, mobilemode);
    }else{
        //現在のタブ
        WebPageForm *form = reinterpret_cast<WebPageForm *>(widget(currentIndex()));
        form->setMobileMode(mobilemode);
        form->setUrl(url);
    }
}
//新しいタブ
void TabWidget::newTab(const QUrl &url, bool mobilemode)
{
    d->newTab(url, mobilemode);
}
//タブを閉じる
void TabWidget::closeTab()
{
    tabCloseRequested(currentIndex());
}
//タブを閉じる
void TabWidget::closeTab(WebPageForm *form)
{
    WebPageForm *f;
    for(int i=0; i<count(); i++){
        f = reinterpret_cast<WebPageForm *>(widget(i));
        if(f == form){
            tabCloseRequested(i);
        }
    }
}
//タブをすべて閉じる
void TabWidget::closeTabAll()
{
    for(int i = count(); i >= 0; i++){
        tabCloseRequested(i);
    }
}
//タブの再読み込み
void TabWidget::reloadTab()
{
    WebPageForm *form = reinterpret_cast<WebPageForm *>(currentWidget());
    form->reload();
}
//前のタブ
void TabWidget::prevTab()
{
    int index = currentIndex() - 1;
    if(index < 0){
        index = count() - 1;
    }
    setCurrentIndex(index);
}
//次のタブ
void TabWidget::nextTab()
{
    int index = currentIndex() + 1;
    if(index >= count()){
        index = 0;
    }
    setCurrentIndex(index);
}

void TabWidget::find()
{
    WebPageForm *form = qobject_cast<WebPageForm *>(currentWidget());
    if(form){
        form->find();
    }
}

//タブとかを読み込む
void TabWidget::load()
{
    QSettings settings(QSettings::IniFormat, QSettings::UserScope, KANMEMO_PROJECT, KANMEMO_NAME);
    settings.beginGroup(QStringLiteral(SETTING_TAB));
    setSaveOpenPage(settings.value(QStringLiteral(SETTING_TAB_SAVE_OPEN_PAGES), true).toBool());
    setOpenAndNewTab(settings.value(QStringLiteral(SETTING_TAB_OPEN_AND_NEWTAB), true).toBool());
    if(count() == 0 && saveOpenPage()){   //タブが無いときだけ復元
        QList<QVariant> pagelist = settings.value(QStringLiteral(SETTING_TAB_OPEN_PAGES), QVariant()).toList();
        QList<QVariant> pageMobileModeList = settings.value(QStringLiteral(SETTING_TAB_OPEN_PAGES_MOBILE_MODE), QVariant()).toList();
        int i=0;
        foreach (QVariant page, pagelist) {
            if(i < pageMobileModeList.count()){
                newTab(page.toString(), pageMobileModeList[i].toBool());
                i++;
            }else{
                newTab(page.toString());
            }
        }
    }
    settings.endGroup();
}
//タブとか設定を保存する
void TabWidget::save()
{
    QList<QVariant> pagelist;
    QList<QVariant> pageMobileModeList;
    WebPageForm *form;
    QSettings settings(QSettings::IniFormat, QSettings::UserScope, KANMEMO_PROJECT, KANMEMO_NAME);
    settings.beginGroup(QStringLiteral(SETTING_TAB));
    settings.setValue(QStringLiteral(SETTING_TAB_SAVE_OPEN_PAGES), saveOpenPage());
    settings.setValue(QStringLiteral(SETTING_TAB_OPEN_AND_NEWTAB), openAndNewTab());
    if(saveOpenPage()){
        for(int i=0; i<count(); i++){
            form = reinterpret_cast<WebPageForm *>(widget(i));
            pagelist.append(form->url().toString());
            pageMobileModeList.append(form->isMobileMode());
        }
    }
    settings.setValue(QStringLiteral(SETTING_TAB_OPEN_PAGES), pagelist);
    settings.setValue(QStringLiteral(SETTING_TAB_OPEN_PAGES_MOBILE_MODE), pageMobileModeList);
    settings.endGroup();
}
//キャッシュをタブの中のWebページへ設定するための情報
QNetworkDiskCache *TabWidget::cache() const
{
    return m_cache;
}
void TabWidget::setCache(QNetworkDiskCache *cache)
{
    m_cache = cache;
}

<commit_msg>Fixed a bug to kill by pressing R when there is no tab<commit_after>/*
 * Copyright 2013 KanMemo 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 "tabwidget.h"
#include "webpage.h"
#include "kanmusumemory_global.h"

#include <QSettings>
#include <QDebug>

class TabWidget::Private
{
public:
    Private(TabWidget *parent);

    void newTab(const QUrl &url, bool mobilemode = true);
    void newTab(WebPage *webpage, bool mobilemode = true);

private:
    TabWidget *q;

};

TabWidget::Private::Private(TabWidget *parent)
    : q(parent)
{

}
//新しいタブ
void TabWidget::Private::newTab(const QUrl &url, bool mobilemode)
{
//    qDebug() << "newTab:" << url << " : mobile=" << mobilemode;

    WebPageForm *web = new WebPageForm(q);
    web->setMobileMode(mobilemode);
    web->setCache(q->cache());
    web->setUrl(url);
    q->addTab(web, QStringLiteral("(untitled)"));
    q->setCurrentWidget(web);

    //タブの追加
    connect(web, &WebPageForm::addTabRequested, [this](WebPage *webpage){
        newTab(webpage);
    });
    //タブを閉じる
    connect(web, &WebPageForm::removeTabRequested, [this](WebPageForm *form) {
        q->closeTab(form);
    });
    //お気に入りの更新
    connect(web, &WebPageForm::updateFavorite, [this]() { emit q->updateFavorite(); });
}

void TabWidget::Private::newTab(WebPage *webpage, bool mobilemode)
{
//    qDebug() << "newTab: webpage";

    WebPageForm *web = new WebPageForm(q);
    web->setMobileMode(mobilemode);
    web->setWebPage(webpage);
    web->setCache(q->cache());
    q->addTab(web, QStringLiteral("(untitled)"));
    q->setCurrentWidget(web);

    //タブの追加
    connect(web, &WebPageForm::addTabRequested, [this](WebPage *webpage){
        newTab(webpage);
    });
    //タブを閉じる
    connect(web, &WebPageForm::removeTabRequested, [this](WebPageForm *form) {
        q->closeTab(form);
    });
    //お気に入りの更新
    connect(web, &WebPageForm::updateFavorite, [this]() { emit q->updateFavorite(); });
}

TabWidget::TabWidget(QWidget* parent)
    : QTabWidget(parent)
    , d(new Private(this))
    , m_saveOpenPage(true)
    , m_openAndNewTab(true)
    , m_cache(NULL)
{
    connect(this, &QObject::destroyed, [this]() { delete d; });

    //タブの閉じる要求
    connect(this, &QTabWidget::tabCloseRequested, [this](int index) {
        WebPageForm *form = reinterpret_cast<WebPageForm *>(widget(index));
//        qDebug() << "close tab(" << index << "):" << form->url();
        delete form;
    });
}

//タブの状態を保存する
bool TabWidget::saveOpenPage() const
{
    return m_saveOpenPage;
}
void TabWidget::setSaveOpenPage(bool saveOpenPage)
{
    m_saveOpenPage = saveOpenPage;
}
//新しいURLを開くとき新しいタブ
bool TabWidget::openAndNewTab() const
{
    return m_openAndNewTab;
}
void TabWidget::setOpenAndNewTab(bool openAndNewTab)
{
    m_openAndNewTab = openAndNewTab;
}

//リンクを開く
void TabWidget::openUrl(const QUrl &url, bool mobilemode)
{
    if(openAndNewTab() || count() == 0){
        //設定が新規タブとタブが無いとき
        newTab(url, mobilemode);
    }else{
        //現在のタブ
        WebPageForm *form = reinterpret_cast<WebPageForm *>(widget(currentIndex()));
        form->setMobileMode(mobilemode);
        form->setUrl(url);
    }
}
//新しいタブ
void TabWidget::newTab(const QUrl &url, bool mobilemode)
{
    d->newTab(url, mobilemode);
}
//タブを閉じる
void TabWidget::closeTab()
{
    tabCloseRequested(currentIndex());
}
//タブを閉じる
void TabWidget::closeTab(WebPageForm *form)
{
    WebPageForm *f;
    for(int i=0; i<count(); i++){
        f = reinterpret_cast<WebPageForm *>(widget(i));
        if(f == form){
            tabCloseRequested(i);
        }
    }
}
//タブをすべて閉じる
void TabWidget::closeTabAll()
{
    for(int i = count(); i >= 0; i++){
        tabCloseRequested(i);
    }
}
//タブの再読み込み
void TabWidget::reloadTab()
{
    if(count() > 0){
        WebPageForm *form = reinterpret_cast<WebPageForm *>(currentWidget());
        form->reload();
    }
}
//前のタブ
void TabWidget::prevTab()
{
    int index = currentIndex() - 1;
    if(index < 0){
        index = count() - 1;
    }
    setCurrentIndex(index);
}
//次のタブ
void TabWidget::nextTab()
{
    int index = currentIndex() + 1;
    if(index >= count()){
        index = 0;
    }
    setCurrentIndex(index);
}

void TabWidget::find()
{
    WebPageForm *form = qobject_cast<WebPageForm *>(currentWidget());
    if(form){
        form->find();
    }
}

//タブとかを読み込む
void TabWidget::load()
{
    QSettings settings(QSettings::IniFormat, QSettings::UserScope, KANMEMO_PROJECT, KANMEMO_NAME);
    settings.beginGroup(QStringLiteral(SETTING_TAB));
    setSaveOpenPage(settings.value(QStringLiteral(SETTING_TAB_SAVE_OPEN_PAGES), true).toBool());
    setOpenAndNewTab(settings.value(QStringLiteral(SETTING_TAB_OPEN_AND_NEWTAB), true).toBool());
    if(count() == 0 && saveOpenPage()){   //タブが無いときだけ復元
        QList<QVariant> pagelist = settings.value(QStringLiteral(SETTING_TAB_OPEN_PAGES), QVariant()).toList();
        QList<QVariant> pageMobileModeList = settings.value(QStringLiteral(SETTING_TAB_OPEN_PAGES_MOBILE_MODE), QVariant()).toList();
        int i=0;
        foreach (QVariant page, pagelist) {
            if(i < pageMobileModeList.count()){
                newTab(page.toString(), pageMobileModeList[i].toBool());
                i++;
            }else{
                newTab(page.toString());
            }
        }
    }
    settings.endGroup();
}
//タブとか設定を保存する
void TabWidget::save()
{
    QList<QVariant> pagelist;
    QList<QVariant> pageMobileModeList;
    WebPageForm *form;
    QSettings settings(QSettings::IniFormat, QSettings::UserScope, KANMEMO_PROJECT, KANMEMO_NAME);
    settings.beginGroup(QStringLiteral(SETTING_TAB));
    settings.setValue(QStringLiteral(SETTING_TAB_SAVE_OPEN_PAGES), saveOpenPage());
    settings.setValue(QStringLiteral(SETTING_TAB_OPEN_AND_NEWTAB), openAndNewTab());
    if(saveOpenPage()){
        for(int i=0; i<count(); i++){
            form = reinterpret_cast<WebPageForm *>(widget(i));
            pagelist.append(form->url().toString());
            pageMobileModeList.append(form->isMobileMode());
        }
    }
    settings.setValue(QStringLiteral(SETTING_TAB_OPEN_PAGES), pagelist);
    settings.setValue(QStringLiteral(SETTING_TAB_OPEN_PAGES_MOBILE_MODE), pageMobileModeList);
    settings.endGroup();
}
//キャッシュをタブの中のWebページへ設定するための情報
QNetworkDiskCache *TabWidget::cache() const
{
    return m_cache;
}
void TabWidget::setCache(QNetworkDiskCache *cache)
{
    m_cache = cache;
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

extern "C" {
   #undef __cplusplus
   #define _WCHART
   #include "CppUTest/TestHarness_c.h"

}
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/TestTestingFixture.h"
#include "CppUTest/PlatformSpecificFunctions.h"

TEST_GROUP(TestHarness_c)
{
	TestTestingFixture* fixture;
	TEST_SETUP()
	{
		fixture = new TestTestingFixture();
	}
	TEST_TEARDOWN()
	{
		delete fixture;
	}
};

void _failIntMethod()
{
	CHECK_EQUAL_C_INT(1, 2);
}

TEST(TestHarness_c, checkInt)
{
	CHECK_EQUAL_C_INT(2, 2);
	fixture->setTestFunction(_failIntMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("expected <1>\n	but was  <2>");
	fixture->assertPrintContains("arness_c");
}

void _failRealMethod()
{
	CHECK_EQUAL_C_REAL(1.0, 2.0, 0.5);
}

TEST(TestHarness_c, checkReal)
{
	CHECK_EQUAL_C_REAL(1.0, 1.1, 0.5);
	fixture->setTestFunction(_failRealMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("expected <1.000000>\n	but was  <2.000000>");
	fixture->assertPrintContains("arness_c");
}

void _failCharMethod()
{
	CHECK_EQUAL_C_CHAR('a', 'c');
}

TEST(TestHarness_c, checkChar)
{
	CHECK_EQUAL_C_CHAR('a', 'a');
	fixture->setTestFunction(_failCharMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("expected <a>\n	but was  <c>");
	fixture->assertPrintContains("arness_c");
}

void _failStringMethod()
{
	CHECK_EQUAL_C_STRING("Hello", "World");
}

TEST(TestHarness_c, checkString)
{
	CHECK_EQUAL_C_STRING("Hello", "Hello");
	fixture->setTestFunction(_failStringMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("expected <Hello>\n	but was  <World>");
	fixture->assertPrintContains("arness_c");
}

void _failTextMethod()
{
	FAIL_TEXT_C("Booo");
}

TEST(TestHarness_c, checkFailText)
{
	fixture->setTestFunction(_failTextMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("Booo");
	fixture->assertPrintContains("arness_c");
}

void _failMethod()
{
	FAIL_C();
}

TEST(TestHarness_c, checkFail)
{
	fixture->setTestFunction(_failMethod);
	fixture->runAllTests();
	LONGS_EQUAL(1, fixture->getFailureCount());
	fixture->assertPrintContains("arness_c");
}

void _CheckMethod()
{
	CHECK_C(false);
}

TEST(TestHarness_c, checkCheck)
{
	CHECK_C(true);
	fixture->setTestFunction(_CheckMethod);
	fixture->runAllTests();
	LONGS_EQUAL(1, fixture->getFailureCount());
}

TEST(TestHarness_c, cpputest_malloc_out_of_memory)
{
    cpputest_malloc_set_out_of_memory();
    CHECK(0 == cpputest_malloc(100));

    cpputest_malloc_set_not_out_of_memory();
    void * mem = cpputest_malloc(100);
    CHECK(0 != mem);
    cpputest_free(mem);
}

TEST(TestHarness_c, cpputest_calloc)
{
   void * mem = cpputest_calloc(10, 10);
   CHECK(0 != mem);
   cpputest_free(mem);
}

TEST(TestHarness_c, cpputest_realloc_larger)
{
   const char* number_string = "123456789";

   char* mem1 = (char*)cpputest_malloc(10);

   PlatformSpecificStrCpy(mem1, number_string);
   CHECK(mem1 != 0);

   char* mem2 = (char*) cpputest_realloc(mem1, 1000);

   CHECK(mem2 != 0);
   STRCMP_EQUAL(number_string, mem2)

   cpputest_free(mem2);
}

TEST(TestHarness_c, macros)
{
   void* mem1 = malloc(10);
   void* mem2 = calloc(10, 20);
   void* mem3 = realloc(mem2, 100);
   free(mem1);
   free(mem3);
}
<commit_msg>Removed undef cplusplus<commit_after>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

extern "C" {
   #define _WCHART
   #include "CppUTest/TestHarness_c.h"

}
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/TestTestingFixture.h"
#include "CppUTest/PlatformSpecificFunctions.h"

TEST_GROUP(TestHarness_c)
{
	TestTestingFixture* fixture;
	TEST_SETUP()
	{
		fixture = new TestTestingFixture();
	}
	TEST_TEARDOWN()
	{
		delete fixture;
	}
};

void _failIntMethod()
{
	CHECK_EQUAL_C_INT(1, 2);
}

TEST(TestHarness_c, checkInt)
{
	CHECK_EQUAL_C_INT(2, 2);
	fixture->setTestFunction(_failIntMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("expected <1>\n	but was  <2>");
	fixture->assertPrintContains("arness_c");
}

void _failRealMethod()
{
	CHECK_EQUAL_C_REAL(1.0, 2.0, 0.5);
}

TEST(TestHarness_c, checkReal)
{
	CHECK_EQUAL_C_REAL(1.0, 1.1, 0.5);
	fixture->setTestFunction(_failRealMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("expected <1.000000>\n	but was  <2.000000>");
	fixture->assertPrintContains("arness_c");
}

void _failCharMethod()
{
	CHECK_EQUAL_C_CHAR('a', 'c');
}

TEST(TestHarness_c, checkChar)
{
	CHECK_EQUAL_C_CHAR('a', 'a');
	fixture->setTestFunction(_failCharMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("expected <a>\n	but was  <c>");
	fixture->assertPrintContains("arness_c");
}

void _failStringMethod()
{
	CHECK_EQUAL_C_STRING("Hello", "World");
}

TEST(TestHarness_c, checkString)
{
	CHECK_EQUAL_C_STRING("Hello", "Hello");
	fixture->setTestFunction(_failStringMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("expected <Hello>\n	but was  <World>");
	fixture->assertPrintContains("arness_c");
}

void _failTextMethod()
{
	FAIL_TEXT_C("Booo");
}

TEST(TestHarness_c, checkFailText)
{
	fixture->setTestFunction(_failTextMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("Booo");
	fixture->assertPrintContains("arness_c");
}

void _failMethod()
{
	FAIL_C();
}

TEST(TestHarness_c, checkFail)
{
	fixture->setTestFunction(_failMethod);
	fixture->runAllTests();
	LONGS_EQUAL(1, fixture->getFailureCount());
	fixture->assertPrintContains("arness_c");
}

void _CheckMethod()
{
	CHECK_C(false);
}

TEST(TestHarness_c, checkCheck)
{
	CHECK_C(true);
	fixture->setTestFunction(_CheckMethod);
	fixture->runAllTests();
	LONGS_EQUAL(1, fixture->getFailureCount());
}

TEST(TestHarness_c, cpputest_malloc_out_of_memory)
{
    cpputest_malloc_set_out_of_memory();
    CHECK(0 == cpputest_malloc(100));

    cpputest_malloc_set_not_out_of_memory();
    void * mem = cpputest_malloc(100);
    CHECK(0 != mem);
    cpputest_free(mem);
}

TEST(TestHarness_c, cpputest_calloc)
{
   void * mem = cpputest_calloc(10, 10);
   CHECK(0 != mem);
   cpputest_free(mem);
}

TEST(TestHarness_c, cpputest_realloc_larger)
{
   const char* number_string = "123456789";

   char* mem1 = (char*)cpputest_malloc(10);

   PlatformSpecificStrCpy(mem1, number_string);
   CHECK(mem1 != 0);

   char* mem2 = (char*) cpputest_realloc(mem1, 1000);

   CHECK(mem2 != 0);
   STRCMP_EQUAL(number_string, mem2)

   cpputest_free(mem2);
}

TEST(TestHarness_c, macros)
{
   void* mem1 = malloc(10);
   void* mem2 = calloc(10, 20);
   void* mem3 = realloc(mem2, 100);
   free(mem1);
   free(mem3);
}
<|endoftext|>


<commit_before>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2013-2020 Igor Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
// doctest include.
#include <doctest.h>

// Args include.
#include <Args/all.hpp>

using namespace Args;

#ifdef ARGS_WSTRING_BUILD
	using CHAR = String::value_type;
#else
	using CHAR = char;
#endif

TEST_CASE( "TestAllIsOk1" )
{
	const int argc = 7;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "100" ), SL( "4545" ), SL( "500" ),
		SL( "-f" ), SL( "local" ) };

	CmdLine cmd( argc, argv );

	Arg f( Char( SL( 'f' ) ), true, true );

	Command c( SL( "add" ), ValueOptions::ManyValues );
	c.addArg( f );

	cmd.addArg( c );

	cmd.parse();

	REQUIRE( f.isDefined() == true );
	REQUIRE( f.value() == SL( "local" ) );

	REQUIRE( c.isDefined() == true );
	REQUIRE( c.value() == SL( "100" ) );
	REQUIRE( c.values().size() == 3 );

	auto it = c.values().begin();

	REQUIRE( *it == SL( "100" ) );

	++it;

	REQUIRE( *it == SL( "4545" ) );

	++it;

	REQUIRE( *it == SL( "500" ) );
}

TEST_CASE( "WrongName1" )
{
	REQUIRE_THROWS_AS( Command c( SL( "-a" ) ), BaseException );
}

TEST_CASE( "WrongName2" )
{
	REQUIRE_THROWS_AS( Command c( SL( "--name" ) ), BaseException );
}

TEST_CASE( "TestNotDefinedRequiredArgInCommand" )
{
	const int argc = 5;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "100" ), SL( "4545" ), SL( "500" ) };

	CmdLine cmd( argc, argv );

	Arg f( Char( SL( 'f' ) ), true, true );

	Command c( SL( "add" ), ValueOptions::ManyValues );
	c.addArg( f );

	cmd.addArg( c );

	REQUIRE_THROWS_AS( cmd.parse(), BaseException );
}

TEST_CASE( "TestRedifinition" )
{
	const int argc = 5;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "file" ), SL( "1.txt" ), SL( "del" ) };

	CmdLine cmd( argc, argv );

	cmd.addCommand( SL( "add" ), ValueOptions::NoValue, true )
			.addCommand( SL( "file" ), ValueOptions::OneValue, false )
			.end()
		.end()
		.addCommand( SL( "del" ), ValueOptions::NoValue, true )
			.addCommand( SL( "file" ), ValueOptions::OneValue, false )
			.end()
		.end()
	.end();

	REQUIRE_THROWS_AS( cmd.parse(), BaseException );
}

TEST_CASE( "TestOkWithSubCommand" )
{
	const int argc = 4;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "file" ), SL( "1.txt" ) };

	CmdLine cmd( argc, argv );

	cmd.addCommand( SL( "add" ), ValueOptions::NoValue, true )
			.addCommand( SL( "file" ), ValueOptions::OneValue, false )
			.end()
		.end()
		.addCommand( SL( "del" ), ValueOptions::NoValue, true )
			.addCommand( SL( "file" ), ValueOptions::OneValue, false )
			.end()
		.end()
	.end();

	cmd.parse();

	REQUIRE( cmd.isDefined( SL( "add" ) ) );
	REQUIRE( cmd.isDefined( SL( "file" ) ) );

	const auto v = cmd.values( SL( "file" ) );

	REQUIRE( v.size() == 1 );
	REQUIRE( v.front() == SL( "1.txt" ) );
}

TEST_CASE( "TestManyArgs" )
{
	const int argc = 5;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "100" ), SL( "4545" ), SL( "500" ) };

	CmdLine cmd( argc, argv );

	Arg f( Char( SL( 'f' ) ), true, true );

	Command c( SL( "add" ), ValueOptions::OneValue );
	c.addArg( f );

	cmd.addArg( c );

	REQUIRE_THROWS_AS( cmd.parse(), BaseException );
}

TEST_CASE( "TestRedefinition" )
{
	const int argc = 3;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "del" ) };

	CmdLine cmd( argc, argv );

	Command c( SL( "add" ) );
	Command d( SL( "del" ) );

	cmd.addArg( c );
	cmd.addArg( d );

	REQUIRE_THROWS_AS( cmd.parse(), BaseException );
}

TEST_CASE( "TestNotDefinedCommand" )
{
	const int argc = 1;
	const CHAR * argv[ argc ] = { SL( "program.exe" ) };

	CmdLine cmd( argc, argv, CmdLine::CommandIsRequired );

	Command c( SL( "add" ) );
	Command d( SL( "del" ) );

	cmd.addArg( c );
	cmd.addArg( d );

	REQUIRE_THROWS_AS( cmd.parse(), BaseException );
}

TEST_CASE( "TestAllIsOk2" )
{
	const int argc = 7;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "100" ), SL( "4545" ), SL( "500" ),
		SL( "-f" ), SL( "local" ) };

	CmdLine cmd( argc, argv );

	Arg f( Char( SL( 'f' ) ), true );

	Command c( SL( "add" ), ValueOptions::ManyValues );
	c.addArg( f );

	cmd.addArg( c );

	cmd.parse();

	REQUIRE( f.isDefined() == true );
	REQUIRE( f.value() == SL( "local" ) );

	REQUIRE( c.isDefined() == true );
	REQUIRE( c.value() == SL( "100" ) );
	REQUIRE( c.values().size() == 3 );

	auto it = c.values().begin();

	REQUIRE( *it == SL( "100" ) );

	++it;

	REQUIRE( *it == SL( "4545" ) );

	++it;

	REQUIRE( *it == SL( "500" ) );
}

TEST_CASE( "TestAllIsOk3" )
{
	const int argc = 5;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "100" ), SL( "4545" ), SL( "500" ) };

	CmdLine cmd( argc, argv );

	Arg f( Char( SL( 'f' ) ), true );

	Command c( SL( "add" ), ValueOptions::ManyValues );
	c.addArg( f );

	cmd.addArg( c );

	cmd.parse();

	REQUIRE( f.isDefined() == false );

	REQUIRE( c.isDefined() == true );
	REQUIRE( c.value() == SL( "100" ) );
	REQUIRE( c.values().size() == 3 );

	auto it = c.values().begin();

	REQUIRE( *it == SL( "100" ) );

	++it;

	REQUIRE( *it == SL( "4545" ) );

	++it;

	REQUIRE( *it == SL( "500" ) );
}

TEST_CASE( "TestAllIsOk4" )
{
	const int argc = 1;
	const CHAR * argv[ argc ] = { SL( "program.exe" ) };

	CmdLine cmd( argc, argv );

	Command c( SL( "add" ) );
	Command d( SL( "del" ) );

	cmd.addArg( c );
	cmd.addArg( d );

	REQUIRE( c.isDefined() == false );
	REQUIRE( d.isDefined() == false );
}

TEST_CASE( "TestAllIsOk5" )
{
	const int argc = 1;
	const CHAR * argv[ argc ] = { SL( "program.exe" ) };

	CmdLine cmd( argc, argv );

	Command a( SL( "add" ), ValueOptions::ManyValues );

	cmd.addArg( a );

	cmd.parse();

	REQUIRE( a.isDefined() == false );
	REQUIRE( a.value().empty() );
	REQUIRE( a.values().empty() );
	REQUIRE( a.defaultValue().empty() );
	REQUIRE( a.defaultValues().empty() );
}

TEST_CASE( "TestAllIsOk6" )
{
	const int argc = 1;
	const CHAR * argv[ argc ] = { SL( "program.exe" ) };

	CmdLine cmd( argc, argv );

	Command a( SL( "add" ), ValueOptions::ManyValues );
	a.setDefaultValue( SL( "default" ) );

	cmd.addArg( a );

	cmd.parse();

	REQUIRE( a.isDefined() == false );
	REQUIRE( a.value() == SL( "default" ) );
	REQUIRE( a.values().size() == 1 );
	REQUIRE( a.values().front() == SL( "default" ) );
	REQUIRE( a.defaultValue() == SL( "default" ) );
	REQUIRE( a.defaultValues().size() == 1 );
	REQUIRE( a.defaultValues().front() == SL( "default" ) );
}

TEST_CASE( "TestMisspelling" )
{
	CmdLine cmd;

	Command add( SL( "add" ) );

	Command file( SL( "file" ) );
	add.addCommand( file );

	cmd.addArg( add );

	StringList correct;

	REQUIRE( add.isMisspelledName( SL( "dad" ), correct ) );
	REQUIRE( correct.size() == 1 );
	REQUIRE( correct.front() == SL( "add" ) );

	correct.clear();

	REQUIRE( add.isMisspelledName( SL( "fiel" ), correct ) );
	REQUIRE( correct.size() == 1 );
	REQUIRE( correct.front() == SL( "file" ) );

	correct.clear();

	REQUIRE( !add.isMisspelledCommand( SL( "fiel" ), correct ) );

	REQUIRE( add.isMisspelledCommand( SL( "dad" ), correct ) );
	REQUIRE( correct.size() == 1 );
	REQUIRE( correct.front() == SL( "add" ) );

	correct.clear();

	REQUIRE( cmd.isMisspelledName( SL( "dad" ), correct ) );
	REQUIRE( correct.size() == 1 );
	REQUIRE( correct.front() == SL( "add" ) );
}

TEST_CASE( "TestStuff" )
{
	Command add( SL( "add" ) );

	ArgIface & a = add;

	REQUIRE( a.description().empty() );
	REQUIRE( a.longDescription().empty() );

	add.setDescription( SL( "desc" ) );

	REQUIRE( a.description() == SL( "desc" ) );
	REQUIRE( a.longDescription() == SL( "desc" ) );

	add.setLongDescription( SL( "long" ) );

	REQUIRE( a.description() == SL( "desc" ) );
	REQUIRE( a.longDescription() == SL( "long" ) );

	REQUIRE( a.valueSpecifier().empty() );

	add.setValueSpecifier( SL( "val" ) );

	REQUIRE( a.valueSpecifier() == SL( "val" ) );

	REQUIRE( !a.isDefined() );

	GroupIface & g = add;

	REQUIRE( !g.isRequired() );

	g.setRequired();

	REQUIRE( !g.isRequired() );

	Command c( SL( "c" ), ValueOptions::ManyValues );

	ArgIface & a2 = c;

	REQUIRE( a2.isWithValue() );
}
<commit_msg>Add test.<commit_after>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2013-2020 Igor Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
// doctest include.
#include <doctest.h>

// Args include.
#include <Args/all.hpp>

using namespace Args;

#ifdef ARGS_WSTRING_BUILD
	using CHAR = String::value_type;
#else
	using CHAR = char;
#endif

TEST_CASE( "TestAllIsOk1" )
{
	const int argc = 7;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "100" ), SL( "4545" ), SL( "500" ),
		SL( "-f" ), SL( "local" ) };

	CmdLine cmd( argc, argv );

	Arg f( Char( SL( 'f' ) ), true, true );

	Command c( SL( "add" ), ValueOptions::ManyValues );
	c.addArg( f );

	cmd.addArg( c );

	cmd.parse();

	REQUIRE( f.isDefined() == true );
	REQUIRE( f.value() == SL( "local" ) );

	REQUIRE( c.isDefined() == true );
	REQUIRE( c.value() == SL( "100" ) );
	REQUIRE( c.values().size() == 3 );

	auto it = c.values().begin();

	REQUIRE( *it == SL( "100" ) );

	++it;

	REQUIRE( *it == SL( "4545" ) );

	++it;

	REQUIRE( *it == SL( "500" ) );
}

TEST_CASE( "WrongName1" )
{
	REQUIRE_THROWS_AS( Command c( SL( "-a" ) ), BaseException );
}

TEST_CASE( "WrongName2" )
{
	REQUIRE_THROWS_AS( Command c( SL( "--name" ) ), BaseException );
}

TEST_CASE( "TestNotDefinedRequiredArgInCommand" )
{
	const int argc = 5;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "100" ), SL( "4545" ), SL( "500" ) };

	CmdLine cmd( argc, argv );

	Arg f( Char( SL( 'f' ) ), true, true );

	Command c( SL( "add" ), ValueOptions::ManyValues );
	c.addArg( f );

	cmd.addArg( c );

	REQUIRE_THROWS_AS( cmd.parse(), BaseException );
}

TEST_CASE( "TestRedifinition" )
{
	const int argc = 5;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "file" ), SL( "1.txt" ), SL( "del" ) };

	CmdLine cmd( argc, argv );

	cmd.addCommand( SL( "add" ), ValueOptions::NoValue, true )
			.addCommand( SL( "file" ), ValueOptions::OneValue, false )
			.end()
		.end()
		.addCommand( SL( "del" ), ValueOptions::NoValue, true )
			.addCommand( SL( "file" ), ValueOptions::OneValue, false )
			.end()
		.end()
	.end();

	REQUIRE_THROWS_AS( cmd.parse(), BaseException );
}

TEST_CASE( "TestDeepRedifinition" )
{
	const int argc = 5;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "file" ), SL( "1.txt" ), SL( "url" ) };

	CmdLine cmd( argc, argv );

	cmd.addCommand( SL( "add" ), ValueOptions::NoValue, true )
			.addCommand( SL( "file" ), ValueOptions::OneValue, false )
			.end()
			.addCommand( SL( "url" ), ValueOptions::OneValue, false )
			.end()
		.end()
		.addCommand( SL( "del" ), ValueOptions::NoValue, true )
			.addCommand( SL( "file" ), ValueOptions::OneValue, false )
			.end()
			.addCommand( SL( "url" ), ValueOptions::OneValue, false )
			.end()
		.end()
	.end();

	REQUIRE_THROWS_AS( cmd.parse(), BaseException );
}

TEST_CASE( "TestOkWithSubCommand" )
{
	const int argc = 4;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "file" ), SL( "1.txt" ) };

	CmdLine cmd( argc, argv );

	cmd.addCommand( SL( "add" ), ValueOptions::NoValue, true )
			.addCommand( SL( "file" ), ValueOptions::OneValue, false )
			.end()
		.end()
		.addCommand( SL( "del" ), ValueOptions::NoValue, true )
			.addCommand( SL( "file" ), ValueOptions::OneValue, false )
			.end()
		.end()
	.end();

	cmd.parse();

	REQUIRE( cmd.isDefined( SL( "add" ) ) );
	REQUIRE( cmd.isDefined( SL( "file" ) ) );

	const auto v = cmd.values( SL( "file" ) );

	REQUIRE( v.size() == 1 );
	REQUIRE( v.front() == SL( "1.txt" ) );
}

TEST_CASE( "TestManyArgs" )
{
	const int argc = 5;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "100" ), SL( "4545" ), SL( "500" ) };

	CmdLine cmd( argc, argv );

	Arg f( Char( SL( 'f' ) ), true, true );

	Command c( SL( "add" ), ValueOptions::OneValue );
	c.addArg( f );

	cmd.addArg( c );

	REQUIRE_THROWS_AS( cmd.parse(), BaseException );
}

TEST_CASE( "TestRedefinition" )
{
	const int argc = 3;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "del" ) };

	CmdLine cmd( argc, argv );

	Command c( SL( "add" ) );
	Command d( SL( "del" ) );

	cmd.addArg( c );
	cmd.addArg( d );

	REQUIRE_THROWS_AS( cmd.parse(), BaseException );
}

TEST_CASE( "TestNotDefinedCommand" )
{
	const int argc = 1;
	const CHAR * argv[ argc ] = { SL( "program.exe" ) };

	CmdLine cmd( argc, argv, CmdLine::CommandIsRequired );

	Command c( SL( "add" ) );
	Command d( SL( "del" ) );

	cmd.addArg( c );
	cmd.addArg( d );

	REQUIRE_THROWS_AS( cmd.parse(), BaseException );
}

TEST_CASE( "TestAllIsOk2" )
{
	const int argc = 7;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "100" ), SL( "4545" ), SL( "500" ),
		SL( "-f" ), SL( "local" ) };

	CmdLine cmd( argc, argv );

	Arg f( Char( SL( 'f' ) ), true );

	Command c( SL( "add" ), ValueOptions::ManyValues );
	c.addArg( f );

	cmd.addArg( c );

	cmd.parse();

	REQUIRE( f.isDefined() == true );
	REQUIRE( f.value() == SL( "local" ) );

	REQUIRE( c.isDefined() == true );
	REQUIRE( c.value() == SL( "100" ) );
	REQUIRE( c.values().size() == 3 );

	auto it = c.values().begin();

	REQUIRE( *it == SL( "100" ) );

	++it;

	REQUIRE( *it == SL( "4545" ) );

	++it;

	REQUIRE( *it == SL( "500" ) );
}

TEST_CASE( "TestAllIsOk3" )
{
	const int argc = 5;
	const CHAR * argv[ argc ] = { SL( "program.exe" ),
		SL( "add" ), SL( "100" ), SL( "4545" ), SL( "500" ) };

	CmdLine cmd( argc, argv );

	Arg f( Char( SL( 'f' ) ), true );

	Command c( SL( "add" ), ValueOptions::ManyValues );
	c.addArg( f );

	cmd.addArg( c );

	cmd.parse();

	REQUIRE( f.isDefined() == false );

	REQUIRE( c.isDefined() == true );
	REQUIRE( c.value() == SL( "100" ) );
	REQUIRE( c.values().size() == 3 );

	auto it = c.values().begin();

	REQUIRE( *it == SL( "100" ) );

	++it;

	REQUIRE( *it == SL( "4545" ) );

	++it;

	REQUIRE( *it == SL( "500" ) );
}

TEST_CASE( "TestAllIsOk4" )
{
	const int argc = 1;
	const CHAR * argv[ argc ] = { SL( "program.exe" ) };

	CmdLine cmd( argc, argv );

	Command c( SL( "add" ) );
	Command d( SL( "del" ) );

	cmd.addArg( c );
	cmd.addArg( d );

	REQUIRE( c.isDefined() == false );
	REQUIRE( d.isDefined() == false );
}

TEST_CASE( "TestAllIsOk5" )
{
	const int argc = 1;
	const CHAR * argv[ argc ] = { SL( "program.exe" ) };

	CmdLine cmd( argc, argv );

	Command a( SL( "add" ), ValueOptions::ManyValues );

	cmd.addArg( a );

	cmd.parse();

	REQUIRE( a.isDefined() == false );
	REQUIRE( a.value().empty() );
	REQUIRE( a.values().empty() );
	REQUIRE( a.defaultValue().empty() );
	REQUIRE( a.defaultValues().empty() );
}

TEST_CASE( "TestAllIsOk6" )
{
	const int argc = 1;
	const CHAR * argv[ argc ] = { SL( "program.exe" ) };

	CmdLine cmd( argc, argv );

	Command a( SL( "add" ), ValueOptions::ManyValues );
	a.setDefaultValue( SL( "default" ) );

	cmd.addArg( a );

	cmd.parse();

	REQUIRE( a.isDefined() == false );
	REQUIRE( a.value() == SL( "default" ) );
	REQUIRE( a.values().size() == 1 );
	REQUIRE( a.values().front() == SL( "default" ) );
	REQUIRE( a.defaultValue() == SL( "default" ) );
	REQUIRE( a.defaultValues().size() == 1 );
	REQUIRE( a.defaultValues().front() == SL( "default" ) );
}

TEST_CASE( "TestMisspelling" )
{
	CmdLine cmd;

	Command add( SL( "add" ) );

	Command file( SL( "file" ) );
	add.addCommand( file );

	cmd.addArg( add );

	StringList correct;

	REQUIRE( add.isMisspelledName( SL( "dad" ), correct ) );
	REQUIRE( correct.size() == 1 );
	REQUIRE( correct.front() == SL( "add" ) );

	correct.clear();

	REQUIRE( add.isMisspelledName( SL( "fiel" ), correct ) );
	REQUIRE( correct.size() == 1 );
	REQUIRE( correct.front() == SL( "file" ) );

	correct.clear();

	REQUIRE( !add.isMisspelledCommand( SL( "fiel" ), correct ) );

	REQUIRE( add.isMisspelledCommand( SL( "dad" ), correct ) );
	REQUIRE( correct.size() == 1 );
	REQUIRE( correct.front() == SL( "add" ) );

	correct.clear();

	REQUIRE( cmd.isMisspelledName( SL( "dad" ), correct ) );
	REQUIRE( correct.size() == 1 );
	REQUIRE( correct.front() == SL( "add" ) );
}

TEST_CASE( "TestStuff" )
{
	Command add( SL( "add" ) );

	ArgIface & a = add;

	REQUIRE( a.description().empty() );
	REQUIRE( a.longDescription().empty() );

	add.setDescription( SL( "desc" ) );

	REQUIRE( a.description() == SL( "desc" ) );
	REQUIRE( a.longDescription() == SL( "desc" ) );

	add.setLongDescription( SL( "long" ) );

	REQUIRE( a.description() == SL( "desc" ) );
	REQUIRE( a.longDescription() == SL( "long" ) );

	REQUIRE( a.valueSpecifier().empty() );

	add.setValueSpecifier( SL( "val" ) );

	REQUIRE( a.valueSpecifier() == SL( "val" ) );

	REQUIRE( !a.isDefined() );

	GroupIface & g = add;

	REQUIRE( !g.isRequired() );

	g.setRequired();

	REQUIRE( !g.isRequired() );

	Command c( SL( "c" ), ValueOptions::ManyValues );

	ArgIface & a2 = c;

	REQUIRE( a2.isWithValue() );
}
<|endoftext|>