text:
#ifndef skye_detail_function_assertion_hpp
#define skye_detail_function_assertion_hpp

#include <skye/detail/validator.hpp>
#include <boost/range/adaptor/reversed.hpp>

#include <list>
#include <memory>
#include <string>
#include <sstream>
#include <type_traits>

namespace skye {
namespace detail {

/**
 * Build a validation check, executes it and then reports the results.
 *
 * Somebody more clever than me can figure out how to implement this
 * without lists and other additional data structures, seems like an
 * intrusive list with a sentinel should be able to handle it.  And
 * maybe use a form of the "Chain of Responsibility" pattern to
 * implement the iteration.  The current implementation works as
 * follows.  The user makes a series of chained calls like this:
 *
 * @code
 * mock_function<void(int,std::string const&)> f;
 * f(1, "abc");
 * f(2, "bcd");
 * f(2, "bcd");
 * f(2, "bcd");
 *
 * f.check_called().exactly(3).with(2, "bcd");
 * @endcode
 *
 * After some minimal pre-processor macro hidden inside that
 * check_called() member-function looking thing, the mock_function
 * constructs an instance of this class.  The chain of calls
 * exactly().with(), produces the following list of validators:
 *
 * @code
 * f.check_called().exactly(3).with(2, "bcd");
 * // with_validator(2, "bcd") -> exactly(3)
 * @endverbatim
 *
 * Naturally this sequence is constructor in steps, growing with each
 * call as shown here:
 *
 * @code
 * f.check_called();
 *
 * f.check_called().exactly(3);
 * // exactly(3)
 *
 * f.check_called().exactly(3).with(2, "bcd");
 * // with_validator(2, "bcd") -> exactly(3)
 *
 * @endcode
 *
 * The never() quantifier short-circuits validation, that means that
 * whatever results from subsequent validators are ignored.
 *
 * @tparam capture_strategy_T how was the underlying mock function
 * capturing its arguments.
 * @tparam reporting_strategy_T how are assertion results supposed to
 * be reported.
 */
template<typename capture_strategy_T,
         typename reporting_strategy_T>
class function_assertion {
 public:
  typedef capture_strategy_T capture_strategy;
  typedef reporting_strategy_T reporting_strategy;
  typedef typename capture_strategy::value_type value_type;
  typedef typename capture_strategy::capture_sequence sequence_type;
  typedef std::shared_ptr<validator<sequence_type>> pointer;

  function_assertion(
      sequence_type const & sequence, location const & where)
      : validators_()
      , sequence_(sequence)
      , where_(where) {
    reporting_strategy::checkpoint(where_);
  }
  ~function_assertion() {
    validate();
  }

  //@{
  /**
   * @name Validator factory functions.
   */
  /// Requires at least (inclusive) this many calls after filtering.
  function_assertion & at_least(std::size_t min) {
    add_validator(pointer(new at_least_validator<sequence_type>(min)));
    return *this;
  }

  /// Requires at most (inclusive) this many calls after filtering.
  function_assertion & at_most(std::size_t max) {
    add_validator(pointer(new at_most_validator<sequence_type>(max)));
    return *this;
  }

  /// Requires exactly this many calls after filtering.
  function_assertion & exactly(std::size_t expected) {
    add_validator(pointer(
        new exactly_validator<sequence_type,false>(expected)));
    return *this;
  }

  /// Requires exactly one call after filtering.
  function_assertion & once() {
    return exactly(1);
  }

  /// Requires no calls after filtering.
  function_assertion & never() {
    add_validator(pointer(
        new exactly_validator<sequence_type,true>(0)));
    return *this;
  }

  /// Requires between @a min and @a max calls, both inclusive, after
  /// filtering.
  function_assertion & between(std::size_t min, std::size_t max) {
    return at_least(min).at_most(max);
  }

  /// Filters to only the calls with the given value.
  template<typename... arg_types>
  function_assertion & with(arg_types&&... args) {
    auto match = capture_strategy::capture(std::forward<arg_types>(args)...);
    return with(std::move(match));
  }

  function_assertion & with(value_type && m) {
    value_type match(m);
    std::ostringstream os;
    capture_strategy::stream(os, match);
    add_validator(
        make_negative_filter<sequence_type>( os.str(), [match](value_type v) {
            return not capture_strategy::equals(match, v);
          }));
    return *this;
  }

  //@}

 private:
  void add_validator(pointer v) {
    validators_.push_back(v);
  }

  void validate() {
    sequence_type sequence;
    sequence.swap(sequence_); // We no longer need the contents of sequence_

    for (auto i : boost::adaptors::reverse(validators_)) {
      i->filter(sequence);
    }

    validation_result r{true,false,std::string()};
    std::string msg = "check_called()";
    for (auto i : validators_) {
      r = i->validate(sequence);
      msg += r.msg;
      if (not r.pass or r.short_circuit) {
        break;
      }
    }
    if (r.pass) {
      reporting_strategy::report_success(where_, msg);
    } else {
      reporting_strategy::report_failure(where_, msg);
    }
  }

 private:
  std::list<pointer> validators_;
  sequence_type sequence_;
  location where_;
};

/**
 * Validate using BOOST_CHECK_* semantics, i.e., errors are not fatal.
 *
 * The use of a macro here is required to capture the file and line
 * number.  We are allowing a macro with a short name because this
 * is intended to be used in test code only, so any namespace
 * pollution can be kept under control.
 */
#define check_called() check(SKYE_LOCATION)

/**
 * Validate using BOOST_REQUIRE_* semantics, i.e., errors terminate
 * the test.
 *
 * The use of a macro here is required to capture the file and line
 * number.  We are allowing a macro with a short name because this
 * is intended to be used in test code only, so any namespace
 * pollution can be kept under control.
 */
#define require_called() require(SKYE_LOCATION)

} // namespace detail
} // namespace skye

#endif // skye_detail_function_assertion_hpp

max_stars_repo_name: coryan/Skye

max_issues_repo_name: coryan/Skye

max_forks_repo_name: coryan/Skye


text:
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//                          *** w90.hpp ***                                  //
//                                                                           //
// class to manage methods relating to wannier90 hamiltonian                 //
// templatized over dimension of the mesh                                    //
//                                                                           //
// created November 27, 2017                                                 //
// copyright Christopher N. Singh Binghamton University Physics              //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#ifndef W90_hpp
#define W90_hpp

#include <cassert>
#include <Eigen/Dense>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>

class W90
{
public:
	W90(std::string hr_file);

	Eigen::MatrixXcd fft(const Eigen::Vector3d& k);

private:
	Eigen::ArrayXXd hr;

	inline std::complex<double> tij(int nn, const Eigen::Vector3d& k);
};

#endif /* W90_hpp */

ext: hpp


text:
//!
//! Contains the implementation of Monte Carlo Markov Chain simulations.
//!
//! \file infer/mcmc.cpp
//! \author Lachlan McCalman
//! \author Darren Shen
//! \date 2014
//! \license Affero General Public License version 3 or later
//! \copyright (c) 2014, NICTA
//!

#pragma once

#include <limits>
#include <random>
#include <iomanip>
#include <chrono>
#include <Eigen/Dense>
#include <boost/circular_buffer.hpp>
#include <iostream>
#include <glog/logging.h>

#include "db/db.hpp"
#include "app/settings.hpp"
#include "infer/chainarray.hpp"
#include "infer/diagnostics.hpp"
#include "comms/transport.hpp"

namespace stateline
{
  namespace mcmc
  {
    //! Represents a Markov Chain Monte Carlo sampler that returns samples from
    //! a distribution.
    //!
    class Sampler
    {
    public:
      //! Create a new sampler.
      //!
      //! \param s Settings to tune various parameters of the MCMC.
      //! \param d Settings for configuring the database for storing samples.
      //! \param stateDim The number of dimensions in each sample.
      //! \param interrupted A flag used to monitor whether the sampler has been interrupted.
      //!
      Sampler(const MCMCSettings& s, const DBSettings& d, uint stateDim, volatile bool& interrupted)
          : db_(d),
            chains_(s.stacks, s.chains, s.initialTempFactor, s.proposalInitialSigma, s.initialSigmaFactor, db_, s.cacheLength, d.recover),
            lengths_(s.stacks * s.chains, 0),
            propStates_(s.stacks * s.chains, stateDim),
            locked_(s.stacks * s.chains, false),
            nextChainBeta_(s.stacks * s.chains),
            nAcceptsGlobal_(s.stacks * s.chains, 0),
            nSwapsGlobal_(s.stacks * (s.chains), 0),
            nSwapAttemptsGlobal_(s.stacks * s.chains, 0),
            sigmas_(s.stacks * s.chains),
            betas_(s.stacks * s.chains),
            acceptRates_(s.stacks * s.chains),
            swapRates_(s.stacks * s.chains),
            lowestEnergies_(s.stacks * s.chains),
            s_(s),
            recover_(d.recover),
            numOutstandingJobs_(0),
            interrupted_(interrupted),
            context_(1)
      {
        // Initialise for logging purposes
        for (uint i = 0; i < s.chains * s.stacks; i++)
        {
          lengths_[i] = chains_.length(i);
          sigmas_[i] = chains_.sigma(i);
          betas_[i] = chains_.beta(i);
          nextChainBeta_[i] = chains_.beta(i);
          acceptRates_[i] = 1;
          swapRates_[i] = 0;
          lowestEnergies_[i] = std::numeric_limits<double>::infinity();
          acceptBuffers_.push_back(boost::circular_buffer<bool>(s.adaptionLength));
          swapBuffers_.push_back(boost::circular_buffer<bool>(s.adaptionLength / s.swapInterval + 1));
          nAcceptsGlobal_[i] = 1;
          acceptBuffers_[i].push_back(true); // first state always accepts
          nSwapsGlobal_[i] = 0;
          nSwapAttemptsGlobal_[i] = 1;
          swapBuffers_[i].push_back(false); // gets rid of a nan, not really needed
        }
      }

