<commit_before>// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
#include <Rmath.h>

#include <vector>
#include <cassert>

#include "vmat.h"
#include "gmat.h"
#include "DataPairs.h"
#include "quadrule.h"
#include "pn.h"
#include "functions.h"

using namespace Rcpp;
using namespace arma;
using namespace std;

const double twopi = 2*datum::pi;

/////////////////////////////////////////////////////////////////////////////////////////////////
/* Full loglikelihood */
double loglikfull(unsigned row, DataPairs &data, const gmat &sigmaMarg, const gmat &sigmaJoint, const gmat &sigmaMargCond, vmat sigmaU, vec u, bool full=1){

  data.pi_gen(row, u); // Estimation of pi based on u

  irowvec causes = data.causes_get(row); // Failure causes for pair in question

  double res = 0; // Initialising output (loglik contribution)

  if ((causes(0) > 0) & (causes(1) > 0)){
    /* Both individuals experience failure */
    res = logdF2(row, causes, data, sigmaJoint, u);
  }
  else if((causes(0) <= 0) & (causes(1) <= 0)){
    /* Neither individual experience failure */

    if ((causes(0) < 0) & (causes(1) < 0)){
      // Full follow-up for both individuals
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data);
	  lik -= prob;
	}
	res += log(lik);
      }
    }
    else if (((causes(0) < 0) & (causes(1) == 0)) | ((causes(0) == 0) & (causes(1) < 0))){
      // Full follow-up for only one individual
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  if (causes(i-1) < 0){
	    double prob = F1(row, j, i, data);
	    lik -= prob;
	  }
	  else {
	    double prob = F1(row, j, i, data, sigmaMarg, u);
	    lik -= prob;
	  }
	}
	res += log(lik);
      }
    }
    else {
      // Full follow-up for neither individual
      double lik = 1;
      // Marginal probabilities
      for (unsigned i=1; i<=2; i++){ // Over individuals
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data, sigmaMarg, u);
	  lik -= prob; // Subtracting
	}
      }
      // Bivariate probabilities
      for (unsigned k=1; k<=data.ncauses; k++){ // Over failure causes
	for (unsigned l=1; l<=data.ncauses; l++){
	  irowvec vcauses(2);
	  vcauses(0) = k; vcauses(1) = l;
	  double prob = F2(row, vcauses, data, sigmaJoint, u);
	  lik += prob; // Adding
	}
      }
      res = log(lik);
    }
  }
  else {
    /* One individual experiences failure the other does not */
    for (unsigned i=1; i<=2; i++){ // Over individuals
      unsigned cause = causes(i-1);
      if (cause > 0){
	// Marginal probability of failure
	res += logdF1(row, cause, i, data, sigmaMarg, u);
      }
      else {
	// Marginal probability of no failure
	unsigned cond_cause;
	if (i==1){
	  cond_cause = causes(1);
	}
	else {
	  cond_cause = causes(0);
	}
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double lik = 1;
	  if (cause < 0){
	    // Unconditional
	    double prob = F1(row, j, i, data);
	    lik -= prob;
	  }
	  else {
	    // Conditional
	    double prob = F1(row, j, i, cond_cause, data, sigmaMargCond, u);
	    lik -= prob;
	  }
	  res += log(lik);
	}
      }
    }
  }
  /* Contribution from u */
  if (full){
    vmat sig = sigmaU; // Variance-covariance matrix of u
    double inner = as_scalar(u*sig.inv*u.t());

    // PDF of u
    double logpdfu = log(pow(twopi,-(data.ncauses/2))) + sig.loginvsqdet - 0.5*inner;

    // Adding to the loglik
    res += logpdfu;
  }

  /* Return */
  return(res);
}

/////////////////////////////////////////////////////////////////////////////////////////////////
/* Score function of full loglikelihood */
rowvec Dloglikfull(unsigned row, DataPairs &data, const gmat &sigmaMarg, const gmat &sigmaJoint, const gmat &sigmaMargCond, vmat sigmaU, vec u, bool full=1){

  /* Estimation of pi, dpidu and dlogpidu */
  data.pi_gen(row, u);
  data.dpidu_gen(row, u);
  data.dlogpidu_gen(row, u);

  irowvec causes = data.causes_get(row); // Failure causes for pair in question

  rowvec res = zeros<rowvec>(data.ncauses); // Initialising output (score contribution)

  if ((causes(0) > 0) & (causes(1) > 0)){
    /* Both individuals experience failure */
    res = dlogdF2du(row, causes, data, sigmaJoint, u);
  }
  else if((causes(0) <= 0) & (causes(1) <= 0)){
    /* Neither individual experience failure */

    if ((causes(0) < 0) & (causes(1) < 0)){
      // Full follow-up for both individuals
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	rowvec likdu = zeros<rowvec>(data.ncauses);
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data);
	  rowvec probdu = dF1du(row, j, i, data);
	  lik -= prob;
	  likdu -= probdu;
	}
	res += (1/lik)*likdu;
      }
    }
    else if (((causes(0) < 0) & (causes(1) == 0)) | ((causes(0) == 0) & (causes(1) < 0))){
      // Full follow-up for only one individual
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	rowvec likdu = zeros<rowvec>(data.ncauses);
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  if (causes(i-1) < 0){
	    double prob = F1(row, j, i, data);
	    rowvec probdu = dF1du(row, j, i, data);
	    lik -= prob;
	    likdu -= probdu;
	  }
	  else {
	    double prob = F1(row, j, i, data, sigmaMarg, u);
	    rowvec probdu = dF1du(row, j, i, data, sigmaMarg, u);
	    lik -= prob;
	    likdu -= probdu;
	  }
	}
	res += (1/lik)*likdu;
      }
    }
    else {
      // Full follow-up for neither individual
      double lik = 1;
      rowvec likdu = zeros<rowvec>(data.ncauses);
      // Marginal probabilities
      for (unsigned i=1; i<=2; i++){ // Over individuals
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data, sigmaMarg, u);
	  rowvec probdu = dF1du(row, j, i, data, sigmaMarg, u);
	  lik -= prob; // Subtracting
	  likdu -= probdu;
	}
      }
      // Bivariate probabilities
      for (unsigned k=1; k<=data.ncauses; k++){ // Over failure causes
	for (unsigned l=1; l<=data.ncauses; l++){
	  irowvec vcauses(2);
	  vcauses(0) = k; vcauses(1) = l;
	  double prob = F2(row, vcauses, data, sigmaJoint, u);
	  rowvec probdu = dF2du(row, vcauses, data, sigmaJoint, u);
	  lik += prob; // Adding
	  likdu += probdu;
	}
      }
      res = (1/lik)*likdu;
    }
  }
  else {
    /* One individual experiences failure the other does not */
    for (unsigned i=1; i<=2; i++){ // Over individuals
      unsigned cause = causes(i-1);
      if (cause > 0){
	// Marginal probability of failure
	res += dlogdF1du(row, cause, i, data, sigmaMarg, u);
      }
      else {
	// Marginal probability of no failure
	unsigned cond_cause;
	if (i==1){
	  cond_cause = causes(1);
	}
	else {
	  cond_cause = causes(0);
	}
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double lik = 1;
	  rowvec likdu = zeros<rowvec>(data.ncauses);
	  if (cause < 0){ // Uncondtional
	    double prob = F1(row, j, i, data);
	    rowvec probdu = dF1du(row, j, i, data);
	    lik -= prob;
	    likdu -= probdu;
	  }
	  else { // Conditional
	    double prob = F1(row, j, i, cond_cause, data, sigmaMargCond, u);
	    rowvec probdu = dF1du(row, j, i, cond_cause, data, sigmaMargCond, u);
	    lik -= prob;
	    likdu -= probdu;
	  }
	  res += (1/lik)*likdu;
	}
      }
    }
  }
  /* Contribution from u */
  if (full){

    vmat sig = sigmaU; // Variance-covariance matrix etc. of u

    // Adding to the score
    res += -u.t()*sig.inv;
  };
  return(res);
}

/////////////////////////////////////////////////////////////////////////////
// FOR TESTING

double loglikout(unsigned row, mat sigma, vec u, int ncauses, imat causes, mat alpha, mat dalpha, mat beta, mat gamma){

  // Initialising gmats of sigma (Joint, Cond)
  gmat sigmaJoint = gmat(ncauses, ncauses);
  gmat sigmaCond = gmat(ncauses, ncauses);

  // Vectors for extracting rows and columns from sigma
  uvec rcJ(2); /* for joint */
  uvec rc1(1); /* for conditional */
  uvec rc2(ncauses+1); /* for conditional */
  uvec rcu(ncauses);
  for (int h=0; h<ncauses; h++){
    rcu(h) = ncauses + h;
  };

  // Estimating and setting vmats sigmaJoint
  for (int h=0; h<ncauses; h++){
    for (int i=0; i<ncauses; i++){
      rcJ(0)=h;
      rcJ(1)=ncauses+i;
      vmat x = vmat(sigma, rcJ, rcu);
      sigmaJoint.set(h,i,x);
    };
  };

  // Estimating and setting vmats of sigmaCond
  for (int h=0; h<ncauses; h++){
    for (int i=0; i<ncauses; i++){
      rc1(1) = h;
      rc2(0) = i;
      for (int j=0; j<ncauses; j++){
	rc2(j+1) = rcu(j);
      };
      vmat x = vmat(sigma, rc1, rc2);
      sigmaCond.set(h,i,x);
    };
  };

  // vmat of the us
  mat matU = sigma.submat(rcu,rcu);
  vmat sigmaU = vmat(matU);

  // Generating DataPairs
  DataPairs data = DataPairs(int ncauses, imat causes, mat alpha, mat dalpha, mat beta, mat gamma);

  // Estimating likelihood contribution
  double loglik = loglikfull(unsigned row, DataPairs data, gmat sigmaJoint, gmat sigmaCond, vmat sigmaU, vec u, bool full=1);

  // Return
  return loglik;
};

//rowvec Dloglikout(unsigned row, mat sigma, mat data, vec u){

  // Generating gmats of sigma (Marg, Joint, MargCond, sigU)

  // Generating DataPairs

  // Estimating score contribution
//  rowvec score = Dloglikfull(unsigned row, DataPairs data, gmat sigmaJoint, gmat sigmaMargCond, vmat sigmaU, vec u, bool full=1);

  // Return
//  return score;
//};
<commit_msg>testing<commit_after>// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
#include <Rmath.h>

#include <vector>
#include <cassert>

#include "vmat.h"
#include "gmat.h"
#include "DataPairs.h"
#include "quadrule.h"
#include "pn.h"
#include "functions.h"

using namespace Rcpp;
using namespace arma;
using namespace std;

const double twopi = 2*datum::pi;

/////////////////////////////////////////////////////////////////////////////////////////////////
/* Full loglikelihood */
double loglikfull(unsigned row, DataPairs &data, const gmat &sigmaMarg, const gmat &sigmaJoint, const gmat &sigmaMargCond, vmat sigmaU, vec u, bool full=1){

  data.pi_gen(row, u); // Estimation of pi based on u

  irowvec causes = data.causes_get(row); // Failure causes for pair in question

  double res = 0; // Initialising output (loglik contribution)

  if ((causes(0) > 0) & (causes(1) > 0)){
    /* Both individuals experience failure */
    res = logdF2(row, causes, data, sigmaJoint, u);
  }
  else if((causes(0) <= 0) & (causes(1) <= 0)){
    /* Neither individual experience failure */

    if ((causes(0) < 0) & (causes(1) < 0)){
      // Full follow-up for both individuals
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data);
	  lik -= prob;
	}
	res += log(lik);
      }
    }
    else if (((causes(0) < 0) & (causes(1) == 0)) | ((causes(0) == 0) & (causes(1) < 0))){
      // Full follow-up for only one individual
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  if (causes(i-1) < 0){
	    double prob = F1(row, j, i, data);
	    lik -= prob;
	  }
	  else {
	    double prob = F1(row, j, i, data, sigmaMarg, u);
	    lik -= prob;
	  }
	}
	res += log(lik);
      }
    }
    else {
      // Full follow-up for neither individual
      double lik = 1;
      // Marginal probabilities
      for (unsigned i=1; i<=2; i++){ // Over individuals
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data, sigmaMarg, u);
	  lik -= prob; // Subtracting
	}
      }
      // Bivariate probabilities
      for (unsigned k=1; k<=data.ncauses; k++){ // Over failure causes
	for (unsigned l=1; l<=data.ncauses; l++){
	  irowvec vcauses(2);
	  vcauses(0) = k; vcauses(1) = l;
	  double prob = F2(row, vcauses, data, sigmaJoint, u);
	  lik += prob; // Adding
	}
      }
      res = log(lik);
    }
  }
  else {
    /* One individual experiences failure the other does not */
    for (unsigned i=1; i<=2; i++){ // Over individuals
      unsigned cause = causes(i-1);
      if (cause > 0){
	// Marginal probability of failure
	res += logdF1(row, cause, i, data, sigmaMarg, u);
      }
      else {
	// Marginal probability of no failure
	unsigned cond_cause;
	if (i==1){
	  cond_cause = causes(1);
	}
	else {
	  cond_cause = causes(0);
	}
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double lik = 1;
	  if (cause < 0){
	    // Unconditional
	    double prob = F1(row, j, i, data);
	    lik -= prob;
	  }
	  else {
	    // Conditional
	    double prob = F1(row, j, i, cond_cause, data, sigmaMargCond, u);
	    lik -= prob;
	  }
	  res += log(lik);
	}
      }
    }
  }
  /* Contribution from u */
  if (full){
    vmat sig = sigmaU; // Variance-covariance matrix of u
    double inner = as_scalar(u*sig.inv*u.t());

    // PDF of u
    double logpdfu = log(pow(twopi,-(data.ncauses/2))) + sig.loginvsqdet - 0.5*inner;

    // Adding to the loglik
    res += logpdfu;
  }

  /* Return */
  return(res);
}

/////////////////////////////////////////////////////////////////////////////////////////////////
/* Score function of full loglikelihood */
rowvec Dloglikfull(unsigned row, DataPairs &data, const gmat &sigmaMarg, const gmat &sigmaJoint, const gmat &sigmaMargCond, vmat sigmaU, vec u, bool full=1){

  /* Estimation of pi, dpidu and dlogpidu */
  data.pi_gen(row, u);
  data.dpidu_gen(row, u);
  data.dlogpidu_gen(row, u);

  irowvec causes = data.causes_get(row); // Failure causes for pair in question

  rowvec res = zeros<rowvec>(data.ncauses); // Initialising output (score contribution)

  if ((causes(0) > 0) & (causes(1) > 0)){
    /* Both individuals experience failure */
    res = dlogdF2du(row, causes, data, sigmaJoint, u);
  }
  else if((causes(0) <= 0) & (causes(1) <= 0)){
    /* Neither individual experience failure */

    if ((causes(0) < 0) & (causes(1) < 0)){
      // Full follow-up for both individuals
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	rowvec likdu = zeros<rowvec>(data.ncauses);
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data);
	  rowvec probdu = dF1du(row, j, i, data);
	  lik -= prob;
	  likdu -= probdu;
	}
	res += (1/lik)*likdu;
      }
    }
    else if (((causes(0) < 0) & (causes(1) == 0)) | ((causes(0) == 0) & (causes(1) < 0))){
      // Full follow-up for only one individual
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	rowvec likdu = zeros<rowvec>(data.ncauses);
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  if (causes(i-1) < 0){
	    double prob = F1(row, j, i, data);
	    rowvec probdu = dF1du(row, j, i, data);
	    lik -= prob;
	    likdu -= probdu;
	  }
	  else {
	    double prob = F1(row, j, i, data, sigmaMarg, u);
	    rowvec probdu = dF1du(row, j, i, data, sigmaMarg, u);
	    lik -= prob;
	    likdu -= probdu;
	  }
	}
	res += (1/lik)*likdu;
      }
    }
    else {
      // Full follow-up for neither individual
      double lik = 1;
      rowvec likdu = zeros<rowvec>(data.ncauses);
      // Marginal probabilities
      for (unsigned i=1; i<=2; i++){ // Over individuals
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data, sigmaMarg, u);
	  rowvec probdu = dF1du(row, j, i, data, sigmaMarg, u);
	  lik -= prob; // Subtracting
	  likdu -= probdu;
	}
      }
      // Bivariate probabilities
      for (unsigned k=1; k<=data.ncauses; k++){ // Over failure causes
	for (unsigned l=1; l<=data.ncauses; l++){
	  irowvec vcauses(2);
	  vcauses(0) = k; vcauses(1) = l;
	  double prob = F2(row, vcauses, data, sigmaJoint, u);
	  rowvec probdu = dF2du(row, vcauses, data, sigmaJoint, u);
	  lik += prob; // Adding
	  likdu += probdu;
	}
      }
      res = (1/lik)*likdu;
    }
  }
  else {
    /* One individual experiences failure the other does not */
    for (unsigned i=1; i<=2; i++){ // Over individuals
      unsigned cause = causes(i-1);
      if (cause > 0){
	// Marginal probability of failure
	res += dlogdF1du(row, cause, i, data, sigmaMarg, u);
      }
      else {
	// Marginal probability of no failure
	unsigned cond_cause;
	if (i==1){
	  cond_cause = causes(1);
	}
	else {
	  cond_cause = causes(0);
	}
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double lik = 1;
	  rowvec likdu = zeros<rowvec>(data.ncauses);
	  if (cause < 0){ // Uncondtional
	    double prob = F1(row, j, i, data);
	    rowvec probdu = dF1du(row, j, i, data);
	    lik -= prob;
	    likdu -= probdu;
	  }
	  else { // Conditional
	    double prob = F1(row, j, i, cond_cause, data, sigmaMargCond, u);
	    rowvec probdu = dF1du(row, j, i, cond_cause, data, sigmaMargCond, u);
	    lik -= prob;
	    likdu -= probdu;
	  }
	  res += (1/lik)*likdu;
	}
      }
    }
  }
  /* Contribution from u */
  if (full){

    vmat sig = sigmaU; // Variance-covariance matrix etc. of u

    // Adding to the score
    res += -u.t()*sig.inv;
  };
  return(res);
}

/////////////////////////////////////////////////////////////////////////////
// FOR TESTING

double loglikout(unsigned row, mat sigma, vec u, int ncauses, imat causes, mat alpha, mat dalpha, mat beta, mat gamma){

  // Initialising gmats of sigma (Joint, Cond)
  gmat sigmaJoint = gmat(ncauses, ncauses);
  gmat sigmaCond = gmat(ncauses, ncauses);

  // Vectors for extracting rows and columns from sigma
  uvec rcJ(2); /* for joint */
  uvec rc1(1); /* for conditional */
  uvec rc2(ncauses+1); /* for conditional */
  uvec rcu(ncauses);
  for (int h=0; h<ncauses; h++){
    rcu(h) = ncauses + h;
  };

  // Estimating and setting vmats sigmaJoint
  for (int h=0; h<ncauses; h++){
    for (int i=0; i<ncauses; i++){
      rcJ(0)=h;
      rcJ(1)=ncauses+i;
      vmat x = vmat(sigma, rcJ, rcu);
      sigmaJoint.set(h,i,x);
    };
  };

  // Estimating and setting vmats of sigmaCond
  for (int h=0; h<ncauses; h++){
    for (int i=0; i<ncauses; i++){
      rc1(1) = h;
      rc2(0) = i;
      for (int j=0; j<ncauses; j++){
	rc2(j+1) = rcu(j);
      };
      vmat x = vmat(sigma, rc1, rc2);
      sigmaCond.set(h,i,x);
    };
  };

  // vmat of the us
  mat matU = sigma.submat(rcu,rcu);x
  vmat sigmaU = vmat(matU);

  // Generating DataPairs
  DataPairs data = DataPairs(ncauses, causes, alpha, dalpha, beta, gamma);

  // Estimating likelihood contribution
  double loglik = loglikfull(unsigned row, data, sigmaJoint, sigmaCond, sigmaU, u, bool full=1);

  // Return
  return loglik;
};

//rowvec Dloglikout(unsigned row, mat sigma, mat data, vec u){

  // Generating gmats of sigma (Marg, Joint, MargCond, sigU)

  // Generating DataPairs

  // Estimating score contribution
//  rowvec score = Dloglikfull(unsigned row, DataPairs data, gmat sigmaJoint, gmat sigmaMargCond, vmat sigmaU, vec u, bool full=1);

  // Return
//  return score;
//};
<|endoftext|>


<commit_before>#include "NTClient.h"
using namespace std;