      //! Run the sampler for a period of time.
      //!
      //! \param policy Async policy to evaluate states.
      //! \param initialStates Initial chain states. Ignored if recovering.
      //! \param propFn The proposal function.
      //! \param numSeconds The number of seconds to run the MCMC for.
      //!
      template<class AsyncPolicy, class PropFn>
      void run(AsyncPolicy &policy, const std::vector<Eigen::VectorXd>& initialStates, PropFn &propFn, uint numSeconds)
      {
        using namespace std::chrono;

        // Used for publishing statistics to visualisation server.
        zmq::socket_t publisher(context_, ZMQ_PUB);
        publisher.bind("tcp://*:5556");

        // Record the starting time of the MCMC
        steady_clock::time_point startTime = steady_clock::now();

        // Initialise the chains if we're not recovering
        if (!recover_)
        {
          initialise(policy, initialStates);
        }

        // Start all the chains from hottest to coldest
        for (uint i = 0; i < chains_.numTotalChains(); i++)
        {
          uint c = chains_.numTotalChains() - i - 1;
          propose(policy, c, propFn);
        }

        // Initialise the convergence criteria
        uint stateDim = initialStates[0].size();
        EpsrConvergenceCriteria cc(chains_.numStacks(), stateDim);

        // Listen for replies. As soon as a new state comes back,
        // add it to the corresponding chain, and submit a new proposed state
        auto lastLogTime = steady_clock::now();
        auto lastPrintTime = steady_clock::now();
        while (duration_cast<seconds>(steady_clock::now() - startTime).count() < numSeconds && !interrupted_)
        {
          std::pair<uint, double> result;

          // Wait a for reply
          try
          {
            result = policy.retrieve();
          }
          catch (...)
          {
            VLOG(3) << "Comms error -- probably shutting down";
          }

          // If we weree interrupted this state will be garbage
          if (interrupted_)
            break;

          numOutstandingJobs_--;
          uint id = result.first;
          double energy = result.second;

          // Check if this chain is either the coldest or the hottest
          bool isHottestChainInStack = id % chains_.numChains() == chains_.numChains() - 1;
          bool isColdestChainInStack = id % chains_.numChains() == 0;

          // Handle the new proposal and add a new state to the chain
          State propState { propStates_.row(id), energy, chains_.beta(id), false, SwapType::NoAttempt };
          bool propAccepted = chains_.append(id, propState);
          lengths_[id] += 1;
          updateAccepts(id, propAccepted);

          // Update the convergence test if this is the coldest chain in a stack
          if (isColdestChainInStack && chains_.numChains() > 1 && chains_.numStacks() > 1)
          {
            cc.update(id / chains_.numChains(), chains_.lastState(id).sample);
          }

          // Check if this chain was locked. If it was locked, it means that
          // the chain above (hotter) locked it so that it can swap with it
          if (locked_[id])
          {
            // Try swapping this chain with the one above it
            bool swapAccepted = chains_.swap(id, id + 1);
            updateSwaps(id + 1, swapAccepted);
            // Unlock this chain, propgating the lock downwards
            unlock(policy, id, propFn);
          }
          else if (isHottestChainInStack && lengths_[id] % s_.swapInterval == 0 && chains_.numChains() > 1)
          {
            // The hottest chain is ready to swap. Lock the next chain
            // to prevent it from proposing any more
            locked_[id - 1] = true;
          }
          else
          {
            // This chain is not locked, so we can propose
            try
            {
              propose(policy, id, propFn);
            }
            catch (...)
            {
              VLOG(3) << "Comms error -- probably shutting down";
            }
          }

          // Check again after a new interaction with comms
          if (interrupted_)
            break;

          // Log the best energy state so far
          lowestEnergies_[id] = std::min(lowestEnergies_[id], chains_.lastState(id).energy);

          // Check if we need to adapt the step size for this chain
          if (lengths_[id] % s_.proposalAdaptInterval == 0)
          {
            adaptSigma(id);
          }

          // Update the temperature which might have changed while waiting
          chains_.setBeta(id, nextChainBeta_[id]);
          betas_[id] = nextChainBeta_[id];
          // Check for adapting the temperatures of all the chains but the 1st
          if (lengths_[id] % s_.betaAdaptInterval == 0 && !isColdestChainInStack)
          {
            adaptBeta(id);
          }

          // Update the accept and swap rates
          if (duration_cast<milliseconds>(steady_clock::now() - lastLogTime).count() > 50)
          {
            lastLogTime = steady_clock::now();

            std::stringstream s;
            s << "\n\nChainID  Length  MinEngy  CurrEngy    Sigma      AcptRt    GlbAcptRt    Beta     SwapRt   GlbSwapRt\n";
            s << "-----------------------------------------------------------------------------------------------------\n";
            for (uint i = 0; i < chains_.numTotalChains(); i++)
            {
              if (i % chains_.numChains() == 0 && i != 0)
                s << '\n';
              s << std::setprecision(6) << std::showpoint << i << " " << std::setw(9) << lengths_[i] << " " << std::setw(10)
                  << lowestEnergies_[i] << " " << std::setw(10) << chains_.lastState(i).energy << " " << std::setw(10) << sigmas_[i] << " "
                  << std::setw(10) << acceptRates_[i] << " " << std::setw(10) << nAcceptsGlobal_[i] / (double) lengths_[i] << " "
                  << std::setw(10) << betas_[i] << " " << std::setw(10) << swapRates_[i] << " " << std::setw(10)
                  << nSwapsGlobal_[i] / (double) nSwapAttemptsGlobal_[i] << " \n";
            }

            // Quick and dirty way to get the data to the visualisation server
            comms::sendString(publisher, s.str());

            if (duration_cast<milliseconds>(steady_clock::now() - lastPrintTime).count() > 500)
            {
              lastPrintTime = steady_clock::now();

              LOG(INFO)<< s.str() << "\n";

              if (chains_.numStacks() > 1 && chains_.numChains() > 1)
              {
                if (cc.hasConverged())
                {
                  LOG(INFO)<< "converged: true ("<< cc.rHat().transpose() << " < 1.1)";
                }
                else
                {
                  LOG(INFO) << "converged: false ("<< cc.rHat().transpose() << " > 1.1)";
                }
              }
            }
          }
        }

        // Time limit reached. We need to now retrieve all outstanding job results.
        if (!interrupted_)
        {
          while (numOutstandingJobs_--)
          {
            auto result = policy.retrieve();
            uint id = result.first;
            double energy = result.second;
            State propState { propStates_.row(id), energy, chains_.beta(id), false, SwapType::NoAttempt };
            bool propAccepted = chains_.append(id, propState);
            lengths_[id] += 1;
            updateAccepts(id, propAccepted);
          }
        }
        else
        {
          LOG(INFO)<< "Inference interrupted by user: Exiting.";
        }

        // Manually flush any chain states that are in memory to disk
        for (uint i = 0; i < chains_.numTotalChains(); i++)
        {
          chains_.flushCache(i);
        }

        if (cc.hasConverged())
        {
          LOG(INFO)<< "MCMC has converged";
        }
        else
        {
          LOG(INFO) << "WARNING: MCMC has not converged";
        }

        LOG(INFO)<<"Length of chain 0: " << lengths_[0];
    }

    //! Get the MCMC chain array.
    //!
    //! \return A copy of the chain array.
    //!
    ChainArray chains()
    {
      return chains_;
    }

    //! Get the MCMC chain array.
    //!
    //! \return A const reference to the chain array.
    //!
    const ChainArray &chains() const
    {
      return chains_;
    }

  private:

    //! Initialise the sampler.
    //!
    //! \param policy Async policy to evaluate states.
    //! \param initialStates A list containing the initial states of the chains.
    //!
    template <class AsyncPolicy>
    void initialise(AsyncPolicy &policy, const std::vector<Eigen::VectorXd>& initialStates)
    {
      // Evaluate the initial states of the chains
      for (uint i = 0; i < chains_.numTotalChains(); i++)
      {
        propStates_.row(i) = initialStates[i];
        policy.submit(i, propStates_.row(i));
      }

      // Retrieve the energies and temperatures for the initial states
      for (uint i = 0; i < chains_.numTotalChains(); i++)
      {
        auto result = policy.retrieve();
        uint id = result.first;
        double energy = result.second;
        State s
        { initialStates[id], energy, chains_.beta(id), true, SwapType::NoAttempt};
        chains_.initialise(id, s);
      }
    }

    //! Propose a new state through an async policy.
    //!
    //! \param policy Async policy to evaluate proposals.
    //! \param id The id of the chain that is proposing.
    //! \param propFn The proposal function.
    //!
    template <class AsyncPolicy, class PropFn>
    void propose(AsyncPolicy &policy, uint id, PropFn &propFn)
    {
      propStates_.row(id) = propFn(chains_.lastState(id).sample, chains_.sigma(id));
      policy.submit(id, propStates_.row(id));
      numOutstandingJobs_++;
    }

    //! Unlock a chain and reactivate any chains that were waiting for it.
    //!
    //! \param policy Async policy to evulate proposals.
    //! \param id The id of the chain to unlock.
    //! \param propFn The proposal function.
    //!
    template <class AsyncPolicy, class PropFn>
    void unlock(AsyncPolicy &policy, uint id, PropFn &propFn)
    {
      // Unlock this chain
      locked_[id] = false;

      // The hotter chain no longer has to wait for this chain, so
      // it can propose new state
      propose(policy, id + 1, propFn);

      // Check if this was the coldest chain
      if (id % chains_.numChains() != 0)
      {
        // Lock the chain that is below (colder) than this.
        locked_[id - 1] = true;
      }
      else
      {
        // This is the coldest chain and there is no one to swap with
        propose(policy, id, propFn);
      }
    }

    //! Return a new proposal step size for a chain.
    //!
    //! \param id The id of the chain to be adapted.
    //! \return The new proposal step size.
    //!
    double adaptSigma(uint id)
    {
      double acceptRate = acceptRates_[id];
      double oldSigma= chains_.sigma(id);
      double factor = std::pow(acceptRate / s_.proposalOptimalAccept, s_.proposalAdaptRate);
      double boundFactor = std::min(std::max(factor, s_.proposalMinFactor), s_.proposalMaxFactor);
      double gamma = s_.adaptionLength/(double)(s_.adaptionLength+lengths_[id]);

      double newSigma = oldSigma * std::pow(boundFactor, gamma);
      VLOG(2) << "Adapting Sigma" << id <<":" << oldSigma << "->" << newSigma << " @acceptrate:" << acceptRate;
      chains_.setSigma(id, newSigma);
      sigmas_[id] = newSigma;

      // Ensure higher temperature chains have larger sigmas than chains colder than it
      if (id % chains_.numChains() != 0 && newSigma < chains_.sigma(id - 1))
      {
        newSigma = chains_.sigma(id - 1);
      }

      return newSigma;
    }

    //! Adapt a new temperature for a chain.
    //!
    //! \param id The id of the chain to be adapted.
    //!
    void adaptBeta(uint id)
    {
      // Adapt the temperature
      double swapRate = swapRates_[id];
      double rawFactor = std::pow(swapRate/s_.betaOptimalSwapRate, s_.betaAdaptRate);
      double boundedFactor = std::min( std::max(rawFactor, s_.betaMinFactor), s_.betaMaxFactor);
      double beta = chains_.beta(id);
      double lowerBeta = chains_.beta(id-1);// temperature changes propogate UP
      double factor = 1.0/std::max(boundedFactor, 2*beta/(beta + lowerBeta));

      // Set the temperature for this chain (because it hasn't proposed yet)
      double gamma = s_.adaptionLength/(double)(s_.adaptionLength+lengths_[id]);
      double newbeta = chains_.beta(id) * std::pow(factor, gamma);
      chains_.setBeta(id,newbeta);
      nextChainBeta_[id] = newbeta;
      betas_[id] = newbeta;

      // Just for logging
      VLOG(2) << "Adapting Beta" << id << ":" << beta << "->" << newbeta << " @swaprate:" << swapRate;

      // Loop through the other temperatures
      uint coldestChainId = (uint)(id / (double)chains_.numChains()) * chains_.numChains();
      uint hottestChainId = coldestChainId + chains_.numChains()-1;

      // Set the next temperatures for the other chains (as they're busy)
      for (uint i = id+1; i <= hottestChainId; i++)
      {
        nextChainBeta_[i] = nextChainBeta_[i] * std::pow(factor, gamma);
      }
    }