NTClient::NTClient(int _wpm, double _accuracy) {
	typeIntervalMS = 12000 / _wpm;
	wpm = _wpm;
	accuracy = _accuracy;
	firstConnect = true;
	connected = false;
	finished = false;
	lessonLen = 0;
	log = new NTLogger("(Not logged in)");
	wsh = nullptr;
	racesCompleted = 0;
	rIdx = 0;
	eIdx = 0;
}
NTClient::~NTClient() {
	if (log != nullptr) {
		delete log;
		log = nullptr;
	}
	if (wsh != nullptr) {
		delete wsh;
		wsh = nullptr;
	}
}
bool NTClient::login(string username, string password) {
	log->type(LOG_HTTP);
	log->wr("Logging into the NitroType account...\n");
	log->setUsername(username);
	uname = username;
	pword = password;
	bool ret = true;
	string data = string("username=");
	data += uname;
	data += "&password=";
	data += pword;
	data += "&adb=1&tz=America%2FChicago"; // No need to have anything other than Chicago timezone
	httplib::SSLClient loginReq(NITROTYPE_HOSTNAME, HTTPS_PORT);
	shared_ptr<httplib::Response> res = loginReq.post(NT_LOGIN_ENDPOINT, data, "application/x-www-form-urlencoded; charset=UTF-8");
	if (res) {
		bool foundLoginCookie = false;
		for (int i = 0; i < res->cookies.size(); ++i) {
			string cookie = res->cookies.at(i);
			addCookie(Utils::extractCKey(cookie), Utils::extractCValue(cookie));
			if (cookie.find("ntuserrem=") == 0) {
				foundLoginCookie = true;
				token = Utils::extractCValue(cookie);
				log->type(LOG_HTTP);
				log->wr("Resolved ntuserrem login token.\n");
				// addCookie("ntuserrem", token);
			}
		}
		if (!foundLoginCookie) {
			ret = false;
			log->type(LOG_HTTP);
			log->wr("Unable to locate the login cookie. Maybe try a different account?\n");
		}
	} else {
		ret = false;
		log->type(LOG_HTTP);
		log->wr("Login request failed. This might be a network issue. Maybe try resetting your internet connection?\n");
	}
	if (ret == false) {
		log->type(LOG_HTTP);
		log->wr("Failed to log in.\n");
	} else {
		bool success = getPrimusSID();
		if (!success) return false;
	}
	return ret;
}
bool NTClient::connect() {
	wsh = new Hub();
	time_t tnow = time(0);
	rawCookieStr = Utils::stringifyCookies(&cookies);
	stringstream uristream;
	uristream  << "wss://realtime1.nitrotype.com:443/realtime/?_primuscb=" << tnow << "-0&EIO=3&transport=websocket&sid=" << primusSid << "&t=" << tnow << "&b64=1";
	string wsURI = uristream.str();
	log->type(LOG_CONN);
	log->wr("Attempting to connect to the NitroType realtime server...\n");
	if (firstConnect) {
		addListeners();
	}
	// cout << "Cookies: " << rawCookieStr << endl << endl;
	// Create override headers
	customHeaders["Cookie"] = rawCookieStr;
	customHeaders["Origin"] = "https://www.nitrotype.com";
	customHeaders["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/55.0.2883.87 Chrome/55.0.2883.87 Safari/537.36";
	// customHeaders["Host"] = "realtime1.nitrotype.com";
	wsh->connect(wsURI, (void*)this, customHeaders, 7000);
	// wsh->connect(wsURI);
	if (firstConnect) {
		wsh->run();
		firstConnect = false;
	}
	return true;
}
void NTClient::addCookie(string key, string val) {
	SPair sp = SPair(key, val);
	cookies.push_back(sp);
}
bool NTClient::getPrimusSID() {
	time_t tnow = time(0);
	log->type(LOG_HTTP);
	log->wr("Resolving Primus SID...\n");
	rawCookieStr = Utils::stringifyCookies(&cookies);
	stringstream squery;
	squery << "?_primuscb=" << tnow << "-0&EIO=3&transport=polling&t=" << tnow << "-0&b64=1";
	string queryStr = squery.str();

	httplib::SSLClient loginReq(NT_REALTIME_HOST, HTTPS_PORT);
	string path = NT_PRIMUS_ENDPOINT + queryStr;
	shared_ptr<httplib::Response> res = loginReq.get(path.c_str(), rawCookieStr.c_str());
	if (res) {
		json jres = json::parse(res->body.substr(4, res->body.length()));
		primusSid = jres["sid"];
		log->type(LOG_HTTP);
		log->wr("Resolved Primus SID successfully.\n");
		// addCookie("io", primusSid);
	} else {
		cout << "Error retrieving primus handshake data.\n";
		return false;
	}
	return true;
}
string NTClient::getJoinPacket(int avgSpeed) {
	json p = {
		{"stream", "race"},
		{"msg", "join"},
		{"payload", {
			{"avgSpeed", avgSpeed},
			{"debugging", false},
			{"music", "standard"},
			{"track", "forest"},
			{"update", 3417}
		}}
	};
	return "4" + p.dump();
}
void NTClient::addListeners() {
	assert(wsh != nullptr);
	wsh->onError([this](void* udata) {
		log->type(LOG_CONN);
		log->wr("WebSocket connection error. Firing disconn event.\n");
		onDisconnection();
	});
	wsh->onConnection([this](WebSocket<CLIENT>* wsocket, HttpRequest req) {
		log->type(LOG_CONN);
		log->wr("Established a WebSocket connection with the realtime server.\n");
		onConnection(wsocket, req);
	});
	wsh->onDisconnection([this](WebSocket<CLIENT>* wsocket, int code, char* msg, size_t len) {
		log->type(LOG_CONN);
		log->wr("Disconnected from the realtime server.\n");
		onDisconnection();
	});
	wsh->onMessage([this](WebSocket<CLIENT>* ws, char* msg, size_t len, OpCode opCode) {
		onMessage(ws, msg, len, opCode);
	});
}
void NTClient::onDisconnection(void) {
	/*
	cout << "Disconn message: " << string(msg, len) << endl;
	cout << "Disconn code: " << code << endl;
	*/
	log->type(LOG_CONN);
	log->wr("Reconnecting to the realtime server...\n");
	getPrimusSID();
	rawCookieStr = Utils::stringifyCookies(&cookies);
	stringstream uristream;
	uristream  << "wss://realtime1.nitrotype.com:443/realtime/?_primuscb=" << time(0) << "-0&EIO=3&transport=websocket&sid=" << primusSid << "&t=" << time(0) << "&b64=1";
	string wsURI = uristream.str();
	wsh->connect(wsURI, (void*)this, customHeaders, 7000);
}
void NTClient::handleData(WebSocket<CLIENT>* ws, json* j) {
	// Uncomment to dump all raw JSON packets
	// cout << "Recieved json data:" << endl << j->dump(4) << endl;
	if (j->operator[]("msg") == "setup") {
		log->type(LOG_RACE);
		log->wr("I joined a new race.\n");
		recievedEndPacket = false;
		rIdx = 0;
		eIdx = 0;
		finished = false;
	} else if (j->operator[]("msg") == "joined") {
		string joinedName = j->operator[]("payload")["profile"]["username"];
		string dispName;
		try {
			dispName = j->operator[]("payload")["profile"]["displayName"];
		} catch (const exception& e) {
			dispName = "[None]";
		}
		log->type(LOG_RACE);
		if (joinedName == "bot") {
			log->wr("Bot user '");
			log->wrs(dispName);
			log->wrs("' joined the race.\n");
		} else {
			log->wr("Human user '");
			log->wrs(joinedName);
			log->wrs("' joined the race.\n");
		}
	} else if (j->operator[]("msg") == "status" && j->operator[]("payload")["status"] == "countdown") {
		lastRaceStart = time(0);
		log->type(LOG_RACE);
		log->wr("The race has started.\n");
		lesson = j->operator[]("payload")["l"];
		lessonLen = lesson.length();
		log->type(LOG_INFO);
		log->wr("Lesson length: ");
		log->operator<<(lessonLen);
		log->ln();
		this_thread::sleep_for(chrono::milliseconds(50));
		type(ws);
	} else if (j->operator[]("msg") == "update" &&
		j->operator[]("payload")["racers"][0] != nullptr &&
		j->operator[]("payload")["racers"][0]["r"] != nullptr) {
			// Race has finished for a client
			if (recievedEndPacket == false) {
				// Ensures its this client
				recievedEndPacket = true;
				handleRaceFinish(ws);
			}
	}
}
void NTClient::onMessage(WebSocket<CLIENT>* ws, char* msg, size_t len, OpCode opCode) {
	if (opCode != OpCode::TEXT) {
		cout << "The realtime server did not send a text packet for some reason, ignoring.\n";
		return;
	}
	string smsg = string(msg, len);
	if (smsg == "3probe") {
		// Response to initial connection probe
		ws->send("5", OpCode::TEXT);
		// Join packet
		this_thread::sleep_for(chrono::seconds(1));
		string joinTo = getJoinPacket(20); // 20 WPM just to test
		ws->send(joinTo.c_str(), OpCode::TEXT);
	} else if (smsg.length() > 2 && smsg[0] == '4' && smsg[1] == '{') {
		string rawJData = smsg.substr(1, smsg.length());
		json jdata;
		try {
			jdata = json::parse(rawJData);
		} catch (const exception& e) {
			// Some error parsing real race data, something must be wrong
			cout << "There was an issue parsing server data: " << e.what() << endl;
			return;
		}
		handleData(ws, &jdata);
	} else {
		cout << "Recieved unknown WebSocket message: '" << smsg << "'\n";
	}
}
void NTClient::onConnection(WebSocket<CLIENT>* wsocket, HttpRequest req) {
	// Send a probe, which is required for connection
	wsocket->send("2probe", OpCode::TEXT);
}
void NTClient::sendTypePacket(WebSocket<CLIENT>* ws, int idx, string typeType) {
	json p = {
		{"stream", "race"},
		{"msg", "update"},
		{"payload", {}}
	};
	p["payload"][typeType] = idx;
	string packet = "4" + p.dump();
	// cout << "Packet: " << packet << endl;
	ws->send(packet.c_str(), OpCode::TEXT);
}
void NTClient::type(WebSocket<CLIENT>* ws) {
	if (rIdx > lessonLen) {
		// All characters have been typed
		if (!finished) {
			handleRaceFinish(ws);
		}
		return;
	}
	int low = typeIntervalMS - 15;
	int high = typeIntervalMS + 15;
	bool isRight = Utils::randBool(accuracy);
	int sleepFor = Utils::randInt(low, high);
	if (low < 10) {
		low = Utils::randInt(9, 12);
	}
	if (rIdx % 25 == 0) { // Display info every 25 characters
		// Log race updated
		log->type(LOG_INFO);
		log->wr("I have finished ");
		log->operator<<((((double)rIdx) / ((double)lessonLen)) * 100.00);
		log->wrs("% of the race (");
		log->operator<<((int)rIdx);
		log->wrs(" / ");
		log->operator<<((int)lessonLen);
		log->wrs(" characters at ");
		log->operator<<((int)wpm);
		log->wrs(" WPM)");
		log->ln();
	}
	if (!isRight) {
		++eIdx;
		sendTypePacket(ws, eIdx, "e");
	}
	++rIdx;
	sendTypePacket(ws, rIdx, "t");
	// cout << "rIdx " << rIdx << ", eIdx: " << eIdx << ", isRight: " << isRight << ", sleepFor: " << sleepFor << endl;
	this_thread::sleep_for(chrono::milliseconds(sleepFor));
	type(ws); // Call the function until the lesson has been "typed"
}
void NTClient::handleRaceFinish(WebSocket<CLIENT>* ws) {
	finished = true;
	racesCompleted++;
	int raceCompleteTime = time(0) - lastRaceStart;
	rIdx = 0;
	eIdx = 0;
	log->type(LOG_RACE);
	log->wr("The race has finished.\n");
	log->type(LOG_INFO);
	log->wr("The race took ");
	log->operator<<(raceCompleteTime);
	log->wrs(" seconds to complete. Waiting 5 seconds before the next race.\n");
	log->type(LOG_RACE);
	log->wr("I have completed ");
	log->operator<<(racesCompleted);
	log->wrs(" race(s).\n");
	this_thread::sleep_for(chrono::seconds(5));
	log->type(LOG_CONN);
	log->wr("Closing WebSocket...\n");
	ws->close();
}<commit_msg>Properly handle all JSON parsing issues<commit_after>#include "NTClient.h"
using namespace std;

NTClient::NTClient(int _wpm, double _accuracy) {
	typeIntervalMS = 12000 / _wpm;
	wpm = _wpm;
	accuracy = _accuracy;
	firstConnect = true;
	connected = false;
	finished = false;
	lessonLen = 0;
	log = new NTLogger("(Not logged in)");
	wsh = nullptr;
	racesCompleted = 0;
	rIdx = 0;
	eIdx = 0;
}
NTClient::~NTClient() {
	if (log != nullptr) {
		delete log;
		log = nullptr;
	}
	if (wsh != nullptr) {
		delete wsh;
		wsh = nullptr;
	}
}
bool NTClient::login(string username, string password) {
	log->type(LOG_HTTP);
	log->wr("Logging into the NitroType account...\n");
	log->setUsername(username);
	uname = username;
	pword = password;
	bool ret = true;
	string data = string("username=");
	data += uname;
	data += "&password=";
	data += pword;
	data += "&adb=1&tz=America%2FChicago"; // No need to have anything other than Chicago timezone
	httplib::SSLClient loginReq(NITROTYPE_HOSTNAME, HTTPS_PORT);
	shared_ptr<httplib::Response> res = loginReq.post(NT_LOGIN_ENDPOINT, data, "application/x-www-form-urlencoded; charset=UTF-8");
	if (res) {
		bool foundLoginCookie = false;
		for (int i = 0; i < res->cookies.size(); ++i) {
			string cookie = res->cookies.at(i);
			addCookie(Utils::extractCKey(cookie), Utils::extractCValue(cookie));
			if (cookie.find("ntuserrem=") == 0) {
				foundLoginCookie = true;
				token = Utils::extractCValue(cookie);
				log->type(LOG_HTTP);
				log->wr("Resolved ntuserrem login token.\n");
				// addCookie("ntuserrem", token);
			}
		}
		if (!foundLoginCookie) {
			ret = false;
			log->type(LOG_HTTP);
			log->wr("Unable to locate the login cookie. Maybe try a different account?\n");
		}
	} else {
		ret = false;
		log->type(LOG_HTTP);
		log->wr("Login request failed. This might be a network issue. Maybe try resetting your internet connection?\n");
	}
	if (ret == false) {
		log->type(LOG_HTTP);
		log->wr("Failed to log in.\n");
	} else {
		bool success = getPrimusSID();
		if (!success) return false;
	}
	return ret;
}
bool NTClient::connect() {
	wsh = new Hub();
	time_t tnow = time(0);
	rawCookieStr = Utils::stringifyCookies(&cookies);
	stringstream uristream;
	uristream  << "wss://realtime1.nitrotype.com:443/realtime/?_primuscb=" << tnow << "-0&EIO=3&transport=websocket&sid=" << primusSid << "&t=" << tnow << "&b64=1";
	string wsURI = uristream.str();
	log->type(LOG_CONN);
	log->wr("Attempting to connect to the NitroType realtime server...\n");
	if (firstConnect) {
		addListeners();
	}
	// cout << "Cookies: " << rawCookieStr << endl << endl;
	// Create override headers
	customHeaders["Cookie"] = rawCookieStr;
	customHeaders["Origin"] = "https://www.nitrotype.com";
	customHeaders["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/55.0.2883.87 Chrome/55.0.2883.87 Safari/537.36";
	// customHeaders["Host"] = "realtime1.nitrotype.com";
	wsh->connect(wsURI, (void*)this, customHeaders, 7000);
	// wsh->connect(wsURI);
	if (firstConnect) {
		wsh->run();
		firstConnect = false;
	}
	return true;
}
void NTClient::addCookie(string key, string val) {
	SPair sp = SPair(key, val);
	cookies.push_back(sp);
}
bool NTClient::getPrimusSID() {
	time_t tnow = time(0);
	log->type(LOG_HTTP);
	log->wr("Resolving Primus SID...\n");
	rawCookieStr = Utils::stringifyCookies(&cookies);
	stringstream squery;
	squery << "?_primuscb=" << tnow << "-0&EIO=3&transport=polling&t=" << tnow << "-0&b64=1";
	string queryStr = squery.str();

	httplib::SSLClient loginReq(NT_REALTIME_HOST, HTTPS_PORT);
	string path = NT_PRIMUS_ENDPOINT + queryStr;
	shared_ptr<httplib::Response> res = loginReq.get(path.c_str(), rawCookieStr.c_str());
	if (res) {
		try {
			json jres = json::parse(res->body.substr(4, res->body.length()));
		} catch (const exception& e) {
			log->type(LOG_HTTP);
			log->wr("There was an issue parsing Primus polling info. Retrying.\n");
			return getPrimusSID();
		}
		primusSid = jres["sid"];
		log->type(LOG_HTTP);
		log->wr("Resolved Primus SID successfully.\n");
		// addCookie("io", primusSid);
	} else {
		cout << "Error retrieving primus handshake data.\n";
		return false;
	}
	return true;
}
string NTClient::getJoinPacket(int avgSpeed) {
	json p = {
		{"stream", "race"},
		{"msg", "join"},
		{"payload", {
			{"avgSpeed", avgSpeed},
			{"debugging", false},
			{"music", "standard"},
			{"track", "forest"},
			{"update", 3417}
		}}
	};
	return "4" + p.dump();
}
void NTClient::addListeners() {
	assert(wsh != nullptr);
	wsh->onError([this](void* udata) {
		log->type(LOG_CONN);
		log->wr("WebSocket connection error. Firing disconn event.\n");
		onDisconnection();
	});
	wsh->onConnection([this](WebSocket<CLIENT>* wsocket, HttpRequest req) {
		log->type(LOG_CONN);
		log->wr("Established a WebSocket connection with the realtime server.\n");
		onConnection(wsocket, req);
	});
	wsh->onDisconnection([this](WebSocket<CLIENT>* wsocket, int code, char* msg, size_t len) {
		log->type(LOG_CONN);
		log->wr("Disconnected from the realtime server.\n");
		onDisconnection();
	});
	wsh->onMessage([this](WebSocket<CLIENT>* ws, char* msg, size_t len, OpCode opCode) {
		onMessage(ws, msg, len, opCode);
	});
}
void NTClient::onDisconnection(void) {
	/*
	cout << "Disconn message: " << string(msg, len) << endl;
	cout << "Disconn code: " << code << endl;
	*/
	log->type(LOG_CONN);
	log->wr("Reconnecting to the realtime server...\n");
	getPrimusSID();
	rawCookieStr = Utils::stringifyCookies(&cookies);
	stringstream uristream;
	uristream  << "wss://realtime1.nitrotype.com:443/realtime/?_primuscb=" << time(0) << "-0&EIO=3&transport=websocket&sid=" << primusSid << "&t=" << time(0) << "&b64=1";
	string wsURI = uristream.str();
	wsh->connect(wsURI, (void*)this, customHeaders, 7000);
}
void NTClient::handleData(WebSocket<CLIENT>* ws, json* j) {
	// Uncomment to dump all raw JSON packets
	// cout << "Recieved json data:" << endl << j->dump(4) << endl;
	if (j->operator[]("msg") == "setup") {
		log->type(LOG_RACE);
		log->wr("I joined a new race.\n");
		recievedEndPacket = false;
		rIdx = 0;
		eIdx = 0;
		finished = false;
	} else if (j->operator[]("msg") == "joined") {
		string joinedName = j->operator[]("payload")["profile"]["username"];
		string dispName;
		try {
			dispName = j->operator[]("payload")["profile"]["displayName"];
		} catch (const exception& e) {
			dispName = "[None]";
		}
		log->type(LOG_RACE);
		if (joinedName == "bot") {
			log->wr("Bot user '");
			log->wrs(dispName);
			log->wrs("' joined the race.\n");
		} else {
			log->wr("Human user '");
			log->wrs(joinedName);
			log->wrs("' joined the race.\n");
		}
	} else if (j->operator[]("msg") == "status" && j->operator[]("payload")["status"] == "countdown") {
		lastRaceStart = time(0);
		log->type(LOG_RACE);
		log->wr("The race has started.\n");
		lesson = j->operator[]("payload")["l"];
		lessonLen = lesson.length();
		log->type(LOG_INFO);
		log->wr("Lesson length: ");
		log->operator<<(lessonLen);
		log->ln();
		this_thread::sleep_for(chrono::milliseconds(50));
		type(ws);
	} else if (j->operator[]("msg") == "update" &&
		j->operator[]("payload")["racers"][0] != nullptr &&
		j->operator[]("payload")["racers"][0]["r"] != nullptr) {
			// Race has finished for a client
			if (recievedEndPacket == false) {
				// Ensures its this client
				recievedEndPacket = true;
				handleRaceFinish(ws);
			}
	}
}
void NTClient::onMessage(WebSocket<CLIENT>* ws, char* msg, size_t len, OpCode opCode) {
	if (opCode != OpCode::TEXT) {
		cout << "The realtime server did not send a text packet for some reason, ignoring.\n";
		return;
	}
	string smsg = string(msg, len);
	if (smsg == "3probe") {
		// Response to initial connection probe
		ws->send("5", OpCode::TEXT);
		// Join packet
		this_thread::sleep_for(chrono::seconds(1));
		string joinTo = getJoinPacket(20); // 20 WPM just to test
		ws->send(joinTo.c_str(), OpCode::TEXT);
	} else if (smsg.length() > 2 && smsg[0] == '4' && smsg[1] == '{') {
		string rawJData = smsg.substr(1, smsg.length());
		json jdata;
		try {
			jdata = json::parse(rawJData);
		} catch (const exception& e) {
			// Some error parsing real race data, something must be wrong
			cout << "There was an issue parsing server data: " << e.what() << ", ignoring it." << endl;
			return;
		}
		handleData(ws, &jdata);
	} else {
		cout << "Recieved unknown WebSocket message: '" << smsg << "'\n";
	}
}
void NTClient::onConnection(WebSocket<CLIENT>* wsocket, HttpRequest req) {
	// Send a probe, which is required for connection
	wsocket->send("2probe", OpCode::TEXT);
}
void NTClient::sendTypePacket(WebSocket<CLIENT>* ws, int idx, string typeType) {
	json p = {
		{"stream", "race"},
		{"msg", "update"},
		{"payload", {}}
	};
	p["payload"][typeType] = idx;
	string packet = "4" + p.dump();
	// cout << "Packet: " << packet << endl;
	ws->send(packet.c_str(), OpCode::TEXT);
}
void NTClient::type(WebSocket<CLIENT>* ws) {
	if (rIdx > lessonLen) {
		// All characters have been typed
		if (!finished) {
			handleRaceFinish(ws);
		}
		return;
	}
	int low = typeIntervalMS - 15;
	int high = typeIntervalMS + 15;
	bool isRight = Utils::randBool(accuracy);
	int sleepFor = Utils::randInt(low, high);
	if (low < 10) {
		low = Utils::randInt(9, 12);
	}
	if (rIdx % 25 == 0) { // Display info every 25 characters
		// Log race updated
		log->type(LOG_INFO);
		log->wr("I have finished ");
		log->operator<<((((double)rIdx) / ((double)lessonLen)) * 100.00);
		log->wrs("% of the race (");
		log->operator<<((int)rIdx);
		log->wrs(" / ");
		log->operator<<((int)lessonLen);
		log->wrs(" characters at ");
		log->operator<<((int)wpm);
		log->wrs(" WPM)");
		log->ln();
	}
	if (!isRight) {
		++eIdx;
		sendTypePacket(ws, eIdx, "e");
	}
	++rIdx;
	sendTypePacket(ws, rIdx, "t");
	// cout << "rIdx " << rIdx << ", eIdx: " << eIdx << ", isRight: " << isRight << ", sleepFor: " << sleepFor << endl;
	this_thread::sleep_for(chrono::milliseconds(sleepFor));
	type(ws); // Call the function until the lesson has been "typed"
}
void NTClient::handleRaceFinish(WebSocket<CLIENT>* ws) {
	finished = true;
	racesCompleted++;
	int raceCompleteTime = time(0) - lastRaceStart;
	rIdx = 0;
	eIdx = 0;
	log->type(LOG_RACE);
	log->wr("The race has finished.\n");
	log->type(LOG_INFO);
	log->wr("The race took ");
	log->operator<<(raceCompleteTime);
	log->wrs(" seconds to complete. Waiting 5 seconds before the next race.\n");
	log->type(LOG_RACE);
	log->wr("I have completed ");
	log->operator<<(racesCompleted);
	log->wrs(" race(s).\n");
	this_thread::sleep_for(chrono::seconds(5));
	log->type(LOG_CONN);
	log->wr("Closing WebSocket...\n");
	ws->close();
}<|endoftext|>


<commit_before>/*
  Copyright (c) 2012 Stuart Walsh

  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.
*/

#include <fnmatch.h>

#include "stdinc.h"
#include "nuhmask.h"

NuhMask::NuhMask()
{
  Logging::trace << "Created NuhMask: " << this << Logging::endl;
}

NuhMask::NuhMask(const string& mask)
{
  parse_mask(mask);
}

NuhMask::~NuhMask()
{
  Logging::trace << "Destroyed NuhMask: " << this << Logging::endl;
}

void NuhMask::parse_mask(const string& mask)
{
  full_mask = mask;
  size_t pos, last;

  last = pos = mask.find_first_of('!');
  if(pos == string::npos || pos == 0)
    name = "*";
  else
    name = mask.substr(0, pos).c_str();

  if(last == string::npos)
    last = 0;
  else
    last++;

  pos = mask.find_first_of('@', last);
  if(pos == string::npos || pos == last)
    username = "*";
  else
    username = mask.substr(last, pos - last).c_str();

  last = pos;
  if(last == string::npos)
    last = 0;
  else
    last++;

  host = mask.substr(last, pos - last);
  if(host.empty())
    host = "*";
}

string NuhMask::str() const
{
  stringstream ss;

  ss << name << "!" << username << "@" << host;

  return ss.str();
}

bool NuhMask::match(const NuhMask& right)
{
  std::string spat(this->str());
  std::transform(spat.begin(), spat.end(), spat.begin(), to_upper);
  const char *pat = spat.c_str();

  std::string sdet(right.str());
  std::transform(sdet.begin(), sdet.end(), sdet.begin(), to_upper);
  const char *det = sdet.c_str();

  int ret = fnmatch(pat, det, FNM_NOESCAPE | FNM_CASEFOLD);
  bool ismatch = ret == 0 ? true : false;

  Logging::debug << "NuhMask " << det << " ";

  if(ismatch)
    Logging::debug << "Matched";
  else
    Logging::debug << "No Match";

  Logging::debug << " " << pat << Logging::endl;

  return ismatch;
}

bool NuhMask::match(const ClientPtr right)
{
  NuhMask r(right->str().c_str());
  return this->match(r);
}
<commit_msg>win32ify nuhmask::match<commit_after>/*
  Copyright (c) 2012 Stuart Walsh

  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.
*/

#include "stdinc.h"
#include "nuhmask.h"
#ifndef _WIN32
#include <fnmatch.h>
#else
#include <shlwapi.h>
#pragma comment(lib,"shlwapi.lib");
#endif

NuhMask::NuhMask()
{
  Logging::trace << "Created NuhMask: " << this << Logging::endl;
}

NuhMask::NuhMask(const string& mask)
{
  parse_mask(mask);
}

NuhMask::~NuhMask()
{
  Logging::trace << "Destroyed NuhMask: " << this << Logging::endl;
}

void NuhMask::parse_mask(const string& mask)
{
  full_mask = mask;
  size_t pos, last;

  last = pos = mask.find_first_of('!');
  if(pos == string::npos || pos == 0)
    name = "*";
  else
    name = mask.substr(0, pos).c_str();

  if(last == string::npos)
    last = 0;
  else
    last++;

  pos = mask.find_first_of('@', last);
  if(pos == string::npos || pos == last)
    username = "*";
  else
    username = mask.substr(last, pos - last).c_str();

  last = pos;
  if(last == string::npos)
    last = 0;
  else
    last++;

  host = mask.substr(last, pos - last);
  if(host.empty())
    host = "*";
}

string NuhMask::str() const
{
  stringstream ss;

  ss << name << "!" << username << "@" << host;

  return ss.str();
}

bool NuhMask::match(const NuhMask& right)
{
  std::string spat(this->str());
  std::transform(spat.begin(), spat.end(), spat.begin(), to_upper);
  const char *pat = spat.c_str();

  std::string sdet(right.str());
  std::transform(sdet.begin(), sdet.end(), sdet.begin(), to_upper);
  const char *det = sdet.c_str();

#ifndef _WIN32
  int ret = fnmatch(pat, det, FNM_NOESCAPE | FNM_CASEFOLD);
#else
  int ret = !PathMatchSpec(det, pat);
#endif
  bool ismatch = ret == 0 ? true : false;

  Logging::debug << "NuhMask " << det << " ";

  if(ismatch)
    Logging::debug << "Matched";
  else
    Logging::debug << "No Match";

  Logging::debug << " " << pat << Logging::endl;

  return ismatch;
}

bool NuhMask::match(const ClientPtr right)
{
  NuhMask r(right->str().c_str());
  return this->match(r);
}
<|endoftext|>


<commit_before>//
// Created by Malachi Burke on 11/12/17.
//

#include <catch.hpp>

#include "../mc/pipeline.h"

using namespace moducom::pipeline;
using namespace moducom::pipeline::experimental;
using namespace moducom::pipeline::layer3;
using namespace moducom::pipeline::layer3::experimental;

TEST_CASE("Pipeline basic tests", "[pipeline]")
{
    SECTION("1")
    {
        MemoryChunk chunk;
        SimpleBufferedPipeline p(chunk);
    }
    SECTION("experimental")
    {
        uint8_t buffer[128];
        MemoryChunk _chunk(buffer, 128);
        BufferProviderPipeline p(_chunk);
        MemoryChunk* chunk = NULLPTR;

        if(p.get_buffer(&chunk))
        {
            sprintf((char*)chunk->data, "Hello World");

            PipelineMessage::CopiedStatus copied_status;

            MemoryChunk chunk2 = p.advance(100, copied_status);
        }
    }
}<commit_msg>Experimental pseudo code<commit_after>//
// Created by Malachi Burke on 11/12/17.
//

#include <catch.hpp>

#include "../mc/pipeline.h"

using namespace moducom::pipeline;
using namespace moducom::pipeline::experimental;
using namespace moducom::pipeline::layer3;
using namespace moducom::pipeline::layer3::experimental;

TEST_CASE("Pipeline basic tests", "[pipeline]")
{
    SECTION("1")
    {
        MemoryChunk chunk;
        SimpleBufferedPipeline p(chunk);
    }
    SECTION("experimental")
    {
        uint8_t buffer[128];
        MemoryChunk _chunk(buffer, 128);
        BufferProviderPipeline p(_chunk);
        MemoryChunk* chunk = NULLPTR;

        if(p.get_buffer(&chunk))
        {
            sprintf((char*)chunk->data, "Hello World");

            PipelineMessage::CopiedStatus copied_status;

            MemoryChunk chunk2 = p.advance(100, copied_status);
        }

#ifdef IDEALIZED
        PipelineType p;
        PipelineMessageWrapper<default_boundary_number> msg;

        size_t len = sprintf(msg, "Hello");

        // bump forward and notify interested parties
        msg.advance(len, boundary_number);

        // this should auto advance
        msg << "Hello Again" << endl;

        msg.boundary();

#endif
    }
}<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ZipEnumeration.cxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 16:15:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _ZIP_ENUMERATION_HXX
#include <ZipEnumeration.hxx>
#endif

/** Provides an Enumeration over the contents of a Zip file */

ZipEnumeration::ZipEnumeration( EntryHash & rNewEntryHash)
: rEntryHash(rNewEntryHash)
, aIterator(rEntryHash.begin())
{
}
ZipEnumeration::~ZipEnumeration( void )
{
}
sal_Bool SAL_CALL ZipEnumeration::hasMoreElements()
{
    return (aIterator != rEntryHash.end());
}

const ZipEntry* SAL_CALL ZipEnumeration::nextElement()
{
    if (aIterator != rEntryHash.end())
        return &((*aIterator++).second);
    else
        return NULL;
}
<commit_msg>INTEGRATION: CWS pchfix02 (1.12.44); FILE MERGED 2006/09/01 17:32:42 kaib 1.12.44.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ZipEnumeration.cxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 17:28:02 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_package.hxx"
#ifndef _ZIP_ENUMERATION_HXX
#include <ZipEnumeration.hxx>
#endif

/** Provides an Enumeration over the contents of a Zip file */

ZipEnumeration::ZipEnumeration( EntryHash & rNewEntryHash)
: rEntryHash(rNewEntryHash)
, aIterator(rEntryHash.begin())
{
}
ZipEnumeration::~ZipEnumeration( void )
{
}
sal_Bool SAL_CALL ZipEnumeration::hasMoreElements()
{
    return (aIterator != rEntryHash.end());
}

const ZipEntry* SAL_CALL ZipEnumeration::nextElement()
{
    if (aIterator != rEntryHash.end())
        return &((*aIterator++).second);
    else
        return NULL;
}
<|endoftext|>


<commit_before>/**
 *  ofxCsv.cpp
 *  Inspired and based on Ben Fry's [table class](http://benfry.com/writing/map/Table.pde)
 *
 *
 *  The MIT License
 *
 *  Copyright (c) 2011-2012 Paul Vollmer, http://www.wng.cc
 *
 *  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.
 *
 *
 *  @testet_oF          0.07
 *  @testet_plattform   MacOs 10.6
 *                      ??? Win
 *                      ??? Linux
 *  @dependencies
 *  @modified           2012.05.06
 *  @version            0.1.2b
 */

#include "ofxCsv.h"

namespace wng {

	/**
	 * A Constructor, usually called to initialize and start the class.
	 */
	ofxCsv::ofxCsv(){
	}

	/**
	 * Load a CSV File.
	 *
	 * @param path
	 *        Set the File path.
	 * @param separator
	 *        Set the Separator to split CSV File.
	 * @param comments
	 *        Set the Comments sign.
	 */
	void ofxCsv::loadFile(string path, string separator, string comments){

		// Save Filepath, Separator and Comments to variables.
		filePath = path;
		fileSeparator = separator;
		fileComments = comments;
		#ifdef OFXCSV_LOG
			ofLog() << "[ofxCsv] loadFile";
			ofLog() << "         filePath: " << filePath;
			ofLog() << "         fileSeparator: " << fileSeparator;
			ofLog() << "         fileComments: " << fileComments;
		#endif

		// Declare a File Stream.
		ifstream fileIn;

		// Open your text File:
		fileIn.open(path.c_str());

		// Check if File is open.
		if(fileIn.is_open()) {
			int lineCount = 0;
			vector<string> rows;

			while(fileIn != NULL) {
				string temp;
				getline(fileIn, temp);

				// Skip empty lines.
				if(temp.length() == 0) {
					//cout << "Skip empty line no: " << lineCount << endl;
				}
				// Skip Comment lines.
				else if(ofToString(temp[0]) == comments) {
					//cout << "Skip Comment line no: " << lineCount << endl;
				} else {
					rows.push_back(temp);

					// Split row into cols.
					vector<string> cols = ofSplitString(rows[lineCount], ",");

					// Write the string to data.
					data.push_back(cols);

					// Erase remaining elements.
					cols.erase(cols.begin(), cols.end());
					//cout << "cols: After erasing all elements, vector integers " << (cols.empty() ? "is" : "is not" ) << " empty" << endl;

					lineCount++;
				}
			}

			// Save the Number of Rows.
			numRows = rows.size();

			// Erase remaining elements.
			rows.erase(rows.begin(), rows.end());
			//cout << "rows: After erasing all elements, vector integers " << (rows.empty() ? "is" : "is not" ) << " empty" << endl;

			// If File cannot opening, print a message to console.
		} else {
			cerr << "[ofxCsv] Error opening " << path << ".\n";
		}

	}

	/**
	 * Load a CSV File.
	 * The default Comment sign is "#".
	 *
	 * @param path
	 *        Set the file path.
	 * @param separator
	 *        Set the Separator to split CSV file.
	 */
	void ofxCsv::loadFile(string path, string separator){

		loadFile(path, separator, "#");

	}

	/**
	 * Load a CSV File.
	 * The default Separator is ",".
	 * The default Comment sign is "#".
	 *
	 * @param path
	 *        Set the file path.
	 */
	void ofxCsv::loadFile(string path){

		loadFile(path, ",", "#");

	}

	/**
	 * saveFile
	 *
	 * @param path
	 *        Set the file path.
	 * @param separator
	 *        Set the Separator to split CSV file.
	 * @param comments
	 *        Set the Comments sign.
	 */
	void ofxCsv::saveFile(string path, string separator, string comments){

		createFile(path);

		ofstream myfile;
		myfile.open(path.c_str());
		if(myfile.is_open()){
			// Write data to file.
			for(int i=0; i<numRows; i++){
				for(int j=0; j<data[i].size(); j++){
					myfile << data[i][j] << separator;
					if(j==(data[i].size()-1)){
						myfile << "\n";
					}
				}
			}
			myfile.close();
			//cout << "Open file" << endl;
		} else {
			//cout << "Unable to open file" << endl;
		}

	}

	/**
	 * saveFile
	 *
	 * @param path
	 *        Set the file path.
	 * @param separator
	 *        Set the Separator to split Csv file.
	 */
	void ofxCsv::saveFile(string path, string separator) {

		//createFile(path);
		saveFile(path, separator, fileComments);

	}

	/**
	 * saveFile
	 *
	 * @param path
	 *        Set the file path.
	 */
	void ofxCsv::saveFile(string path) {

		//createFile(path);
		saveFile(path, fileSeparator, fileComments);

	}

	/**
	 * Save file.
	 */
	void ofxCsv::saveFile() {

		saveFile(filePath, fileSeparator, fileComments);

	}

	/**
	 * createFile
	 *
	 * @param path
	 *        Set the File Path.
	 */
	void ofxCsv::createFile(string path){

		FILE * pFile;
		pFile = fopen (path.c_str(),"w");

		if (pFile!=NULL) {
			//fputs ("fopen example",pFile);
			fclose (pFile);
		}

	}

	/**
	 * loadFromString
	 *
	 * @param s
	 *        String Input.
	 * @param separator
	 *        Set the Separator to split CSV string.
	 */
	vector<string> ofxCsv::getFromString(string csv, string separator){

		vector<string> cols = ofSplitString(csv, separator);
		return cols;

	}

	/**
	 * loadFromString
	 *
	 * @param s
	 *        String Input.
	 */
	vector<string> ofxCsv::getFromString(string csv){

		getFromString(csv, ",");

	}

	/**
	 * Get the Integer of a specific row and column.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @return integer
	 */
	int ofxCsv::getInt(int row, int col){
		return ofToInt(data[row][col]);//temp;
	}

	/**
	 * Get the Float of a specific row and column.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @return float
	 */
	float ofxCsv::getFloat(int row, int col){

		return ofToFloat(data[row][col]);//temp;

	}

	/**
	 * Get the String of a specific row and column.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @return float
	 */
	string ofxCsv::getString(int row, int col){

		return data[row][col];

	}

	/**
	 * Get the Boolean of a specific row and column.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @return bool
	 */
	bool ofxCsv::getBool(int row, int col){

		return ofToBool(data[row][col]);

	}

	/**
	 * Set a specific Integer to a new value.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @param what
	 *        new Integer
	 */
	void ofxCsv::setInt(int row, int col, int what){

		data[row][col] = ofToString(what);

	}

	/**
	 * Set a specific Float to a new value.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @param what
	 *        new row Float
	 */
	void ofxCsv::setFloat(int row, int col, float what){

		data[row][col] = ofToString(what);

	}

	/**
	 * Set a specific String to a new value.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @param what
	 *        new row String
	 */
	void ofxCsv::setString(int row, int col, string what){

		data[row][col] = ofToString(what);

	}

	/**
	 * setBool
	 * set a specific Boolean to a new value.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @param what
	 *        new row Boolean
	 */
	void ofxCsv::setBool(int row, int col, bool what){

		data[row][col] = ofToString(what);

	}

}
<commit_msg>Added missing return statement<commit_after>/**
 *  ofxCsv.cpp
 *  Inspired and based on Ben Fry's [table class](http://benfry.com/writing/map/Table.pde)
 *
 *
 *  The MIT License
 *
 *  Copyright (c) 2011-2012 Paul Vollmer, http://www.wng.cc
 *
 *  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.
 *
 *
 *  @testet_oF          0.07
 *  @testet_plattform   MacOs 10.6
 *                      ??? Win
 *                      ??? Linux
 *  @dependencies
 *  @modified           2012.05.06
 *  @version            0.1.2b
 */

#include "ofxCsv.h"

namespace wng {

	/**
	 * A Constructor, usually called to initialize and start the class.
	 */
	ofxCsv::ofxCsv(){
	}

	/**
	 * Load a CSV File.
	 *
	 * @param path
	 *        Set the File path.
	 * @param separator
	 *        Set the Separator to split CSV File.
	 * @param comments
	 *        Set the Comments sign.
	 */
	void ofxCsv::loadFile(string path, string separator, string comments){

		// Save Filepath, Separator and Comments to variables.
		filePath = path;
		fileSeparator = separator;
		fileComments = comments;
		#ifdef OFXCSV_LOG
			ofLog() << "[ofxCsv] loadFile";
			ofLog() << "         filePath: " << filePath;
			ofLog() << "         fileSeparator: " << fileSeparator;
			ofLog() << "         fileComments: " << fileComments;
		#endif

		// Declare a File Stream.
		ifstream fileIn;

		// Open your text File:
		fileIn.open(path.c_str());

		// Check if File is open.
		if(fileIn.is_open()) {
			int lineCount = 0;
			vector<string> rows;

			while(fileIn != NULL) {
				string temp;
				getline(fileIn, temp);

				// Skip empty lines.
				if(temp.length() == 0) {
					//cout << "Skip empty line no: " << lineCount << endl;
				}
				// Skip Comment lines.
				else if(ofToString(temp[0]) == comments) {
					//cout << "Skip Comment line no: " << lineCount << endl;
				} else {
					rows.push_back(temp);

					// Split row into cols.
					vector<string> cols = ofSplitString(rows[lineCount], ",");

					// Write the string to data.
					data.push_back(cols);

					// Erase remaining elements.
					cols.erase(cols.begin(), cols.end());
					//cout << "cols: After erasing all elements, vector integers " << (cols.empty() ? "is" : "is not" ) << " empty" << endl;

					lineCount++;
				}
			}

			// Save the Number of Rows.
			numRows = rows.size();

			// Erase remaining elements.
			rows.erase(rows.begin(), rows.end());
			//cout << "rows: After erasing all elements, vector integers " << (rows.empty() ? "is" : "is not" ) << " empty" << endl;

			// If File cannot opening, print a message to console.
		} else {
			cerr << "[ofxCsv] Error opening " << path << ".\n";
		}

	}

	/**
	 * Load a CSV File.
	 * The default Comment sign is "#".
	 *
	 * @param path
	 *        Set the file path.
	 * @param separator
	 *        Set the Separator to split CSV file.
	 */
	void ofxCsv::loadFile(string path, string separator){

		loadFile(path, separator, "#");

	}

	/**
	 * Load a CSV File.
	 * The default Separator is ",".
	 * The default Comment sign is "#".
	 *
	 * @param path
	 *        Set the file path.
	 */
	void ofxCsv::loadFile(string path){

		loadFile(path, ",", "#");

	}

	/**
	 * saveFile
	 *
	 * @param path
	 *        Set the file path.
	 * @param separator
	 *        Set the Separator to split CSV file.
	 * @param comments
	 *        Set the Comments sign.
	 */
	void ofxCsv::saveFile(string path, string separator, string comments){

		createFile(path);

		ofstream myfile;
		myfile.open(path.c_str());
		if(myfile.is_open()){
			// Write data to file.
			for(int i=0; i<numRows; i++){
				for(int j=0; j<data[i].size(); j++){
					myfile << data[i][j] << separator;
					if(j==(data[i].size()-1)){
						myfile << "\n";
					}
				}
			}
			myfile.close();
			//cout << "Open file" << endl;
		} else {
			//cout << "Unable to open file" << endl;
		}

	}

	/**
	 * saveFile
	 *
	 * @param path
	 *        Set the file path.
	 * @param separator
	 *        Set the Separator to split Csv file.
	 */
	void ofxCsv::saveFile(string path, string separator) {

		//createFile(path);
		saveFile(path, separator, fileComments);

	}

	/**
	 * saveFile
	 *
	 * @param path
	 *        Set the file path.
	 */
	void ofxCsv::saveFile(string path) {

		//createFile(path);
		saveFile(path, fileSeparator, fileComments);

	}

	/**
	 * Save file.
	 */
	void ofxCsv::saveFile() {

		saveFile(filePath, fileSeparator, fileComments);

	}

	/**
	 * createFile
	 *
	 * @param path
	 *        Set the File Path.
	 */
	void ofxCsv::createFile(string path){

		FILE * pFile;
		pFile = fopen (path.c_str(),"w");

		if (pFile!=NULL) {
			//fputs ("fopen example",pFile);
			fclose (pFile);
		}

	}

	/**
	 * loadFromString
	 *
	 * @param s
	 *        String Input.
	 * @param separator
	 *        Set the Separator to split CSV string.
	 */
	vector<string> ofxCsv::getFromString(string csv, string separator){

		vector<string> cols = ofSplitString(csv, separator);
		return cols;

	}

	/**
	 * loadFromString
	 *
	 * @param s
	 *        String Input.
	 */
	vector<string> ofxCsv::getFromString(string csv){

		return getFromString(csv, ",");

	}

	/**
	 * Get the Integer of a specific row and column.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @return integer
	 */
	int ofxCsv::getInt(int row, int col){
		return ofToInt(data[row][col]);//temp;
	}

	/**
	 * Get the Float of a specific row and column.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @return float
	 */
	float ofxCsv::getFloat(int row, int col){

		return ofToFloat(data[row][col]);//temp;

	}

	/**
	 * Get the String of a specific row and column.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @return float
	 */
	string ofxCsv::getString(int row, int col){

		return data[row][col];

	}

	/**
	 * Get the Boolean of a specific row and column.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @return bool
	 */
	bool ofxCsv::getBool(int row, int col){

		return ofToBool(data[row][col]);

	}

	/**
	 * Set a specific Integer to a new value.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @param what
	 *        new Integer
	 */
	void ofxCsv::setInt(int row, int col, int what){

		data[row][col] = ofToString(what);

	}

	/**
	 * Set a specific Float to a new value.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @param what
	 *        new row Float
	 */
	void ofxCsv::setFloat(int row, int col, float what){

		data[row][col] = ofToString(what);

	}

	/**
	 * Set a specific String to a new value.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @param what
	 *        new row String
	 */
	void ofxCsv::setString(int row, int col, string what){

		data[row][col] = ofToString(what);

	}

	/**
	 * setBool
	 * set a specific Boolean to a new value.
	 *
	 * @param row
	 *        row number
	 * @param col
	 *        column number
	 * @param what
	 *        new row Boolean
	 */
	void ofxCsv::setBool(int row, int col, bool what){

		data[row][col] = ofToString(what);

	}

}
<|endoftext|>


<commit_before>#include "../utils/parameter_parser.h"
#include "gtest/gtest.h"
#include <tuple>

TEST(ParserTest,StreamerParserSuccess) {
  int size;
  const char *file;
  bool valid = false;
  const char *testArguments[] = {"../sim_datastreamer", "-s", "42", "path/to/file/file"};
  int argc = 4;

  std::tie(file,size,std::ignore, std::ignore,valid) = taylortrack::utils::ParameterParser::parse_streamer(argc,testArguments);
  ASSERT_TRUE(valid);
  ASSERT_EQ(size,42);
  ASSERT_EQ(file,"path/to/file/file");
}

TEST(ParserTest,StramerParserNoLenght) {
  int size, argc = 2;
  const char *file;
  bool valid;
  const char *testArguments[] = {"../sim_datastreamer","path/to/file/file"};
  std::tie(file,size,std::ignore, std::ignore,valid) = taylortrack::utils::ParameterParser::parse_streamer(argc,testArguments);
  ASSERT_TRUE(valid);
  ASSERT_EQ(size,0);
  ASSERT_EQ(file,"path/to/file/file");
}

TEST(ParserTest, InvalidParameter) {
  int size, argc = 2;
  const char *file;
  bool valid;
  const char *testArguments[] = {"./sim_datastreamer","-s"};
  std::tie(std::ignore,std::ignore,std::ignore, std::ignore,valid) = taylortrack::utils::ParameterParser::parse_streamer(argc,testArguments);
  ASSERT_FALSE(valid);
}

TEST(ParserTest, InvalidParameterName) {
  int argc = 2;
  const char *testArguments[] = {"./sim_datastreamer","-"};
  bool valid=false;
  std::tie(std::ignore,std::ignore,std::ignore, std::ignore,valid) = taylortrack::utils::ParameterParser::parse_streamer(argc,testArguments);
  ASSERT_FALSE(valid);
}

/*TEST(ParserTest, InvalidParameterName) {
  int argc = 2;
  const char *testArguments[] = {"./sim_datastreamer","-"};
  bool valid=false;
  std::tie(std::ignore,std::ignore,std::ignore, std::ignore,valid) = taylortrack::utils::ParameterParser::parse_streamer(argc,testArguments);
  ASSERT_FALSE(valid);
}*/<commit_msg>expanded parameter parser tests<commit_after>#include "../utils/parameter_parser.h"
#include "gtest/gtest.h"
#include <tuple>

TEST(ParserTest,StreamerParserSuccess) {
  int size;
  const char *file;
  bool valid = false;
  const char *testArguments[] = {"../sim_datastreamer", "-s", "42", "path/to/file/file"};
  int argc = 4;

  std::tie(file,size,std::ignore, std::ignore,valid) = taylortrack::utils::ParameterParser::parse_streamer(argc,testArguments);
  ASSERT_TRUE(valid);
  ASSERT_EQ(size,42);
  ASSERT_EQ(file,"path/to/file/file");
}

TEST(ParserTest,SetOutportTest) {
  const char *testArguments[] = {"../sim_datastreamer", "-o", "/taylortest", "path/to/file/file"};
  int argc = 4;
  bool valid = false;
  const char* outport;
  const char *file;

  std::tie(file,std::ignore,outport, std::ignore,valid) = taylortrack::utils::ParameterParser::parse_streamer(argc,testArguments);
  ASSERT_TRUE(valid);
  ASSERT_EQ(outport, "/taylortest");
  ASSERT_EQ(file,"path/to/file/file");
}

TEST(ParserTest,SetInportTest) {
  const char *testArguments[] = {"../sim_datastreamer", "-i", "/taylortest", "path/to/file/file"};
  int argc = 4;
  bool valid = false;
  const char* inport;
  const char *file;

  std::tie(file,std::ignore,std::ignore, inport,valid) = taylortrack::utils::ParameterParser::parse_streamer(argc,testArguments);
  ASSERT_TRUE(valid);
  ASSERT_EQ(inport, "/taylortest");
  ASSERT_EQ(file,"path/to/file/file");
}

TEST(ParserTest,StramerParserNoLenght) {
  int size, argc = 2;
  const char *file;
  bool valid;
  const char *testArguments[] = {"../sim_datastreamer","path/to/file/file"};
  std::tie(file,size,std::ignore, std::ignore,valid) = taylortrack::utils::ParameterParser::parse_streamer(argc,testArguments);
  ASSERT_TRUE(valid);
  ASSERT_EQ(size,0);
  ASSERT_EQ(file,"path/to/file/file");
}

TEST(ParserTest, InvalidParameter) {
  int size, argc = 2;
  const char *file;
  bool valid;
  const char *testArguments[] = {"./sim_datastreamer","-s"};
  std::tie(std::ignore,std::ignore,std::ignore, std::ignore,valid) = taylortrack::utils::ParameterParser::parse_streamer(argc,testArguments);
  ASSERT_FALSE(valid);
}

TEST(ParserTest, InvalidParameterOutport) {
  int size, argc = 2;
  const char *file;
  bool valid;
  const char *testArguments[] = {"./sim_datastreamer","-o"};
  std::tie(std::ignore,std::ignore,std::ignore, std::ignore,valid) = taylortrack::utils::ParameterParser::parse_streamer(argc,testArguments);
  ASSERT_FALSE(valid);
}

TEST(ParserTest, InvalidParameterInport) {
  int size, argc = 2;
  const char *file;
  bool valid;
  const char *testArguments[] = {"./sim_datastreamer","-i"};
  std::tie(std::ignore,std::ignore,std::ignore, std::ignore,valid) = taylortrack::utils::ParameterParser::parse_streamer(argc,testArguments);
  ASSERT_FALSE(valid);
}

TEST(ParserTest, InvalidParameterName) {
  int argc = 2;
  const char *testArguments[] = {"./sim_datastreamer","-"};
  bool valid=false;
  std::tie(std::ignore,std::ignore,std::ignore, std::ignore,valid) = taylortrack::utils::ParameterParser::parse_streamer(argc,testArguments);
  ASSERT_FALSE(valid);
}

/*TEST(ParserTest, InvalidParameterName) {
  int argc = 2;
  const char *testArguments[] = {"./sim_datastreamer","-"};
  bool valid=false;
  std::tie(std::ignore,std::ignore,std::ignore, std::ignore,valid) = taylortrack::utils::ParameterParser::parse_streamer(argc,testArguments);
  ASSERT_FALSE(valid);
}*/<|endoftext|>


<commit_before>#include <blackhole/macro.hpp>

#include "global.hpp"
#include "mocks/logger.hpp"

using namespace blackhole;

TEST(Macro, OpensInvalidLogRecordAndNotPush) {
    log::record_t record;
    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));
    EXPECT_CALL(log, push(_))
            .Times(0);
    BH_LOG(log, level::debug, "message");
}

struct ExtractMessageAttributeAction {
    std::string& actual;

    void operator ()(log::record_t record) const {
        actual = record.extract<std::string>("message");
    }
};

TEST(Macro, OpensValidRecordAndPush) {
    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    std::string actual;
    ExtractMessageAttributeAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));
    BH_LOG(log, level::debug, "value");

    EXPECT_EQ("value", actual);
}

TEST(Macro, FormatMessageWithPrintfStyle) {
    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    std::string actual;
    ExtractMessageAttributeAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));

    BH_LOG(log, level::debug, "value [%d]: %s - okay", 100500, "blah");
    EXPECT_EQ("value [100500]: blah - okay", actual);
}

struct ExtractAttributesAction {
    struct pack_t {
        std::string message;
        int value;
        std::string reason;
        timeval timestamp;
    };

    pack_t& actual;

    void operator ()(log::record_t record) const {
        actual.message = record.extract<std::string>("message");
        actual.value = record.extract<int>("value");
        actual.reason = record.extract<std::string>("reason");
        actual.timestamp = record.extract<timeval>("timestamp");
    }
};

TEST(Macro, FormatMessageWithAttributes) {
    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    ExtractAttributesAction::pack_t actual;
    ExtractAttributesAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));

    BH_LOG(log, level::debug, "message")(
        attribute::make("value", 42),
        attribute::make("reason", "42"),
        keyword::timestamp() = timeval{ 100500, 0 }
    );

    EXPECT_EQ("message", actual.message);
    EXPECT_EQ(42, actual.value);
    EXPECT_EQ("42", actual.reason);
    EXPECT_EQ(100500, actual.timestamp.tv_sec);
}