    void updateAccepts(uint id, bool acc)
    {
      uint oldSize = acceptBuffers_[id].size();
      double oldRate = acceptRates_[id];
      bool isFull = acceptBuffers_[id].full();
      bool lastAcc = acceptBuffers_[id].front();

      // Now push on the new state
      acceptBuffers_[id].push_back(acc);

      // Compute the new rate
      uint newSize = acceptBuffers_[id].size();
      double delta = ((int)acc - (int)(lastAcc&&isFull))/(double)newSize;
      double scale = oldSize/(double)newSize;
      acceptRates_[id] = std::max(oldRate*scale + delta, 0.0);
      nAcceptsGlobal_[id] += acc;
      if (acceptRates_[id] > 1.0)
      {
        std::cout << "oldSize: " << oldSize << "\n"
        << "isFull:" << isFull << "\n"
        << "newSize:" << newSize << "\n"
        << "lastAcc:" << lastAcc << "\n"
        << "delta:" << delta << "\n"
        << "scale:" << scale << "\n"
        << "oldRate:" << oldRate << "\n"
        << "rate:" << acceptRates_[id] << "\n"
        << std::endl;
        exit(EXIT_FAILURE);
      }
    }

    void updateSwaps(uint id, bool sw)
    {
      uint oldSize = swapBuffers_[id].size();
      double oldRate = swapRates_[id];
      bool isFull = swapBuffers_[id].full();
      bool lastSw = swapBuffers_[id].front();

      // Now push back the new state
      swapBuffers_[id].push_back(sw);

      // Compute the new rate
      uint newSize = swapBuffers_[id].size();
      double delta = ((int)sw - (int)(lastSw&&isFull))/(double)newSize;
      double scale = oldSize/(double)newSize;
      swapRates_[id] = std::max(oldRate*scale + delta, 0.0);
      nSwapsGlobal_[id] += sw;// for global rate
      nSwapAttemptsGlobal_[id] += 1;
    }

    // The MCMC chain database
    db::Database db_;

    // The MCMC chain wrapper
    ChainArray chains_;

    // lengths of the chains
    std::vector<uint> lengths_;

    // Matrix of proposed states
    Eigen::MatrixXd propStates_;

    // Whether a chain is locked. A locked chain will wait for any outstanding
    // job results and propagate the lock.
    std::vector<bool> locked_;

    // Cache the next temperature as computed by lower chains in the stack
    std::vector<double> nextChainBeta_;

    // Keep track of the swaps and accepts for adaption
    std::vector<unsigned long long> nAcceptsGlobal_;
    std::vector<unsigned long long> nSwapsGlobal_;
    std::vector<unsigned long long> nSwapAttemptsGlobal_;

    std::vector<boost::circular_buffer<bool>> acceptBuffers_;
    std::vector<boost::circular_buffer<bool>> swapBuffers_;

    // For logging purposes
    std::vector<double> sigmas_;
    std::vector<double> betas_;
    std::vector<double> acceptRates_;
    std::vector<double> swapRates_;
    std::vector<double> lowestEnergies_;

    // The MCMC settings
    MCMCSettings s_;

    // Recovering?
    bool recover_;

    // How many jobs haven't been retrieved?
    uint numOutstandingJobs_;

    // Whether an interrupt signal has been sent to the sampler.
    volatile bool& interrupted_;

    zmq::context_t context_;
  };
}
// namespace mcmc
}// namespace obsidian

max_stars_repo_name: NICTA/obsidian

max_issues_repo_name: NICTA/obsidian

max_forks_repo_name: NICTA/obsidian


text:
/*******************************************************************************
*
*Copyright: armuxinxian@aliyun.com
*
*File name: csf_logger.hpp
*
*Author: f
*
*Version: 1.0
*
*Date: 01-7月-2018 20:38:59
*
*Description: Class(csf_logger)
*
*Others:
*
*History:
*******************************************************************************/

#include "csf_logger.hpp"
#include "csf_attribute_include.h"
#include "csf_attribute_exception_critical.hpp"
#include <boost/filesystem.hpp>

using csf::core::system::csf_logger;
using csf::core::system::attribute::csf_attribute_manager;

/**
* 表示当前系统中每条日志的最大长度
*/
#ifndef CSF_LOGGER_MAX_ERROR_STRING
#define CSF_LOGGER_MAX_ERROR_STRING						102400
#endif

#ifdef WIN32

#define csf_static_thread_local			static thread_local

#else

#if defined(HAVE___ATTRIBUTE__) && defined(HAVE_TLS)
#define ATTR_INITIAL_EXEC __attribute__ ((tls_model ("initial-exec")))
//#define csf_static_thread_local			static __thread
#define csf_static_thread_local			static thread_local
#else
#define ATTR_INITIAL_EXEC
//#warning "disable TLS."
#define csf_static_thread_local
#endif

#endif

csf_logger::csf_logger()
	: m_configure_manager(csf_nullptr)
	, m_path("")
	, m_rotation_size(0)
	, m_stored_max_size(0)
	, m_disk_min_free_size(0)
	, m_file_name_format("")
	, m_attribute_manager(new csf_attribute_manager()) {

}

/**
* 表示根据配置文件创建日志模块
*
* @param configure_manager    表示配置文件
* @param path    表示日志文件保存的主目录路径
*/
csf_logger::csf_logger(const csf_configure_manager* configure_manager, const csf_string path)
	: m_configure_manager((csf_configure_manager*)configure_manager)
	, m_path(path)
	, m_rotation_size(0)
	, m_stored_max_size(0)
	, m_disk_min_free_size(0)
	, m_file_name_format("")
	, m_attribute_manager(new csf_attribute_manager(configure_manager)) {

}

csf_logger::~csf_logger() {

	if (csf_nullptr != m_attribute_manager) {
		delete ((csf_attribute_manager*)m_attribute_manager);
		m_attribute_manager = csf_nullptr;
	}
}
// #ifdef WIN32
// #pragma data_seg("csf_logger::m_level")
// #endif

/**
* 表示当前系统的日志级别，默认notice级别
*/
//csf_logger_level csf_logger::m_level = csf_logger_level::csf_logger_level_notice;
csf_logger_level csf_logger::m_level = csf_logger_level::csf_logger_level_debug;

// #ifdef WIN32
// #pragma data_seg()
// #pragma comment(linker, "/section:SHARED,RWS")
// #endif

/**
* 表示日志级别对应的名称列表内容。
*/
const csf_unordered_map<csf_string, csf_logger_level> csf_logger::m_level_name = {
	{ "debug", csf_logger_level_debug },
	{ "normal", csf_logger_level_normal },
	{ "info", csf_logger_level_info },
	{ "notice", csf_logger_level_notice },
	{ "warning", csf_logger_level_warning },
	{ "error", csf_logger_level_error },
	{ "critical", csf_logger_level_critical },
};

/**
 * 模块初始化
 *
 * @param conf_mg    表示配置文件信息
 */
csf::core::base::csf_int32 csf_logger::init(const csf_configure_manager * conf_mg) {

	csf_bool						tmp_bool_ret = csf_false;
	csf_string						tmp_string_ret = "";
	csf_string						tmp_string_level = "";
	csf_logger_level				tmp_level = csf_logger_level::csf_logger_level_notice;
	csf_char						tmp_path_buffer[2048] = { 0, };

	//校验各种配置信息的合法性
	if (!get_configure_manager() || !get_attribute_manager()) {

		csf_log_ex(critical, csf_log_code_critical
			, "configure_manager[%p] / attribute_manager[%p] is null."
			, get_configure_manager()
			, get_attribute_manager());

		return csf_failure;
	}

	/************************************************************************/
	/* 设置日志系统需要的几个配置属性信息                                     */
	/************************************************************************/
	//表示日志保存的目录位置,如果该值为空则采用默认的系统路径
	((csf_attribute_manager*)get_attribute_manager())->add(CSF_LOGGER_ATTRIBUTE_NAME(path)
		, csf_attribute_string(std::list<csf_string>{ "log_configure", "path" }));

	//表示日志文件的名称格式
	((csf_attribute_manager*)get_attribute_manager())->add(CSF_LOGGER_ATTRIBUTE_NAME(format)
		, csf_attribute_string(std::list<csf_string>{ "log_configure", "format" }
			, csf_attribute_exception_critical()));

	//日志级别：debug/normal/info/notice/warning/error/critical
	((csf_attribute_manager*)get_attribute_manager())->add(CSF_LOGGER_ATTRIBUTE_NAME(level)
		, csf_attribute_string(std::list<csf_string>{ "log_configure", "level" }
			, csf_attribute_exception_critical()));

	//表示单文件回滚最大大小，即每个文件的最大大小。注意：该数值要小于stored_max_size,最大为:1GB
	((csf_attribute_manager*)get_attribute_manager())->add(CSF_LOGGER_ATTRIBUTE_NAME(rotation_size)
			, csf_attribute_space_size(std::list<csf_string>{ "log_size", "rotation_size" }
				, csf_attribute_space_size::csf_space_size_unit::csf_space_size_unit_b
				, csf_attribute_boundary("(1000, n)")
				, csf_attribute_exception_critical()));

	//表示日志占用磁盘最大大小，stored_max_size/rotation_size表示保存的日志文件数量。注意：该值要大于rotation_size，最大为:1GB
	((csf_attribute_manager*)get_attribute_manager())->add(CSF_LOGGER_ATTRIBUTE_NAME(stored_max_size)
		, csf_attribute_space_size(std::list<csf_string>{ "log_size", "stored_max_size" }
			, csf_attribute_space_size::csf_space_size_unit::csf_space_size_unit_b
			, csf_attribute_boundary("(1000, n)")
			, csf_attribute_exception_critical()));

	//表示磁盘空间最小多大的时候才能写日志。注意：该值要大于stored_max_size，最大为:1GB
	((csf_attribute_manager*)get_attribute_manager())->add(CSF_LOGGER_ATTRIBUTE_NAME(disk_min_free_size)
		, csf_attribute_space_size(std::list<csf_string>{ "log_size", "disk_min_free_size" }
			, csf_attribute_space_size::csf_space_size_unit::csf_space_size_unit_b
			, csf_attribute_boundary("(1000, n)")
			, csf_attribute_exception_critical()));

	/************************************************************************/

	//根据配置文件的配置数据，设置日志级别
	tmp_string_level = ((csf_attribute_manager*)get_attribute_manager())->get_value<csf_attribute_string>(CSF_LOGGER_ATTRIBUTE_NAME(level));
	tmp_bool_ret = convert(tmp_level, tmp_string_level);
	if (!tmp_bool_ret) {
		csf_log_ex(critical, csf_log_code_critical
			, "logger unknow level_name[%s] error."
			, tmp_string_level.c_str());
		return csf_failure;
	}
	else {
		set_level(tmp_level);
	}

	//根据配置文件内容，设置日志文件名格式
	tmp_string_ret = ((csf_attribute_manager*)get_attribute_manager())->get_value<csf_attribute_string>(CSF_LOGGER_ATTRIBUTE_NAME(format));
	if (tmp_string_ret.empty()) {
		csf_log_ex(critical, csf_log_code_critical
			, "logger format is null error.");
		return csf_failure;
	}
	else {
		set_file_name_format(tmp_string_ret);
	}

	//根据配置文件内容，设置日志文件保存路径
	//优先使用日志配置文件中的日志保存地址。如果该路径为空，则使用已经配置程序指定目录
	//如果日志没有配置任何路径信息，则日志系统无法正常工作
	tmp_string_ret = ((csf_attribute_manager*)get_attribute_manager())->get_value<csf_attribute_string>(CSF_LOGGER_ATTRIBUTE_NAME(path));
	if (tmp_string_ret.empty()) {
		//如果没有配置日志目录，则采用程序当前的工件目录作为日志的目录
		boost::filesystem::path tmp_cp = boost::filesystem::current_path();
		csf_snprintf(tmp_path_buffer
			, csf_sizeof(tmp_path_buffer)
			, "%s%c%s%c"
			, boost::filesystem::current_path().string().c_str()
			, boost::filesystem::path::preferred_separator
			, CSF_LOGGER_DIRECTORY_NAME
			, boost::filesystem::path::preferred_separator
		);

		set_path(tmp_path_buffer);
	}
	else {
		csf_snprintf(tmp_path_buffer
			, csf_sizeof(tmp_path_buffer)
			, "%s%c%s%c"
			, tmp_string_ret.c_str()
			, boost::filesystem::path::preferred_separator
			, CSF_LOGGER_DIRECTORY_NAME
			, boost::filesystem::path::preferred_separator
		);

		set_path(tmp_path_buffer);
	}

	//设置各种空间参数信息
	set_rotation_size(((csf_attribute_manager*)get_attribute_manager())->get_value<csf_attribute_space_size>(CSF_LOGGER_ATTRIBUTE_NAME(rotation_size)));
	set_stored_max_size(((csf_attribute_manager*)get_attribute_manager())->get_value<csf_attribute_space_size>(CSF_LOGGER_ATTRIBUTE_NAME(stored_max_size)));
	set_disk_min_free_size(((csf_attribute_manager*)get_attribute_manager())->get_value<csf_attribute_space_size>(CSF_LOGGER_ATTRIBUTE_NAME(disk_min_free_size)));

	csf_log_ex(notice, csf_log_code_notice
		, "init logger[rotation_size: %s  stored_max_size: %s  disk_min_free_size: %s ]."
		, ((csf_attribute_manager*)get_attribute_manager())->get_content(CSF_LOGGER_ATTRIBUTE_NAME(rotation_size)).c_str()
		, ((csf_attribute_manager*)get_attribute_manager())->get_content(CSF_LOGGER_ATTRIBUTE_NAME(stored_max_size)).c_str()
		, ((csf_attribute_manager*)get_attribute_manager())->get_content(CSF_LOGGER_ATTRIBUTE_NAME(disk_min_free_size)).c_str());

	csf_log_ex(notice, csf_log_code_notice
		, "init logger[level: \"%s\"  format: \"%s\"  path: \"%s\"]."
		, tmp_string_level.c_str()
		, get_file_name_format().c_str()
		, get_path().c_str());

	return csf_succeed;
}