TEST(Macro, FormatMessageWithPrintfStyleWithAttributes) {
    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    ExtractAttributesAction::pack_t actual;
    ExtractAttributesAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));

    BH_LOG(log, level::debug, "value [%d]: %s - okay", 100500, "blah")(
        attribute::make("value", 42),
        attribute::make("reason", "42"),
        keyword::timestamp() = timeval{ 100500, 0 }
    );

    EXPECT_EQ("value [100500]: blah - okay", actual.message);
    EXPECT_EQ(42, actual.value);
    EXPECT_EQ("42", actual.reason);
    EXPECT_EQ(100500, actual.timestamp.tv_sec);
}

namespace blackhole {

namespace format {

namespace message {

template<>
struct insitu<keyword::tag::severity_t<level>> {
    static inline std::ostream& execute(std::ostream& stream, level lvl) {
        static std::string DESCRIPTIONS[] = {
            "DEBUG",
            "INFO ",
            "WARN ",
            "ERROR"
        };

        std::size_t lvl_ = static_cast<std::size_t>(lvl);
        if (lvl_ < sizeof(DESCRIPTIONS) / sizeof(DESCRIPTIONS[0])) {
            stream << DESCRIPTIONS[lvl_];
        } else {
            stream << lvl_;
        }

        return stream;
    }
};

} // namespace message

} // namespace format

} // namespace blackhole