/**
 * 模块启动
 *
 * @param conf_mg    表示配置文件信息
 */
csf::core::base::csf_int32 csf_logger::start(const csf_configure_manager * conf_mg) {

	std::string				tmp_log_file_name = "";

	tmp_log_file_name = get_path() + get_file_name_format();
	try	{
		//text_ostream_backend
		boost::shared_ptr<text_sink> tmp_text_sink_ptr(new text_sink);
		{
			text_sink::locked_backend_ptr tmp_backend = tmp_text_sink_ptr->locked_backend();

			boost::shared_ptr< std::ostream > tmp_stream(&std::clog, csf_null_deleter());

			tmp_backend->add_stream(tmp_stream);
			tmp_backend->auto_flush();
		}
		boost::log::core::get()->add_sink(tmp_text_sink_ptr);

		boost::log::formatter tmp_fmtter =
			boost::log::expressions::stream
			<< boost::log::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "[%Y-%m-%d %H:%M:%S.%f] [")
			<< boost::log::expressions::attr<boost::log::attributes::current_thread_id::value_type >("ThreadID")
			<< "] ["
			<< log_severity
			<< ":"
			<< boost::log::expressions::if_(boost::log::expressions::has_attr("Code"))
			[
				boost::log::expressions::stream << boost::log::expressions::attr< int >("Code")
			]
			//<< "] -- " << boost::log::expressions::format_named_scope(log_scope, boost::log::keywords::format = "[%F:%l (%c)] ")
			<< "] -- "
			<< boost::log::expressions::smessage;

		// Create a text file sink
		boost::shared_ptr<file_sink> tmp_file_sink_ptr(new file_sink(
			boost::log::keywords::file_name = tmp_log_file_name,				// file name pattern
			boost::log::keywords::rotation_size = get_rotation_size(),			// rotation size, in characters
			boost::log::keywords::time_based_rotation = boost::log::sinks::file::rotation_at_time_point(0, 0, 0)
		));

		// Set up where the rotated files will be stored
		tmp_file_sink_ptr->locked_backend()->set_file_collector(boost::log::sinks::file::make_collector(
			boost::log::keywords::target = get_path(),							// where to store rotated files
			boost::log::keywords::max_size = get_stored_max_size(),             // maximum total size of the stored files, in bytes
			boost::log::keywords::min_free_space = get_disk_min_free_size()     // minimum free space on the drive, in bytes
		));
		// Upon restart, scan the target directory for files matching the file_name pattern
		tmp_file_sink_ptr->locked_backend()->scan_for_files();
		tmp_file_sink_ptr->locked_backend()->auto_flush();
		boost::log::core::get()->add_sink(tmp_file_sink_ptr);

		//boost::log::add_common_attributes();

		// Add some attributes too
		boost::log::core::get()->add_global_attribute("TimeStamp", boost::log::attributes::local_clock());
		//boost::log::core::get()->add_global_attribute("Severity", boost::log::attributes::constant<pc_severity_level>());
		//boost::log::core::get()->add_global_attribute("Code", boost::log::attributes::constant<int>());
		boost::log::core::get()->add_global_attribute("ThreadID", boost::log::attributes::current_thread_id());
		boost::log::core::get()->add_thread_attribute("Scope", boost::log::attributes::named_scope());

		tmp_text_sink_ptr->set_formatter(tmp_fmtter);
		tmp_file_sink_ptr->set_formatter(tmp_fmtter);

		//set filter
// 		tmp_text_sink_ptr->set_filter(log_severity >= csf_logger::get_level()); // ...or specifically tagged
// 		tmp_file_sink_ptr->set_filter(log_severity >= csf_logger::get_level()); // ...or specifically tagged
		tmp_text_sink_ptr->set_filter(log_severity >= boost::ref(m_level)); // ...or specifically tagged
		tmp_file_sink_ptr->set_filter(log_severity >= boost::ref(m_level)); // ...or specifically tagged

		set_text_sink_ptr(tmp_text_sink_ptr);
		set_file_sink_ptr(tmp_file_sink_ptr);

		return csf_succeed;
	}
	catch (std::exception& e) {
		std::cout << "csf_logger start failure! reason:" << e.what() << std::endl;
		return csf_failure;
	}

	return csf_succeed;
}

/**
 * 模块停止
 *
 * @param conf_mg    表示配置文件信息
 */
csf::core::base::csf_int32 csf_logger::stop(const csf_configure_manager * conf_mg) {

	return 0;
}

/**
* 表示配置文件地址
*
* @param new_value
*/
csf_void csf_logger::set_configure_manager(const csf_configure_manager* new_value) {

	m_configure_manager = (csf_configure_manager*)new_value;

	if (get_attribute_manager()) {
		((csf_attribute_manager*)get_attribute_manager())->set_configure_manager(new_value, std::list<csf_string>());
	}
}

/**
* 表示定义一个printf写日志函数,同时添加判断日志级别
* @author f
* @version 1.0
* @created 01-7月-2018 20:38:59
* @param _level_	表示日志级别,取值为csf_logger_level类型
* @param _code_	表示日志错误码
* @param _fmt_	表示日志格式化字符串，类型printf("_fmt_", args)中的_fmt_字符串
* @param ...	表示日志格式化参数列表，类型printf("_fmt_", args)中的args列表
*/
void csf_logger::write(int _level_, int _code_, const char *_fmt_, ...) {

	if (_level_ >= get_level()) {

		csf_static_thread_local char		_tmp_buf_[CSF_LOGGER_MAX_ERROR_STRING] = { 0, };
		csf_static_thread_local size_t		_tmp_size_ = 0;
		csf_static_thread_local char*		_tmp_buf_point_ = NULL;
		csf_static_thread_local bool		_tmp_is_free = false;
		va_list								_tmp_marker_;

		va_start(_tmp_marker_, _fmt_);

		//这里对日志的频繁分配内存做优化。
		//1、如果已经分配的内存够用，则用已经分配的。（实现需求的内存长度小与固定已有的内存长度，则采用固定内存;）
		//2、如果已经分配的内存不够用，则重新分配，并释放
		_tmp_size_ = csf_vscprintf(_fmt_, _tmp_marker_);
		if (_tmp_size_ < sizeof(_tmp_buf_)) {
			_tmp_buf_point_ = _tmp_buf_;
			//将末尾的一个字节清0，表示字符结束
			_tmp_buf_point_[_tmp_size_ - 1] = '\0';
			_tmp_size_ = sizeof(_tmp_buf_);
			_tmp_is_free = false;
		}
		else {
			_tmp_buf_point_ = (char*)malloc(_tmp_size_);
			//将末尾的一个字节清0，表示字符结束
			_tmp_buf_point_[_tmp_size_ - 1] = '\0';
			_tmp_is_free = true;
		}

		if (csf_vsnprintf(_tmp_buf_point_, _tmp_size_, _fmt_, _tmp_marker_) < 0) {
			_tmp_buf_[CSF_LOGGER_MAX_ERROR_STRING - 2] = '.';
			_tmp_buf_[CSF_LOGGER_MAX_ERROR_STRING - 3] = '.';
			_tmp_buf_[CSF_LOGGER_MAX_ERROR_STRING - 4] = '.';
		}
		va_end(_tmp_marker_);
		//printf("%s\r\n", _tmp_buf_);
		BOOST_LOG_WRITE((csf_logger_level)_level_, (csf_log_code)_code_, _tmp_buf_point_);

		if (_tmp_is_free) {
			free(_tmp_buf_point_);
			_tmp_buf_point_ = NULL;
		}

	}

}

ext: cpp


text:
//  Copyright (c) 2019 Robert Ramey
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// compile only test to test constexpr casting

#include <boost/safe_numerics/safe_integer.hpp>
#include <boost/safe_numerics/native.hpp>
#include <boost/safe_numerics/exception_policies.hpp>

template <class T>
using safe_t = boost::safe_numerics::safe<
    T,
    boost::safe_numerics::native,
    boost::safe_numerics::trap_exception
>;

constexpr const char * test_casting_results[] = {
//      0       0       0       0
//      012345670123456701234567012345670
//      012345678901234567890123456789012
/* 0*/ ".....xxx.xxx.xxx.xxx.xxx.xxx.xxx.",
/* 1*/ ".........xxx.xxx...x.xxx.xxx.xxx.",
/* 2*/ ".............xxx...x...x.xxx.xxx.",
/* 3*/ "...................x...x...x.xxx.",
/* 4*/ "..xx.xxx.xxx.xxx..xx.xxx.xxx.xxx.",
/* 5*/ "..xx..xx.xxx.xxx......xx.xxx.xxx.",
/* 6*/ "..xx..xx..xx.xxx..........xx.xxx.",
/* 7*/ "..xx..xx..xx..xx..............xx.",
};

#include <boost/safe_numerics/safe_integer_literal.hpp>
using namespace boost::safe_numerics;

#include <boost/mp11/algorithm.hpp>

using namespace boost::mp11;

template<class T>
struct p {
    constexpr static bool value = '.' == test_casting_results[mp_first<T>::value][mp_second<T>::value];
};