TEST(Macro, SpecificKeywordMessageFormatting) {
    log::record_t record;
    record.insert(keyword::severity<level>() = level::debug);

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    std::string actual;
    ExtractMessageAttributeAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));
    BH_LOG(log, level::debug, "value: %s", keyword::severity<level>());

    EXPECT_EQ("value: DEBUG", actual);
}

struct EmplaceCheckExtractAttributesAction {
    struct pack_t {
        std::string message;
        int value;
        std::string reason;
    };

    pack_t& actual;

    void operator ()(log::record_t record) const {
        actual.message = record.extract<std::string>("message");
        actual.value = record.extract<int>("value");
        actual.reason = record.extract<std::string>("reason");
    }
};

TEST(Macro, EmplaceAttributes) {
    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    EmplaceCheckExtractAttributesAction::pack_t actual;
    EmplaceCheckExtractAttributesAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));

    BH_LOG(log, level::debug, "message")(
        "value", 42,
        "reason", "42"
    );

    EXPECT_EQ("message", actual.message);
    EXPECT_EQ(42, actual.value);
    EXPECT_EQ("42", actual.reason);
}

namespace testing {

struct streamable_value_t {
    std::string message;
    int value;

    friend std::ostream& operator<<(std::ostream& stream, const streamable_value_t& value) {
        stream << "['" << value.message << "', " << value.value << "]";
        return stream;
    }
};

} // namespace testing

struct ExtractStreamableValueAttributesAction {
    struct pack_t {
        std::string message;
        std::string value;
    };

    pack_t& actual;

    void operator()(const log::record_t& record) const {
        actual.message = record.extract<std::string>("message");
        actual.value = record.extract<std::string>("value");
    }
};

TEST(Macro, UsingStreamOperatorIfNoImplicitConversionAvailable) {
    static_assert(traits::supports::stream_push<streamable_value_t>::value,
                  "`streamable_value_t` must support stream push operator<<");

    streamable_value_t value = { "42", 42 };

    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    ExtractStreamableValueAttributesAction::pack_t actual;
    ExtractStreamableValueAttributesAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));

    BH_LOG(log, level::debug, "message")("value", value);

    EXPECT_EQ("message", actual.message);
    EXPECT_EQ("['42', 42]", actual.value);
}

TEST(Macro, InitializerListAttributes) {
    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    ExtractStreamableValueAttributesAction::pack_t actual;
    ExtractStreamableValueAttributesAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));

    BH_LOG(log, level::debug, "message")(attribute::list({
        {"value", "42"}
    }));

    EXPECT_EQ("message", actual.message);
    EXPECT_EQ("42", actual.value);
}

namespace RecursiveAttributeFeeders {

struct action_t {
    struct pack_t {
        std::string message;
        std::string value;
        int nested;
    };