template<class T2, class T1>
constexpr bool test_cast_constexpr(const T1 & v1){
    // if we don't expect the operation to pass, we can't
    // check the constexpr version of the calculation so
    // just return success.
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wunused-value"
    static_cast<safe_t<T2>>(v1);
    static_cast<T2>(v1);
    #pragma GCC diagnostic pop
    return true;
}

#include "test_values.hpp"

template<typename L2>
struct test {
    static_assert(mp_is_list<L2>(), "must be a list of two indices");
    const static std::size_t i = mp_first<L2>();
    const static std::size_t j = mp_second<L2>();
    using T = mp_at_c<test_types, i>; // first element is a type
    using T1 = typename mp_at_c<test_values, j>::value_type;
    const static T1 v = mp_at_c<test_values, j>::value;
    const static bool value =
        test_cast_constexpr<T>(make_safe_literal(v, native, trap_exception));
};

int main(){
    using namespace boost::safe_numerics;

    using type_indices = mp_iota_c<mp_size<test_types>::value>;
    using value_indices = mp_iota_c<mp_size<test_values>::value>;

    // generate all combinations of types <- value
    using l = mp_product<mp_list,type_indices,value_indices>;
    //boost::safe_numerics::utility::print_types<l> lp;

    // filter out the invalid ones
    using l1 = mp_copy_if<l, p>;
    //boost::safe_numerics::utility::print_types<l1> l1p;

    // verify that all valid ones compile without error
    static_assert(mp_all_of<l1, test>(), "testing all valid casts");
    return 0;
}


text:
#include <pybind11_ext/boost/circular_buffer.hpp>

#include <gtest/gtest.h>
#include <gmock/gmock.h>

#include <boost/optional.hpp>

#include <string>
#include <vector>

using namespace std;
using namespace testing;
namespace py = pybind11;

TEST(circular_buffer, create__char__single)
{
    py::detail::numpy_circular_buffer<char> buffer(1);
    ASSERT_EQ(buffer.capacity(), size_t(getpagesize()));
}

TEST(circular_buffer, create__int__single)
{
    py::detail::numpy_circular_buffer<int> buffer(1);
    ASSERT_EQ(buffer.capacity(), size_t(getpagesize() / sizeof(int)));
}

TEST(circular_buffer, create__custom__not_aligned__single)
{
    struct test_type
    {
        int field_1;
        double field_2;
        char field_3;
    };

    ASSERT_ANY_THROW(py::detail::numpy_circular_buffer<test_type>(1));
}

TEST(circular_buffer, create__custom__aligned__single)
{
    struct alignas(16) test_type
    {
        int field_1;
        double field_2;
        char field_3;
    };

    py::detail::numpy_circular_buffer<test_type> buffer(1);
    ASSERT_EQ(buffer.capacity(), size_t(getpagesize() / sizeof(test_type)));
}


text:
/*
 * Copyright 2013 Matthew Harvey
 *
 * 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 "account_type.hpp"
#include "transaction_type.hpp"
#include <boost/test/unit_test.hpp>
#include <vector>

using std::vector;

#include <iostream>
using std::cout;
using std::endl;

namespace dcm
{
namespace test
{

typedef vector<AccountType> Vec;
typedef Vec::size_type Size;

BOOST_AUTO_TEST_CASE(TestSourceAccountTypesExpenditureTransaction)
{
    Vec const& account_types_ref =
        source_account_types(TransactionType::expenditure);
    Vec const account_types_cpy =
        source_account_types(TransactionType::expenditure);
    BOOST_CHECK_EQUAL(account_types_ref.size(), account_types_cpy.size());
    BOOST_CHECK_EQUAL(account_types_ref.size(), static_cast<size_t>(2));
    for (Size i = 0; i != account_types_ref.size(); ++i)
    {
        BOOST_CHECK(account_types_cpy[i] == account_types_ref[i]);
        BOOST_CHECK
        (   (account_types_ref[i] == AccountType::asset) ||
            (account_types_ref[i] == AccountType::liability)
        );
    }
}

BOOST_AUTO_TEST_CASE(TestDestinationAccountTypesExpenditureTransaction)
{
    Vec const& account_types_ref =
        destination_account_types(TransactionType::expenditure);
    Vec const account_types_cpy =
        destination_account_types(TransactionType::expenditure);
    BOOST_CHECK_EQUAL(account_types_ref.size(), account_types_cpy.size());
    BOOST_CHECK_EQUAL(account_types_ref.size(), static_cast<size_t>(1));
    for (Size i = 0; i != account_types_ref.size(); ++i)
    {
        BOOST_CHECK(account_types_cpy[i] == account_types_ref[i]);
        BOOST_CHECK(account_types_ref[i] == AccountType::expense);
    }
}

BOOST_AUTO_TEST_CASE(TestSourceAccountTypesRevenueTransaction)
{
    Vec const& account_types_ref =
        source_account_types(TransactionType::revenue);
    Vec const account_types_cpy =
        source_account_types(TransactionType::revenue);
    BOOST_CHECK_EQUAL(account_types_ref.size(), account_types_cpy.size());
    BOOST_CHECK_EQUAL(account_types_ref.size(), static_cast<size_t>(1));
    for (Size i = 0; i != account_types_ref.size(); ++i)
    {
        BOOST_CHECK(account_types_cpy[i] == account_types_ref[i]);
        BOOST_CHECK(account_types_ref[i] == AccountType::revenue);
    }
}

BOOST_AUTO_TEST_CASE(TestDestinationAccountTypesRevenueTransaction)
{
    Vec const& account_types_ref =
        destination_account_types(TransactionType::revenue);
    Vec const account_types_cpy =
        destination_account_types(TransactionType::revenue);
    BOOST_CHECK_EQUAL(account_types_ref.size(), account_types_cpy.size());
    BOOST_CHECK_EQUAL(account_types_ref.size(), static_cast<size_t>(2));
    for (Size i = 0; i != account_types_ref.size(); ++i)
    {
        BOOST_CHECK(account_types_cpy[i] == account_types_ref[i]);
        BOOST_CHECK
        (   (account_types_ref[i] == AccountType::asset) ||
            (account_types_ref[i] == AccountType::liability)
        );
    }
}

BOOST_AUTO_TEST_CASE(TestSourceAccountTypesBalanceSheetTransaction)
{
    Vec const& account_types_ref = source_account_types
    (   TransactionType::balance_sheet
    );
    Vec const account_types_cpy = source_account_types
    (   TransactionType::balance_sheet
    );
    BOOST_CHECK_EQUAL(account_types_ref.size(), account_types_cpy.size());
    BOOST_CHECK_EQUAL(account_types_ref.size(), static_cast<size_t>(2));
    for (Size i = 0; i != account_types_ref.size(); ++i)
    {
        BOOST_CHECK(account_types_cpy[i] == account_types_ref[i]);
        BOOST_CHECK
        (   (account_types_ref[i] == AccountType::asset) ||
            (account_types_ref[i] == AccountType::liability)
        );
    }
}

BOOST_AUTO_TEST_CASE(TestDestinationAccountTypesBalanceSheetTransaction)
{
    Vec const& account_types_ref = destination_account_types
    (   TransactionType::balance_sheet
    );
    Vec const account_types_cpy = destination_account_types
    (   TransactionType::balance_sheet
    );
    BOOST_CHECK_EQUAL(account_types_ref.size(), account_types_cpy.size());
    BOOST_CHECK_EQUAL(account_types_ref.size(), static_cast<size_t>(2));
    for (Size i = 0; i != account_types_ref.size(); ++i)
    {
        BOOST_CHECK(account_types_cpy[i] == account_types_ref[i]);
        BOOST_CHECK
        (   (account_types_ref[i] == AccountType::asset) ||
            (account_types_ref[i] == AccountType::liability)
        );
    }
}

BOOST_AUTO_TEST_CASE(TestSourceAccountTypesEnvelopeTransaction)
{
    Vec const& account_types_ref =
        source_account_types(TransactionType::envelope);
    Vec const account_types_cpy =
        source_account_types(TransactionType::envelope);
    BOOST_CHECK_EQUAL(account_types_ref.size(), account_types_cpy.size());
    BOOST_CHECK_EQUAL(account_types_ref.size(), static_cast<size_t>(3));
    for (Size i = 0; i != account_types_ref.size(); ++i)
    {
        BOOST_CHECK(account_types_cpy[i] == account_types_ref[i]);
        BOOST_CHECK
        (   (account_types_ref[i] == AccountType::revenue) ||
            (account_types_ref[i] == AccountType::expense) ||
            (account_types_ref[i] == AccountType::pure_envelope)
        );
    }
}

BOOST_AUTO_TEST_CASE(TestDestinationAccountTypesEnvelopeTransaction)
{
    Vec const& account_types_ref =
        destination_account_types(TransactionType::envelope);
    Vec const account_types_cpy =
        destination_account_types(TransactionType::envelope);
    BOOST_CHECK_EQUAL(account_types_ref.size(), account_types_cpy.size());
    BOOST_CHECK_EQUAL(account_types_ref.size(), static_cast<size_t>(3));
    for (Size i = 0; i != account_types_ref.size(); ++i)
    {
        BOOST_CHECK(account_types_cpy[i] == account_types_ref[i]);
        BOOST_CHECK
        (   (account_types_ref[i] == AccountType::revenue) ||
            (account_types_ref[i] == AccountType::expense) ||
            (account_types_ref[i] == AccountType::pure_envelope)
        );
    }
}

BOOST_AUTO_TEST_CASE(TestSourceAccountTypesGenericTransaction)
{
    Vec const& account_types_ref =
        source_account_types(TransactionType::generic);
    Vec const account_types_cpy =
        source_account_types(TransactionType::generic);
    BOOST_CHECK_EQUAL(account_types_ref.size(), account_types_cpy.size());
    BOOST_CHECK_EQUAL(account_types_ref.size(), static_cast<size_t>(6));
    for (Size i = 0; i != account_types_ref.size(); ++i)
    {
        BOOST_CHECK(account_types_cpy[i] == account_types_ref[i]);
        BOOST_CHECK
        (   (account_types_ref[i] == AccountType::revenue) ||
            (account_types_ref[i] == AccountType::expense) ||
            (account_types_ref[i] == AccountType::pure_envelope) ||
            (account_types_ref[i] == AccountType::asset) ||
            (account_types_ref[i] == AccountType::liability) ||
            (account_types_ref[i] == AccountType::equity)
        );
    }
}

BOOST_AUTO_TEST_CASE(TestDestinationAccountTypesGenericTransaction)
{
    Vec const& account_types_ref =
        destination_account_types(TransactionType::generic);
    Vec const account_types_cpy =
        destination_account_types(TransactionType::generic);
    BOOST_CHECK_EQUAL(account_types_ref.size(), account_types_cpy.size());
    BOOST_CHECK_EQUAL(account_types_ref.size(), static_cast<size_t>(6));
    for (Size i = 0; i != account_types_ref.size(); ++i)
    {
        BOOST_CHECK(account_types_cpy[i] == account_types_ref[i]);
        BOOST_CHECK
        (   (account_types_ref[i] == AccountType::revenue) ||
            (account_types_ref[i] == AccountType::expense) ||
            (account_types_ref[i] == AccountType::pure_envelope) ||
            (account_types_ref[i] == AccountType::asset) ||
            (account_types_ref[i] == AccountType::liability) ||
            (account_types_ref[i] == AccountType::equity)
        );
    }
}

}  // namespace test
}  // namespace dcm

max_stars_repo_name: skybaboon/dailycashmanager

max_issues_repo_name: skybaboon/dailycashmanager

max_forks_repo_name: skybaboon/dailycashmanager


text:
/*
 * File:   ToolsTestFileIO.cpp
 * Author: kjell
 *
 * Created on August 15, 2013, 3:41 PM
 */