    pack_t& actual;

    void operator()(const log::record_t& record) const {
        actual.message = record.extract<std::string>("message");
        actual.value = record.extract<std::string>("value");
        actual.nested = record.extract<int>("nested");
    }
};

} // namespace RecursiveAttributeFeeders

TEST(Macro, RecursiveAttributeFeeders) {
    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    RecursiveAttributeFeeders::action_t::pack_t actual;
    RecursiveAttributeFeeders::action_t action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));

    BH_LOG(log, level::debug, "message")("value", "42")("nested", 42);

    EXPECT_EQ("message", actual.message);
    EXPECT_EQ("42", actual.value);
    EXPECT_EQ(42, actual.nested);
}
<commit_msg>[Code Style] Style.<commit_after>#include <blackhole/macro.hpp>

#include "global.hpp"
#include "mocks/logger.hpp"

using namespace blackhole;

TEST(Macro, OpensInvalidLogRecordAndNotPush) {
    log::record_t record;
    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));
    EXPECT_CALL(log, push(_))
            .Times(0);
    BH_LOG(log, level::debug, "message");
}

struct ExtractMessageAttributeAction {
    std::string& actual;

    void operator()(log::record_t record) const {
        actual = record.extract<std::string>("message");
    }
};

TEST(Macro, OpensValidRecordAndPush) {
    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    std::string actual;
    ExtractMessageAttributeAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));
    BH_LOG(log, level::debug, "value");

    EXPECT_EQ("value", actual);
}

TEST(Macro, FormatMessageWithPrintfStyle) {
    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    std::string actual;
    ExtractMessageAttributeAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));

    BH_LOG(log, level::debug, "value [%d]: %s - okay", 100500, "blah");
    EXPECT_EQ("value [100500]: blah - okay", actual);
}

struct ExtractAttributesAction {
    struct pack_t {
        std::string message;
        int value;
        std::string reason;
        timeval timestamp;
    };

    pack_t& actual;

    void operator ()(log::record_t record) const {
        actual.message = record.extract<std::string>("message");
        actual.value = record.extract<int>("value");
        actual.reason = record.extract<std::string>("reason");
        actual.timestamp = record.extract<timeval>("timestamp");
    }
};

TEST(Macro, FormatMessageWithAttributes) {
    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    ExtractAttributesAction::pack_t actual;
    ExtractAttributesAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));

    BH_LOG(log, level::debug, "message")(
        attribute::make("value", 42),
        attribute::make("reason", "42"),
        keyword::timestamp() = timeval{ 100500, 0 }
    );

    EXPECT_EQ("message", actual.message);
    EXPECT_EQ(42, actual.value);
    EXPECT_EQ("42", actual.reason);
    EXPECT_EQ(100500, actual.timestamp.tv_sec);
}

TEST(Macro, FormatMessageWithPrintfStyleWithAttributes) {
    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    ExtractAttributesAction::pack_t actual;
    ExtractAttributesAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));

    BH_LOG(log, level::debug, "value [%d]: %s - okay", 100500, "blah")(
        attribute::make("value", 42),
        attribute::make("reason", "42"),
        keyword::timestamp() = timeval{ 100500, 0 }
    );

    EXPECT_EQ("value [100500]: blah - okay", actual.message);
    EXPECT_EQ(42, actual.value);
    EXPECT_EQ("42", actual.reason);
    EXPECT_EQ(100500, actual.timestamp.tv_sec);
}

namespace blackhole {

namespace format {

namespace message {

template<>
struct insitu<keyword::tag::severity_t<level>> {
    static inline std::ostream& execute(std::ostream& stream, level lvl) {
        static std::string DESCRIPTIONS[] = {
            "DEBUG",
            "INFO ",
            "WARN ",
            "ERROR"
        };

        std::size_t lvl_ = static_cast<std::size_t>(lvl);
        if (lvl_ < sizeof(DESCRIPTIONS) / sizeof(DESCRIPTIONS[0])) {
            stream << DESCRIPTIONS[lvl_];
        } else {
            stream << lvl_;
        }

        return stream;
    }
};

} // namespace message

} // namespace format

} // namespace blackhole

TEST(Macro, SpecificKeywordMessageFormatting) {
    log::record_t record;
    record.insert(keyword::severity<level>() = level::debug);

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    std::string actual;
    ExtractMessageAttributeAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));
    BH_LOG(log, level::debug, "value: %s", keyword::severity<level>());

    EXPECT_EQ("value: DEBUG", actual);
}

struct EmplaceCheckExtractAttributesAction {
    struct pack_t {
        std::string message;
        int value;
        std::string reason;
    };

    pack_t& actual;

    void operator ()(log::record_t record) const {
        actual.message = record.extract<std::string>("message");
        actual.value = record.extract<int>("value");
        actual.reason = record.extract<std::string>("reason");
    }
};

TEST(Macro, EmplaceAttributes) {
    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    EmplaceCheckExtractAttributesAction::pack_t actual;
    EmplaceCheckExtractAttributesAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));

    BH_LOG(log, level::debug, "message")(
        "value", 42,
        "reason", "42"
    );

    EXPECT_EQ("message", actual.message);
    EXPECT_EQ(42, actual.value);
    EXPECT_EQ("42", actual.reason);
}

namespace testing {

struct streamable_value_t {
    std::string message;
    int value;

    friend std::ostream& operator<<(std::ostream& stream, const streamable_value_t& value) {
        stream << "['" << value.message << "', " << value.value << "]";
        return stream;
    }
};

} // namespace testing

struct ExtractStreamableValueAttributesAction {
    struct pack_t {
        std::string message;
        std::string value;
    };

    pack_t& actual;

    void operator()(const log::record_t& record) const {
        actual.message = record.extract<std::string>("message");
        actual.value = record.extract<std::string>("value");
    }
};

TEST(Macro, UsingStreamOperatorIfNoImplicitConversionAvailable) {
    static_assert(traits::supports::stream_push<streamable_value_t>::value,
                  "`streamable_value_t` must support stream push operator<<");

    streamable_value_t value = { "42", 42 };

    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    ExtractStreamableValueAttributesAction::pack_t actual;
    ExtractStreamableValueAttributesAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));

    BH_LOG(log, level::debug, "message")("value", value);

    EXPECT_EQ("message", actual.message);
    EXPECT_EQ("['42', 42]", actual.value);
}

TEST(Macro, InitializerListAttributes) {
    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    ExtractStreamableValueAttributesAction::pack_t actual;
    ExtractStreamableValueAttributesAction action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));

    BH_LOG(log, level::debug, "message")(attribute::list({
        {"value", "42"}
    }));

    EXPECT_EQ("message", actual.message);
    EXPECT_EQ("42", actual.value);
}

namespace RecursiveAttributeFeeders {

struct action_t {
    struct pack_t {
        std::string message;
        std::string value;
        int nested;
    };

    pack_t& actual;

    void operator()(const log::record_t& record) const {
        actual.message = record.extract<std::string>("message");
        actual.value = record.extract<std::string>("value");
        actual.nested = record.extract<int>("nested");
    }
};

} // namespace RecursiveAttributeFeeders

TEST(Macro, RecursiveAttributeFeeders) {
    log::record_t record;
    record.insert(attribute::make("attr1", "value1"));

    mock::verbose_log_t<level> log;
    EXPECT_CALL(log, open_record(level::debug))
            .Times(1)
            .WillOnce(Return(record));

    RecursiveAttributeFeeders::action_t::pack_t actual;
    RecursiveAttributeFeeders::action_t action { actual };
    EXPECT_CALL(log, push(_))
            .Times(1)
            .WillOnce(WithArg<0>(Invoke(action)));

    BH_LOG(log, level::debug, "message")("value", "42")("nested", 42);

    EXPECT_EQ("message", actual.message);
    EXPECT_EQ("42", actual.value);
    EXPECT_EQ(42, actual.nested);
}
<|endoftext|>