#include <random>
#include <cstdio>
#include <functional>
#include <algorithm>
#include <boost/filesystem.hpp>
#include <future>
#include <thread>
#include <random>
#include <sstream>
#include <unistd.h>
#include "ToolsTestFileIO.h"
#include "FileIO.h"
#include "StopWatch.h"

namespace {
   // Random integer function from http://www2.research.att.com/~bs/C++0xFAQ.html#std-random

   int random_int(int low, int high) {
      using namespace std;
      static std::random_device rd; // Seed with a real random value, if available
      static default_random_engine engine{rd()};
      typedef uniform_int_distribution<int> Distribution;
      static Distribution distribution{};
      return distribution(engine, Distribution::param_type{low, high});
   }
   struct ScopedFileCleanup {
      const std::string file;

      explicit ScopedFileCleanup(const std::string& name) : file(name) { }

      ~ScopedFileCleanup() {
         remove(file.c_str());
      }
   };

   std::string GetCurrentDirectory() {
      char* rawdir = get_current_dir_name();
      std::string dir{rawdir};
      free(rawdir);
      return dir;
   }
} // anonymous

void  FileMover(const std::string& from, const std::string& to, const int permissions, const size_t kbytes) {
      ScopedFileCleanup scopedFrom(from);
      ScopedFileCleanup scopedTo(to);

      EXPECT_TRUE(FileIO::DoesFileExist(from));
      struct stat fromStat;
      stat(from.c_str(), &fromStat);
      EXPECT_EQ(fromStat.st_size, (1024 * kbytes));
      EXPECT_EQ(fromStat.st_mode & permissions, permissions);

      // Move file
      std::this_thread::sleep_for(std::chrono::milliseconds(random_int(0, 100)));
      auto moved = FileIO::MoveFile(from, to);
      EXPECT_TRUE(moved);
      EXPECT_FALSE(FileIO::DoesFileExist(from));
      EXPECT_TRUE(FileIO::DoesFileExist(to));

      // verify size and permissions
      struct stat toStat;
      stat(to.c_str(), &toStat);
      EXPECT_EQ(toStat.st_size, (1024 * kbytes));
      EXPECT_EQ(toStat.st_mode & permissions, permissions) << "file: " << from << " : " << to;
   }

// NO OTHER TEST FUNCTION SHOULD PRECEDE THIS FUNCTION!
TEST_F(TestFileIO, Interrupt_null) {
   EXPECT_FALSE(FileIO::Interrupted());
   volatile int* nullflag = nullptr;
   FileIO::SetInterruptFlag(nullflag);
   EXPECT_FALSE(FileIO::Interrupted());
}
TEST_F(TestFileIO, Interrupt_happens) {
   EXPECT_FALSE(FileIO::Interrupted());
   volatile int flag = 0;
   FileIO::SetInterruptFlag(&flag);
   EXPECT_FALSE(FileIO::Interrupted());
   flag = 1;
   EXPECT_TRUE(FileIO::Interrupted());

   FileIO::SetInterruptFlag(/*nullptr*/);
   EXPECT_FALSE(FileIO::Interrupted());
}

TEST_F(TestFileIO, TestOfTestUtility) {
   std::string file1 = CreateFile(mTestDirectory, "ToBeRemoved.txt");
   EXPECT_TRUE(FileIO::DoesFileExist(file1));
   {
      ScopedFileCleanup cleaner(file1);
   }
   EXPECT_FALSE(FileIO::DoesFileExist(file1));
}

TEST_F(TestFileIO, WriteThenReadBinaryFileContent__Convert_uint8_to_char_should_work_fine){
      using namespace std;

   string filename{"/tmp/TestFileIO_"};
   filename.append(to_string(random_int(0, 1000000)))
     .append({"_"}).append(to_string(random_int(0, 1000000)));

   // cleanup/removing the created file when exiting
   ScopedFileCleanup cleanup{filename};

   const std::vector<uint8_t> deadbeef{0xde, 0xad, 0xbe, 0xef};
   auto resultWrite = FileIO::WriteAppendBinaryFileContent(filename, deadbeef);
   EXPECT_FALSE(resultWrite.HasFailed());

   auto resultRead = FileIO::ReadBinaryFileContent(filename);
   EXPECT_FALSE(resultRead.HasFailed());

   // size and content compared: http://en.cppreference.com/w/cpp/container/vector/operator_cmp
   bool equalCharVectors =  (deadbeef == resultRead.result);
   EXPECT_TRUE(equalCharVectors) << "deadbeef.size(): " << deadbeef.size() << ", resultRead.size(): " << resultRead.result.size();
}

TEST_F(TestFileIO, CannotOpenBinaryFileToRead) {
   auto fileRead = FileIO::ReadBinaryFileContent({"/xyz/*&%/x.y.z"});
   EXPECT_TRUE(fileRead.result.empty());
   EXPECT_FALSE(fileRead.error.empty());
   EXPECT_TRUE(fileRead.HasFailed());
}

TEST_F(TestFileIO, CannotOpenFileToRead) {
   auto fileRead = FileIO::ReadAsciiFileContent({"/xyz/*&%/x.y.z"});
   EXPECT_TRUE(fileRead.result.empty());
   EXPECT_FALSE(fileRead.error.empty());
   EXPECT_TRUE(fileRead.HasFailed());
}

TEST_F(TestFileIO, CanOpenFileToRead) {
   auto fileRead = FileIO::ReadAsciiFileContent({"/proc/stat"}); // fine as long as we are on *nix systems
   EXPECT_FALSE(fileRead.result.empty());
   EXPECT_TRUE(fileRead.error.empty());
   EXPECT_FALSE(fileRead.HasFailed());
}

TEST_F(TestFileIO, CannotWriteToFile) {
   auto fileWrite = FileIO::WriteAsciiFileContent({"xyz/123/proc/stat"},
   {
      "Hello World"
   });
   EXPECT_FALSE(fileWrite.result);
   EXPECT_FALSE(fileWrite.error.empty());
   EXPECT_TRUE(fileWrite.HasFailed());
}

TEST_F(TestFileIO, CanWriteToFileAndReadTheFile) {
   using namespace std;

   string filename{"/tmp/TestFileIO_"};
   filename.append(to_string(random_int(0, 1000000)))
           .append({"_"})
   .append(to_string(random_int(0, 1000000)));

   // cleanup/removing the created file when exiting
   ScopedFileCleanup cleanup{filename};

   auto fileWrite = FileIO::WriteAsciiFileContent(filename,{"Hello World"});
   EXPECT_TRUE(fileWrite.result);
   EXPECT_TRUE(fileWrite.error.empty());
   EXPECT_FALSE(fileWrite.HasFailed());

   auto fileRead = FileIO::ReadAsciiFileContent(filename);
   EXPECT_EQ("Hello World", fileRead.result);
   EXPECT_TRUE(fileRead.error.empty());
   EXPECT_FALSE(fileRead.HasFailed());
}

TEST_F(TestFileIO, FileIsNotADirectory) {
   std::string filename{"/tmp/123_456_789"};
   {
      ScopedFileCleanup cleanup{filename};
      EXPECT_FALSE(FileIO::DoesFileExist(filename));
      EXPECT_FALSE(FileIO::DoesDirectoryExist(filename));

      auto fileWrite = FileIO::WriteAsciiFileContent(filename,{"Hello World"});
      EXPECT_TRUE(fileWrite.result);
      EXPECT_TRUE(fileWrite.error.empty());
      EXPECT_FALSE(fileWrite.HasFailed());

      EXPECT_TRUE(FileIO::DoesFileExist(filename));
      EXPECT_FALSE(FileIO::DoesDirectoryExist(filename));
   }
   // RAII cleanup
   EXPECT_FALSE(FileIO::DoesFileExist(filename));

}

TEST_F(TestFileIO, DirectoryExistance) {
   std::string directory{"/tmp/some_temp_directory"};
   {
      EXPECT_FALSE(FileIO::DoesDirectoryExist(directory)) << directory;
      std::string createDir{"mkdir -p " + directory};
      EXPECT_EQ(0, system(createDir.c_str()));

      ScopedFileCleanup cleanup{directory};
      EXPECT_TRUE(FileIO::DoesFileExist(directory));
      EXPECT_TRUE(FileIO::DoesDirectoryExist(directory));
   }
   // RAII cleanup
   EXPECT_FALSE(FileIO::DoesFileExist(directory));
   EXPECT_FALSE(FileIO::DoesDirectoryExist(directory));
}

TEST_F(TestFileIO,  RemoveEmptyDirectories_FakeDirectoriesAreIgnored) {
   EXPECT_TRUE(FileIO::RemoveEmptyDirectories({}).result); // invalids are ignored
   EXPECT_TRUE(FileIO::RemoveEmptyDirectories({{""}}).result); // invalids are ignored

   std::vector<std::string> doNotExist({{}, {" "}, {"/does/not/exist"}});
   EXPECT_TRUE(FileIO::RemoveEmptyDirectories(doNotExist).result); // invalids are ignored

   CreateSubDirectory("some_directory");
   std::string real = {mTestDirectory+"/"+"some_directory"};
   EXPECT_TRUE(FileIO::DoesDirectoryExist(real));
   EXPECT_TRUE(FileIO::RemoveEmptyDirectories({{"does_not_exist"},real}).result); // the one invalid is ignored

}

TEST_F(TestFileIO, RemoveDirectories__ExpectNonEmptyToStay) {
   CreateSubDirectory("some_directory");
   CreateFile({mTestDirectory + "/some_directory/"}, "some_file");
   EXPECT_TRUE(FileIO::DoesFileExist({mTestDirectory + "/some_directory/some_file"}));
   EXPECT_FALSE(FileIO::RemoveEmptyDirectories({{mTestDirectory + "/some_directory"}}).result);
   EXPECT_TRUE(FileIO::DoesFileExist({mTestDirectory + "/some_directory/some_file"}));
}

TEST_F(TestFileIO, MoveFiles__BogusFileCannotBeMoved) {
   auto dir1 = CreateSubDirectory("some_directory1");
   auto dir2 = CreateSubDirectory("some_directory2");

   auto moved = FileIO::MoveFile({dir1 + "/bogus"}, {dir2 + "/bogus"});
   std::string error {std::strerror(errno)};

   EXPECT_FALSE(moved);
   EXPECT_FALSE(FileIO::DoesFileExist({dir1 + "/bogus"}));
   EXPECT_FALSE(FileIO::DoesFileExist({dir2 + "/bogus"}));
   EXPECT_TRUE(std::string::npos != error.find("No such file or directory")) << error;
}

TEST_F(TestFileIO, MoveFiles__FileCanBeMovedAcrossDirectories) {
   auto dir1 = CreateSubDirectory("some_directory1");
   auto dir2 = CreateSubDirectory("some_directory2");

   std::string file1_5MBPath = {dir1 + "/file1_5MB"};
   std::string createFile5MB = "dd bs=1024 count=5120 if=/dev/zero of=";
   std::string createFile1 = {createFile5MB + file1_5MBPath};
   EXPECT_EQ(0, system(createFile1.c_str()));
   const int file1Permissions = 644;
   EXPECT_TRUE(0 == chmod(file1_5MBPath.c_str(), file1Permissions));

   // Verify creation
   EXPECT_TRUE(FileIO::DoesFileExist(file1_5MBPath));
   struct stat file1Stat;
   stat(file1_5MBPath.c_str(), &file1Stat);
   EXPECT_EQ(file1Stat.st_size, (1024*5120));
   EXPECT_EQ(file1Stat.st_mode & file1Permissions, file1Permissions);
   EXPECT_NE(file1Stat.st_mode & 555, 555); // sanity check

   // Move
   std::string movedFile1_5MBFile = {dir2 + "/moved5MBFile"};
   auto moved = FileIO::MoveFile(file1_5MBPath, movedFile1_5MBFile);
   EXPECT_TRUE(moved);
   EXPECT_FALSE(FileIO::DoesFileExist(file1_5MBPath));
   EXPECT_TRUE(FileIO::DoesFileExist(movedFile1_5MBFile));

   // verify size and permissions
   struct stat fileMovedStat;
   stat(movedFile1_5MBFile.c_str(), &fileMovedStat);
   EXPECT_EQ(fileMovedStat.st_size, (1024*5120));
   EXPECT_EQ(fileMovedStat.st_mode & file1Permissions, file1Permissions);
   EXPECT_NE(fileMovedStat.st_mode & 555, 555); // sanity check
}

TEST_F(TestFileIO, SYSTEM__MoveFiles__ThreadSafeMoveOfFiles) {
   std::string oldStorage = "/tmp";
   std::string newStorage = GetCurrentDirectory();
   if (false == FileIO::DoesDirectoryExist(oldStorage)) {
      SUCCEED() << "Skipping test. Cannot run test. Directory does not exist: " << oldStorage;
      return;
   }

   if (false == FileIO::DoesDirectoryExist(newStorage)) {
      SUCCEED() << "Skipping test. Cannot run test. Directory does not exist: " << newStorage;
      return;
   }

   // Verify that they are on different devices
   struct stat stat_path1;
   struct stat stat_path2;
   stat(oldStorage.c_str(), &stat_path1);
   stat(newStorage.c_str(), &stat_path2);
   if (stat_path1.st_dev == stat_path2.st_dev) {
      std::string warning = "SKIPPING TEST. CANNOT RUN TEST FOR VERIFYING MOVE OF FILES ACROSS DEVICES";
      std::cerr << "WARNING: " << warning << std::endl;
      SUCCEED() << warning;
      return;
   }

   // Create all the files. Put a given size to them and vary the permissions
   const size_t movesToMake = 250;
   for (size_t i = 0; i < movesToMake; ++i) {
      const size_t kbytes = i*10;
      std::string from{oldStorage + "/from_" + std::to_string(i)};
      std::string createFile = {"dd bs=1024 count=" + std::to_string(kbytes) + " if=/dev/zero of=" + from + " >& /dev/null"}; // skip printf from dd
      EXPECT_EQ(0, system(createFile.c_str()));
      int permissions = 777;
      if (0 == i%2) {
         permissions = 640;
      } else if (0 == i%3) {
         permissions = 555;
      }

      // Verify creation
      EXPECT_TRUE(FileIO::DoesFileExist(from));
      EXPECT_TRUE(0 == chmod(from.c_str(), permissions));

      struct stat filestat;
      stat(from.c_str(), &filestat);
      EXPECT_EQ(filestat.st_size, (1024 * kbytes));
      EXPECT_EQ(filestat.st_mode & permissions, permissions);
   }

   std::vector<std::future<void>> result;
   for (size_t i = 0; i < movesToMake; ++i) {
      std::string from{oldStorage + "/from_" + std::to_string(i)};
      std::string to{newStorage + "/to_" + std::to_string(i)};
      int permissions = 777;
      if (0 == i%2) {
         permissions = 640;
       } else if (0 == i%3) {
         permissions = 555;
      }

      const size_t kbytes = i*10;
      result.push_back(std::async(std::launch::async, FileMover, from, to, permissions, kbytes));
   }

   for (auto& res : result) {
      res.wait();
   }
}

//
// Moving a large file is SLOW,. however this is faster than for example the system
// 'mv' command.  On my box the actual FileIO::MoveFile takes about 2.6 seconds
// while the system mv command takes 3.40 seconds
//
// Example
// sudo dd bs=1024 count=3145728 if=/dev/sdb of=/tmp/hej.txt
// time sudo mv /tmp/hej.txt  ~/.
//
//   real    0m3.430s
//   user    0m0.021s
//   sys     0m3.401s
TEST_F(TestFileIO, SYSTEM__MoveFiles__LargeFileCanBeMovedAcrossDevices) {
   std::string oldStorage = "/tmp";
   std::string newStorage = GetCurrentDirectory();
   if (false == FileIO::DoesDirectoryExist(oldStorage)) {
       SUCCEED() << "Skipping test. Cannot run test. directory does not exist: " << oldStorage;
       return;
   }

   if (false == FileIO::DoesDirectoryExist(newStorage)) {
      SUCCEED() << "Skipping test. Cannot run test. directory does not exist: " << newStorage;
      return;
   }

   // Verify that they are on different devices
   struct stat stat_path1;
   struct stat stat_path2;
   stat(oldStorage.c_str(), &stat_path1);
   stat(newStorage.c_str(), &stat_path2);
   if (stat_path1.st_dev == stat_path2.st_dev) {
      std::string warning = "SKIPPING TEST. CANNOT RUN TEST FOR VERIFYING MOVE OF FILES ACROSS DEVICES";
      std::cerr << "WARNING: " << warning << std::endl;
      SUCCEED() << warning;
   } else {

      //
      // We have two devices to test moving a large file between.
      // 3GB will be moved

      // Create the 3GB file
      std::string file1_3GBPath = {oldStorage + "/file1_3GB"};
      // use dd to write   (possibly)non zeroed data to the file
      std::string createFile3GB = {"dd bs=1024 count=3145728 if=/dev/zero of="}; // 3GB : 3145728 * 1024 bytes
      std::string createFile1 = {createFile3GB + file1_3GBPath};
      ScopedFileCleanup fileOldCleaner(file1_3GBPath);
      EXPECT_EQ(0, system(createFile1.c_str()));
      const int file1Permissions = 644;
      EXPECT_TRUE(0 == chmod(file1_3GBPath.c_str(), file1Permissions));
      EXPECT_TRUE(FileIO::DoesFileExist(file1_3GBPath));

      // Verify that the file was created as big as we expected
      // Set test unique file permissions on the file
      struct stat64 file1Stat;
      stat64(file1_3GBPath.c_str(), &file1Stat);
      EXPECT_EQ(file1Stat.st_size, int64_t{3L * 1024L * 1024L * 1024L});
      EXPECT_EQ(file1Stat.st_mode & file1Permissions, file1Permissions);
      EXPECT_NE(file1Stat.st_mode & 555, 555); // sanity check
      std::string checksumFile1Result = {mTestDirectory + "/1_chksum"};
      std::string checksumOnFile1 {"cksum  " + file1_3GBPath + " > " + checksumFile1Result};
      EXPECT_EQ(0, system(checksumOnFile1.c_str()));
      std::string checksum1AsString = FileIO::ReadAsciiFileContent(file1_3GBPath).result;

      // Move it to the other device
      std::string movedFile1_3GBFile = {newStorage + "/moved3GBFile"};
      ScopedFileCleanup fileNewCleaner(movedFile1_3GBFile);

      auto moved = FileIO::MoveFile(file1_3GBPath, movedFile1_3GBFile);
      EXPECT_TRUE(moved) << "std::strerror(errno): " << std::strerror(errno)
              << "\n file1: " << file1_3GBPath << ":" << FileIO::DoesFileExist(file1_3GBPath)
              << "\n file2: " << movedFile1_3GBFile << ":" << FileIO::DoesFileExist(movedFile1_3GBFile);

      EXPECT_FALSE(FileIO::DoesFileExist(file1_3GBPath));
      EXPECT_TRUE(FileIO::DoesFileExist(movedFile1_3GBFile));

      // verify size and permissions and integrity of the file
      struct stat64 fileMovedStat;
      stat64(movedFile1_3GBFile.c_str(), &fileMovedStat);
      EXPECT_EQ(fileMovedStat.st_size, size_t{3L * 1024L * 1024L * 1024L});
      EXPECT_EQ(fileMovedStat.st_mode & file1Permissions, file1Permissions);
      EXPECT_NE(fileMovedStat.st_mode & 555, 555); // sanity check

      // Verify checksums
      std::string checksumFile2Result = {mTestDirectory + "/2_chksum"};
      std::string checksumOnFile2 {"cksum " + movedFile1_3GBFile + " > " + checksumFile2Result};
      EXPECT_EQ(0, system(checksumOnFile2.c_str()));
      std::string checksum2AsString = FileIO::ReadAsciiFileContent(movedFile1_3GBFile).result;
      EXPECT_EQ(checksum1AsString,checksum2AsString);
   }
}

TEST_F(TestFileIO, CleanDirectoryOfFileContents_BogusDirectory) {
   std::vector<std::string> newDirectories;
   size_t removedFiles{0};
   EXPECT_FALSE(FileIO::CleanDirectoryOfFileContents("", removedFiles, newDirectories).result);
   EXPECT_FALSE(FileIO::CleanDirectoryOfFileContents("/does/not/exist/", removedFiles, newDirectories).result);
}

TEST_F(TestFileIO, CleanDirectoryOfFileContents) {
   std::vector<std::string> newDirectories;
   size_t removedFiles{0};
   CreateSubDirectory("some_directory");
   EXPECT_TRUE(FileIO::DoesDirectoryExist({mTestDirectory + "/some_directory"}));
   EXPECT_EQ(removedFiles, 0);

   CreateFile(mTestDirectory, "some_file");
   EXPECT_TRUE(FileIO::CleanDirectoryOfFileContents(mTestDirectory, removedFiles, newDirectories).result);
   EXPECT_EQ(removedFiles, 1);
   ASSERT_EQ(newDirectories.size(), 1);
   EXPECT_EQ(std::string{mTestDirectory + "/some_directory"}, newDirectories[0]);
   // directories are not removed
   EXPECT_TRUE(FileIO::DoesDirectoryExist({mTestDirectory + "/some_directory"}));
}

TEST_F(TestFileIO, CleanDirectoryOfFileContents__StopsWhenInterrupted) {
   std::vector<std::string> newDirectories;
   size_t removedFiles{0};

   EXPECT_EQ(removedFiles, 0);
   volatile int interrupted = 1;
   FileIO::SetInterruptFlag(&interrupted);

   CreateFile(mTestDirectory, "some_file1");
   CreateFile(mTestDirectory, "some_file2");
   EXPECT_TRUE(FileIO::CleanDirectoryOfFileContents(mTestDirectory, removedFiles, newDirectories).result);
   FileIO::SetInterruptFlag(); // reset before we can exit the test
   EXPECT_EQ(removedFiles, 1); // NOT TWO files since we interrupted it
}

TEST_F(TestFileIO, CleanDirectory__NoDirectory__ExpectFailure) {
   std::string nonsense = "/bla/bla/bla/does/not/exist";
   const bool removeStartDirectory = true;
   const bool keepStartDirectory = false;
   auto result = FileIO::CleanDirectory(nonsense, removeStartDirectory);
   EXPECT_TRUE(result.HasFailed());
   auto result2 = FileIO::CleanDirectory(nonsense, keepStartDirectory);
   EXPECT_TRUE(result2.HasFailed());

   // same for a file
   auto file = CreateFile(mTestDirectory, "file.txt");
   EXPECT_TRUE(FileIO::DoesFileExist(file));
   auto result3 = FileIO::CleanDirectory(file, keepStartDirectory);
   EXPECT_TRUE(result3.HasFailed());
}

TEST_F(TestFileIO, CleanDirectoryOfFilesAndDirectories) {
   const std::string baseDir = CreateSubDirectory("base");
   ASSERT_TRUE(FileIO::DoesDirectoryExist(baseDir));

   auto createContent = [&]() {
      // Create a bunch of directories. both with content and emtpy
      std::string currentLevel = baseDir;
      for (size_t index = 0; index < 100; ++index){
         std::string dir1 = CreateSubDirectory("dir1", currentLevel);
         std::string dir2 = CreateSubDirectory("dir2", currentLevel);
         EXPECT_TRUE(FileIO::DoesDirectoryExist(dir1));
         EXPECT_TRUE(FileIO::DoesDirectoryExist(dir2));

         std::string file = CreateFile(dir1, "file.txt");
         EXPECT_TRUE(FileIO::DoesFileExist(file));
         currentLevel = dir1;
      }
   };

   createContent();
   EXPECT_TRUE(FileIO::DoesDirectoryExist({baseDir + "/dir1"}));
   EXPECT_TRUE(FileIO::DoesDirectoryExist({baseDir + "/dir2"}));
   EXPECT_TRUE(FileIO::DoesFileExist({baseDir + "/dir1/file.txt"}));

   // keep base dir
   const bool keepStartDirectory = false;
   auto result1 = FileIO::CleanDirectory(baseDir, keepStartDirectory);
   EXPECT_EQ(result1.HasFailed(), false);
   EXPECT_FALSE(FileIO::DoesDirectoryExist({baseDir + "/dir1"}));
   EXPECT_FALSE(FileIO::DoesDirectoryExist({baseDir + "/dir2"}));
   EXPECT_FALSE(FileIO::DoesFileExist({baseDir + "/dir1/file.txt"}));
   EXPECT_TRUE(FileIO::DoesDirectoryExist(baseDir)); // BASE DIR IS KEPT

   // remove base dir
   createContent();
   const bool removeStartDirectory = true;
   auto result2 = FileIO::CleanDirectory(baseDir, removeStartDirectory);
   EXPECT_EQ(result2.HasFailed(), false);
   EXPECT_FALSE(FileIO::DoesDirectoryExist({baseDir + "/dir1"}));
   EXPECT_FALSE(FileIO::DoesDirectoryExist({baseDir + "/dir2"}));
   EXPECT_FALSE(FileIO::DoesFileExist({baseDir + "/dir1/file.txt"}));
   EXPECT_FALSE(FileIO::DoesDirectoryExist(baseDir)); // BASE DIR IS REMOVED

}

TEST_F(TestFileIO, TestReadAsciiFileContentAsRoot) {

   int previousUID = setfsuid(-1);
   int previousGID = setfsgid(-1);
   ASSERT_EQ(previousUID, 0);
   ASSERT_EQ(previousGID, 0);

   FileIO::SetUserFileSystemAccess("nobody");

   int targetUID = setfsuid(-1);
   int targetGID = setfsgid(-1);
   ASSERT_NE(targetUID, 0);
   ASSERT_NE(targetGID, 0);

   //Open a common root permissioned file without root permissions.
   auto badResult = FileIO::ReadAsciiFileContent("/etc/sysconfig/iptables");
   ASSERT_TRUE(badResult.HasFailed());

   //Open a common root permissioned file.
   auto goodResult = FileIO::ReadAsciiFileContentAsRoot("/etc/sysconfig/iptables");
   EXPECT_FALSE(goodResult.HasFailed());
   EXPECT_TRUE(goodResult.result.size() > 0);
}

TEST_F(TestFileIO, AThousandFiles) {
   using namespace FileIO;
   for (size_t index = 0; index < 1000; ++index) {
      CreateFile(mTestDirectory, std::to_string(index));
   }

   std::vector<std::string> files;
   DirectoryReader::Entry entry;

   DirectoryReader reader(mTestDirectory);
   entry = reader.Next();
   while (entry.first != FileType::End) {
      ASSERT_NE(entry.first, FileType::Directory);
      ASSERT_NE(entry.first, FileType::Unknown);
      files.push_back(entry.second);
      entry = reader.Next();
   }

   ASSERT_EQ(files.size(), 1000);

   std::sort(files.begin(), files.end(), [](const std::string& lh, const std::string & rh) {
      return std::stoul(lh) < std::stoul(rh);
   });
   for (size_t index = 0; index < 1000; ++index) {
      EXPECT_EQ(files[index], std::to_string(index));
   }
}

TEST_F(TestFileIO, DirectoryReader_NotExistingDirectory) {
   FileIO::DirectoryReader reader{mTestDirectory + "/_#Does_not+_exist"};
   EXPECT_TRUE(reader.Valid().HasFailed()) << reader.Valid().error;
}

TEST_F(TestFileIO, DirectoryReader_ExistingDirectory) {
   FileIO::DirectoryReader reader{mTestDirectory};
   EXPECT_FALSE(reader.Valid().HasFailed()) << reader.Valid().error;
}

// An empty directory will only contain "." and ".." which we ignores
TEST_F(TestFileIO, DirectoryReader_NoFilesInDirectory) {
   FileIO::DirectoryReader reader{mTestDirectory};
   EXPECT_FALSE(reader.Valid().HasFailed());

   FileIO::DirectoryReader::Entry fileAndType = reader.Next();
   EXPECT_EQ(fileAndType.first, FileIO::FileType::End);
   EXPECT_EQ(fileAndType.second, "");
}

TEST_F(TestFileIO, DirectoryReader_HasFilesInDirectory__AfterReset) {
   using namespace FileIO;

   DirectoryReader reader{mTestDirectory};
   DirectoryReader::Entry fileAndType = reader.Next();

   EXPECT_EQ(fileAndType.first, FileType::End);
   EXPECT_EQ(fileAndType.second, "");

   // We have already reached the end. This must be reset before reading successfully
   CreateFile(mTestDirectory, "some_file");
   fileAndType = reader.Next();
   EXPECT_EQ(fileAndType.first, FileType::End);
   EXPECT_EQ(fileAndType.second, "");

   // After the reset we can find the file
   reader.Reset();
   fileAndType = reader.Next();
   EXPECT_EQ(fileAndType.first, FileType::File);
   EXPECT_EQ(fileAndType.second, "some_file");

   // has reached the end again
   fileAndType = reader.Next();
   EXPECT_EQ(fileAndType.second, "");
   EXPECT_EQ(fileAndType.first, FileType::End);

   CreateSubDirectory("some_directory");
   EXPECT_TRUE(FileIO::DoesDirectoryExist({mTestDirectory + "/some_directory"}));
   reader.Reset();

   fileAndType = reader.Next();
   EXPECT_NE(fileAndType.first, FileType::End);

   std::string filename;
   std::string directoryname;

   for (size_t count = 0; count < 2; ++count) {
      if (fileAndType.first == FileType::Directory) {
         directoryname = fileAndType.second;
         fileAndType = reader.Next();
      } else if (fileAndType.first == FileType::File) {
         filename = fileAndType.second;
         fileAndType = reader.Next();
      } else {
         // ignored,. "unknown result", can if wanted be printed out by: "fileAndType.second"
      }
   }

   EXPECT_EQ(filename, "some_file");
   EXPECT_EQ(directoryname, "some_directory");
   fileAndType = reader.Next();

   EXPECT_EQ(fileAndType.first, FileType::End);
   EXPECT_EQ(fileAndType.second, "");
}

TEST_F(TestFileIO, Directory_or_bogus_IsNotAMountPoint) {
   auto directory = CreateSubDirectory("A_Directory");
   std::string expectedDirectory  = {mTestDirectory + "/A_Directory"};
   EXPECT_EQ(directory, expectedDirectory);
   EXPECT_TRUE(FileIO::DoesDirectoryExist(directory));
   EXPECT_FALSE(FileIO::IsMountPoint(directory).result);
   EXPECT_TRUE(FileIO::IsMountPoint(directory).HasFailed());

   EXPECT_FALSE(FileIO::IsMountPoint("/does_not_exist/ever/").result);
   EXPECT_TRUE(FileIO::IsMountPoint("/does_not_exist/ever/").HasFailed());

   auto file = CreateFile(directory, "test_file");
   EXPECT_TRUE(FileIO::DoesFileExist(file));
   EXPECT_FALSE(FileIO::IsMountPoint(file).result);
   EXPECT_TRUE(FileIO::IsMountPoint(file).HasFailed());
}

TEST_F(TestFileIO, SYSTEM__Slash_is_always_A_MountPoint) {
   std::string directory = {"/"};
   EXPECT_TRUE(FileIO::DoesDirectoryExist(directory));

   Result<bool> status = FileIO::IsMountPoint(directory);
   EXPECT_TRUE(status.result) << status.error;
   EXPECT_FALSE(status.HasFailed()) << status.error;
}

// This could fail if the system is setup with /root as its own partition
// it is fairly uncommon to do that so I keep it as this for now / Kjell
TEST_F(TestFileIO, SYSTEM__root_is_not_A_MountPoint) {
   std::string directory = {"/root"};
   EXPECT_TRUE(FileIO::DoesDirectoryExist(directory));

   Result<bool> status = FileIO::IsMountPoint(directory);
   EXPECT_FALSE(status.result) << status.error;
   EXPECT_TRUE(status.HasFailed()) << status.error;
}

TEST_F(TestFileIO, SYSTEM__Dependent_Stuff__MountPoint) {

   Result<bool> status = FileIO::IsMountPoint("/").result;
   EXPECT_TRUE(status.result) << status.error;
   EXPECT_FALSE(status.HasFailed()) << status.error;

   EXPECT_TRUE(FileIO::IsMountPoint("/home").result);
}

// FileIO #files   time
//        63,8841  761 ms
//        994,080  1 sec

// Boost #files   time
//       63,8841  3199 ms
//       985,524  5 sec
TEST_F(TestFileIO, DISABLED_System_Performance_FileIO__vs_Boost) {
   using namespace FileIO;

   DirectoryReader::Entry entry;

   StopWatch timeToFind;

   size_t filecounter = 0;

   std::string path = {"/tmp"};
   DirectoryReader reader(path);
   if (false == reader.Valid().HasFailed()) {
      reader.Next();
      while (entry.first != FileIO::FileType::End) {
         ++filecounter;
      }
      entry = reader.Next();
   }

   std::cout << "FileIO Time to find " << filecounter << "took: " << timeToFind.ElapsedSec() << " sec" << std::endl;
   timeToFind.Restart();
   boost::filesystem::path boostPath = path;
   boost::filesystem::directory_iterator end;
   filecounter = 0;
   for (boost::filesystem::directory_iterator dir_iter(boostPath); dir_iter != end; ++dir_iter) {
      if (boost::filesystem::is_regular_file(dir_iter->status())) {
         ++filecounter;
      }
   }
   std::cout  << "Boost Time to find " << filecounter << "took: " << timeToFind.ElapsedSec() << " sec" << std::endl;
}