<commit_before>/* Siconos-Kernel version 3.0.0, Copyright INRIA 2005-2008.
 * Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 * Siconos is a free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * Siconos 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Siconos; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact: Vincent ACARY vincent.acary@inrialpes.fr
 */
#include "LagrangianDS.h"
#include "NewtonEulerDS.h"
#include "UnitaryRelation.h"
#include "RelationTypes.hpp"
#include "NewtonImpactNSL.h"
#include "NewtonImpactFrictionNSL.h"
#include "RuntimeException.h"
#include "FirstOrderNonLinearDS.h"
#include "FirstOrderR.h"
#include "NewtonEulerR.h"

using namespace std;
using namespace RELATION;

// --- CONSTRUCTORS ---

// Data constructor
UnitaryRelation::UnitaryRelation(SP::Interaction inter,
                                 unsigned int pos,
                                 unsigned int num): _mainInteraction(inter),
  _relativePosition(pos),
  _number(num)
{}

// --- DESTRUCTOR ---
UnitaryRelation::~UnitaryRelation()
{
}

SP::SiconosVector UnitaryRelation::y(unsigned int i) const
{
  // i is the derivative number.
  return (interaction()->y(i)->vector(_number));
}

SP::SiconosVector UnitaryRelation::yOld(unsigned int i) const
{
  // i is the derivative number.
  return (interaction()->yOld(i)->vector(_number));
}

const VectorOfVectors UnitaryRelation::getLambda() const
{
  // A new object of type VectorOfVectors is created but it handles
  // pointers to BlockVectors, thus there is no copy of the "basic"
  // SimpleVectors.
  VectorOfVectors tmp;
  VectorOfVectors interactionUnitaryBlocks = interaction()->getLambda();

  for (unsigned int i = 0; i < interactionUnitaryBlocks.size(); ++i)
    tmp[i] = interactionUnitaryBlocks[i]->vector(_number);

  return tmp;
}

SP::SiconosVector UnitaryRelation::lambda(unsigned int i) const
{
  // i is the derivative number.
  return ((interaction()->lambda(i))->vector(_number));
}

const double UnitaryRelation::getYRef(unsigned int i) const
{
  // get the single value used to build indexSets Warning: the
  // relativePosition depends on NsLawSize and/or type.  This means
  // that at the time, for the unitaryBlock of y that corresponds to
  // the present relation, the first scalar value is used.  For
  // example, for friction, normal part is in first position, followed
  // by the tangential parts.
  return (*y(i))(0);
}

const double UnitaryRelation::getLambdaRef(unsigned int i) const
{
  // get the single value used to build indexSets
  return (*lambda(i))(0);
}

const unsigned int UnitaryRelation::getNonSmoothLawSize() const
{
  return interaction()->nonSmoothLaw()->size();
}

const RELATION::TYPES UnitaryRelation::getRelationType() const
{
  return interaction()->relation()->getType();
}

const RELATION::SUBTYPES UnitaryRelation::getRelationSubType() const
{
  return interaction()->relation()->getSubType();
}

SP::DynamicalSystemsSet UnitaryRelation::dynamicalSystems()
{
  return interaction()->dynamicalSystems();
}

void UnitaryRelation::initialize(const std::string& simulationType)
{
  if (!interaction())
    RuntimeException::selfThrow("UnitaryRelation::initialize() failed: the linked interaction is NULL.");

  _workX.reset(new BlockVector());
  _workZ.reset(new BlockVector());
  mWorkXq.reset(new BlockVector());
  _workFree.reset(new BlockVector());

  for (DSIterator it = dynamicalSystemsBegin(); it != dynamicalSystemsEnd(); ++it)
    _workZ->insertPtr((*it)->z());

  if (simulationType == "TimeStepping")
  {
    RELATION::TYPES pbType = getRelationType();
    if (pbType == FirstOrder)
    {
      for (DSIterator it = dynamicalSystemsBegin(); it != dynamicalSystemsEnd(); ++it)
      {
        SP::FirstOrderNonLinearDS fds = boost::static_pointer_cast<FirstOrderNonLinearDS>(*it);
        _workX->insertPtr(fds->x());
        _workFree->insertPtr(fds->workFree());
        mWorkXq->insertPtr(fds->xq());
      }
    }
  }

  if (simulationType == "EventDriven")
  {
    RELATION::TYPES pbType = getRelationType();
    if (pbType == FirstOrder)
    {
      for (DSIterator it = dynamicalSystemsBegin(); it != dynamicalSystemsEnd(); ++it)
      {
        _workX->insertPtr((*it)->x());
        //      mWorkXq->insertPtr((*it)->xq());
      }
    }
    else // Lagrangian
    {
      for (DSIterator it = dynamicalSystemsBegin(); it != dynamicalSystemsEnd(); ++it)
        _workX->insertPtr((boost::static_pointer_cast<LagrangianDS>(*it))->velocity());
    }
  }
  //   else
  //     RuntimeException::selfThrow("UnitaryRelation::initialize(simulationType) failed: unknown simulation type.");
}

void UnitaryRelation::getLeftUnitaryBlockForDS(SP::DynamicalSystem ds, SP::SiconosMatrix UnitaryBlock) const
{
  unsigned int k = 0;
  unsigned int NumDS = 0;
  DSIterator itDS;
  itDS = interaction()->dynamicalSystemsBegin();
  int sizey = interaction()->getSizeOfY();

  // look for ds and its position in G
  while (*itDS != ds && itDS != interaction()->dynamicalSystemsEnd())
  {
    k += (*itDS)->getDim();
    itDS++;
    NumDS++;
  }

  // check dimension (1)
  if ((*itDS)->getDim() != UnitaryBlock->size(1))
    RuntimeException::selfThrow("UnitaryRelation::getLeftUnitaryBlockForDS(DS, UnitaryBlock, ...): inconsistent sizes between UnitaryBlock and DS");

  SP::SiconosMatrix originalMatrix;

  RELATION::TYPES relationType = getRelationType();
  RELATION::SUBTYPES relationSubType = getRelationSubType();

  if (relationType == FirstOrder)
  {
    SP::FirstOrderR r = boost::static_pointer_cast<FirstOrderR> (interaction()->relation());
    originalMatrix = r->jacXH();
  }
  else if (relationType == Lagrangian)
  {
    SP::LagrangianR r = boost::static_pointer_cast<LagrangianR> (interaction()->relation());
    originalMatrix = r->jacQH();
  }
  else if (relationType == NewtonEuler)
  {
    SP::NewtonEulerR r = boost::static_pointer_cast<NewtonEulerR> (interaction()->relation());
    //      SP::BlockMatrix C = boost::static_pointer_cast<BlockMatrix> (r->jacQH());
    SP::SiconosMatrix C = r->jacQH();
    originalMatrix = r->jacQHT();

    //      SP::BlockMatrix jacQHT_block = boost::static_pointer_cast<BlockMatrix> (originalMatrix);

    //      SP::SiconosMatrix C_DS_block = C->block(NumDS,0);
    //      SP::SiconosMatrix CT_DS_block = jacQHT_block->block(NumDS,0);
    //      cout<<" UnitaryRelation::getLeftUnitaryBlockForDS : C_DS_block"<<endl;
    //      C_DS_block->display();
    SP::SimpleMatrix auxBloc(new SimpleMatrix(sizey, 7));
    SP::SimpleMatrix auxBloc2(new SimpleMatrix(sizey, 6));
    Index dimIndex(2);
    Index startIndex(4);
    startIndex[0] = 0;
    startIndex[1] = 0;
    startIndex[0] = 0;
    startIndex[1] = 7 * k / 6;
    dimIndex[0] = sizey;
    dimIndex[1] = 7;
    setBlock(C, auxBloc, dimIndex, startIndex);
    SP::NewtonEulerDS d =  boost::static_pointer_cast<NewtonEulerDS> (ds);
    SP::SiconosMatrix T = d->T();

    prod(*auxBloc, *T, *auxBloc2);
    //      prod(*C_DS_block,*T,*CT_DS_block);

    startIndex[1] = k;
    dimIndex[1] = 6;
    setBlock(auxBloc2, originalMatrix, dimIndex, startIndex);

  }
  else
    RuntimeException::selfThrow("UnitaryRelation::getLeftUnitaryBlockForDS, not yet implemented for relations of type " + relationType);

  // copy sub-unitaryBlock of originalMatrix into UnitaryBlock
  // dim of the sub-unitaryBlock
  Index subDim(2);
  subDim[0] = UnitaryBlock->size(0);
  subDim[1] = UnitaryBlock->size(1);
  // Position (row,col) of first element to be read in originalMatrix
  // and of first element to be set in UnitaryBlock
  Index subPos(4);
  subPos[0] = _relativePosition;
  subPos[1] = k;
  subPos[2] = 0;
  subPos[3] = 0;
  setBlock(originalMatrix, UnitaryBlock, subDim, subPos);
}

void UnitaryRelation::getRightUnitaryBlockForDS(SP::DynamicalSystem ds, SP::SiconosMatrix UnitaryBlock) const
{
  unsigned int k = 0;
  DSIterator itDS;
  itDS = interaction()->dynamicalSystemsBegin();

  // look for ds and its position in G
  while (*itDS != ds && itDS != interaction()->dynamicalSystemsEnd())
  {
    k += (*itDS)->getDim();
    itDS++;
  }

  // check dimension (1)
  if ((*itDS)->getDim() != UnitaryBlock->size(0))
    RuntimeException::selfThrow("UnitaryRelation::getRightUnitaryBlockForDS(DS, UnitaryBlock, ...): inconsistent sizes between UnitaryBlock and DS");

  SP::SiconosMatrix originalMatrix; // Complete matrix, Relation member.
  RELATION::TYPES relationType = getRelationType();
  RELATION::SUBTYPES relationSubType = getRelationSubType();

  if (relationType == FirstOrder)
  {
    originalMatrix = interaction()->relation()->jacLG();
  }
  else if (relationType == Lagrangian || relationType == NewtonEuler)
  {
    RuntimeException::selfThrow("UnitaryRelation::getRightUnitaryBlockForDS, call not permit " + relationType);
  }
  RuntimeException::selfThrow("UnitaryRelation::getRightUnitaryBlockForDS, not yet implemented for relations of type " + relationType);

  if (! originalMatrix)
    RuntimeException::selfThrow("UnitaryRelation::getRightUnitaryBlockForDS(DS, UnitaryBlock, ...): the right unitaryBlock is a NULL pointer (miss matrix B or H or gradients ...in relation ?)");

  // copy sub-unitaryBlock of originalMatrix into UnitaryBlock
  // dim of the sub-unitaryBlock
  Index subDim(2);
  subDim[0] = UnitaryBlock->size(0);
  subDim[1] = UnitaryBlock->size(1);
  // Position (row,col) of first element to be read in originalMatrix
  // and of first element to be set in UnitaryBlock
  Index subPos(4);
  subPos[0] = k;
  subPos[1] = _relativePosition;
  subPos[2] = 0;
  subPos[3] = 0;
  setBlock(originalMatrix, UnitaryBlock, subDim, subPos);
}

void UnitaryRelation::getExtraUnitaryBlock(SP::SiconosMatrix UnitaryBlock) const
{
  // !!! Warning: we suppose that D is unitaryBlock diagonal, ie that
  // there is no coupling between UnitaryRelation through D !!!  Any
  // coupling between relations through D must be taken into account
  // thanks to the nslaw (by "increasing" its dimension).

  RELATION::TYPES relationType = getRelationType();
  RELATION::SUBTYPES relationSubType = getRelationSubType();

  SP::SiconosMatrix D;
  //  if(interaction()->relation()->getNumberOfJacobiansForH()>1)
  D = interaction()->relation()->jacLH();

  if (! D)
  {
    UnitaryBlock->zero();
    return; //ie no extra unitaryBlock
  }

  // copy sub-unitaryBlock of originalMatrix into UnitaryBlock
  // dim of the sub-unitaryBlock
  Index subDim(2);
  subDim[0] = UnitaryBlock->size(0);
  subDim[1] = UnitaryBlock->size(1);
  // Position (row,col) of first element to be read in originalMatrix
  // and of first element to be set in UnitaryBlock
  Index subPos(4);
  subPos[0] = _relativePosition;
  subPos[1] = _relativePosition;
  subPos[2] = 0;
  subPos[3] = 0;
  setBlock(D, UnitaryBlock, subDim, subPos);
}

<commit_msg>Fix a bug<commit_after>/* Siconos-Kernel version 3.0.0, Copyright INRIA 2005-2008.
 * Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 * Siconos is a free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * Siconos 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Siconos; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact: Vincent ACARY vincent.acary@inrialpes.fr
 */
#include "LagrangianDS.h"
#include "NewtonEulerDS.h"
#include "UnitaryRelation.h"
#include "RelationTypes.hpp"
#include "NewtonImpactNSL.h"
#include "NewtonImpactFrictionNSL.h"
#include "RuntimeException.h"
#include "FirstOrderNonLinearDS.h"
#include "FirstOrderR.h"
#include "NewtonEulerR.h"

using namespace std;
using namespace RELATION;

// --- CONSTRUCTORS ---

// Data constructor
UnitaryRelation::UnitaryRelation(SP::Interaction inter,
                                 unsigned int pos,
                                 unsigned int num): _mainInteraction(inter),
  _relativePosition(pos),
  _number(num)
{}

// --- DESTRUCTOR ---
UnitaryRelation::~UnitaryRelation()
{
}

SP::SiconosVector UnitaryRelation::y(unsigned int i) const
{
  // i is the derivative number.
  return (interaction()->y(i)->vector(_number));
}

SP::SiconosVector UnitaryRelation::yOld(unsigned int i) const
{
  // i is the derivative number.
  return (interaction()->yOld(i)->vector(_number));
}

const VectorOfVectors UnitaryRelation::getLambda() const
{
  // A new object of type VectorOfVectors is created but it handles
  // pointers to BlockVectors, thus there is no copy of the "basic"
  // SimpleVectors.
  VectorOfVectors tmp;
  VectorOfVectors interactionUnitaryBlocks = interaction()->getLambda();

  for (unsigned int i = 0; i < interactionUnitaryBlocks.size(); ++i)
    tmp[i] = interactionUnitaryBlocks[i]->vector(_number);

  return tmp;
}

SP::SiconosVector UnitaryRelation::lambda(unsigned int i) const
{
  // i is the derivative number.
  return ((interaction()->lambda(i))->vector(_number));
}

const double UnitaryRelation::getYRef(unsigned int i) const
{
  // get the single value used to build indexSets Warning: the
  // relativePosition depends on NsLawSize and/or type.  This means
  // that at the time, for the unitaryBlock of y that corresponds to
  // the present relation, the first scalar value is used.  For
  // example, for friction, normal part is in first position, followed
  // by the tangential parts.
  return (*y(i))(0);
}

const double UnitaryRelation::getLambdaRef(unsigned int i) const
{
  // get the single value used to build indexSets
  return (*lambda(i))(0);
}

const unsigned int UnitaryRelation::getNonSmoothLawSize() const
{
  return interaction()->nonSmoothLaw()->size();
}

const RELATION::TYPES UnitaryRelation::getRelationType() const
{
  return interaction()->relation()->getType();
}

const RELATION::SUBTYPES UnitaryRelation::getRelationSubType() const
{
  return interaction()->relation()->getSubType();
}

SP::DynamicalSystemsSet UnitaryRelation::dynamicalSystems()
{
  return interaction()->dynamicalSystems();
}

void UnitaryRelation::initialize(const std::string& simulationType)
{
  if (!interaction())
    RuntimeException::selfThrow("UnitaryRelation::initialize() failed: the linked interaction is NULL.");

  _workX.reset(new BlockVector());
  _workZ.reset(new BlockVector());
  mWorkXq.reset(new BlockVector());
  _workFree.reset(new BlockVector());

  for (DSIterator it = dynamicalSystemsBegin(); it != dynamicalSystemsEnd(); ++it)
    _workZ->insertPtr((*it)->z());

  if (simulationType == "TimeStepping")
  {
    RELATION::TYPES pbType = getRelationType();
    if (pbType == FirstOrder)
    {
      for (DSIterator it = dynamicalSystemsBegin(); it != dynamicalSystemsEnd(); ++it)
      {
        SP::FirstOrderNonLinearDS fds = boost::static_pointer_cast<FirstOrderNonLinearDS>(*it);
        _workX->insertPtr(fds->x());
        _workFree->insertPtr(fds->workFree());
        mWorkXq->insertPtr(fds->xq());
      }
    }
  }

  if (simulationType == "EventDriven")
  {
    RELATION::TYPES pbType = getRelationType();
    if (pbType == FirstOrder)
    {
      for (DSIterator it = dynamicalSystemsBegin(); it != dynamicalSystemsEnd(); ++it)
      {
        _workX->insertPtr((*it)->x());
        //      mWorkXq->insertPtr((*it)->xq());
      }
    }
    else // Lagrangian
    {
      for (DSIterator it = dynamicalSystemsBegin(); it != dynamicalSystemsEnd(); ++it)
        _workX->insertPtr((boost::static_pointer_cast<LagrangianDS>(*it))->velocity());
    }
  }
  //   else
  //     RuntimeException::selfThrow("UnitaryRelation::initialize(simulationType) failed: unknown simulation type.");
}

void UnitaryRelation::getLeftUnitaryBlockForDS(SP::DynamicalSystem ds, SP::SiconosMatrix UnitaryBlock) const
{
  unsigned int k = 0;
  unsigned int NumDS = 0;
  DSIterator itDS;
  itDS = interaction()->dynamicalSystemsBegin();
  int sizey = interaction()->getSizeOfY();

  // look for ds and its position in G
  while (*itDS != ds && itDS != interaction()->dynamicalSystemsEnd())
  {
    k += (*itDS)->getDim();
    itDS++;
    NumDS++;
  }

  // check dimension (1)
  if ((*itDS)->getDim() != UnitaryBlock->size(1))
    RuntimeException::selfThrow("UnitaryRelation::getLeftUnitaryBlockForDS(DS, UnitaryBlock, ...): inconsistent sizes between UnitaryBlock and DS");

  SP::SiconosMatrix originalMatrix;

  RELATION::TYPES relationType = getRelationType();
  RELATION::SUBTYPES relationSubType = getRelationSubType();

  if (relationType == FirstOrder)
  {
    SP::FirstOrderR r = boost::static_pointer_cast<FirstOrderR> (interaction()->relation());
    originalMatrix = r->jacXH();
  }
  else if (relationType == Lagrangian)
  {
    SP::LagrangianR r = boost::static_pointer_cast<LagrangianR> (interaction()->relation());
    originalMatrix = r->jacQH();
  }
  else if (relationType == NewtonEuler)
  {
    SP::NewtonEulerR r = boost::static_pointer_cast<NewtonEulerR> (interaction()->relation());
    //      SP::BlockMatrix C = boost::static_pointer_cast<BlockMatrix> (r->jacQH());
    SP::SiconosMatrix C = r->jacQH();
    originalMatrix = r->jacQHT();

    //      SP::BlockMatrix jacQHT_block = boost::static_pointer_cast<BlockMatrix> (originalMatrix);

    //      SP::SiconosMatrix C_DS_block = C->block(NumDS,0);
    //      SP::SiconosMatrix CT_DS_block = jacQHT_block->block(NumDS,0);
    //      cout<<" UnitaryRelation::getLeftUnitaryBlockForDS : C_DS_block"<<endl;
    //      C_DS_block->display();
    SP::SimpleMatrix auxBloc(new SimpleMatrix(sizey, 7));
    SP::SimpleMatrix auxBloc2(new SimpleMatrix(sizey, 6));
    Index dimIndex(2);
    Index startIndex(4);
    startIndex[0] = 0;
    startIndex[1] = 0;
    startIndex[0] = 0;
    startIndex[1] = 7 * k / 6;
    dimIndex[0] = sizey;
    dimIndex[1] = 7;
    setBlock(C, auxBloc, dimIndex, startIndex);
    SP::NewtonEulerDS d =  boost::static_pointer_cast<NewtonEulerDS> (ds);
    SP::SiconosMatrix T = d->T();

    prod(*auxBloc, *T, *auxBloc2);
    //      prod(*C_DS_block,*T,*CT_DS_block);

    startIndex[1] = k;
    dimIndex[1] = 6;
    setBlock(auxBloc2, originalMatrix, dimIndex, startIndex);

  }
  else
    RuntimeException::selfThrow("UnitaryRelation::getLeftUnitaryBlockForDS, not yet implemented for relations of type " + relationType);

  // copy sub-unitaryBlock of originalMatrix into UnitaryBlock
  // dim of the sub-unitaryBlock
  Index subDim(2);
  subDim[0] = UnitaryBlock->size(0);
  subDim[1] = UnitaryBlock->size(1);
  // Position (row,col) of first element to be read in originalMatrix
  // and of first element to be set in UnitaryBlock
  Index subPos(4);
  subPos[0] = _relativePosition;
  subPos[1] = k;
  subPos[2] = 0;
  subPos[3] = 0;
  setBlock(originalMatrix, UnitaryBlock, subDim, subPos);
}

void UnitaryRelation::getRightUnitaryBlockForDS(SP::DynamicalSystem ds, SP::SiconosMatrix UnitaryBlock) const
{
  unsigned int k = 0;
  DSIterator itDS;
  itDS = interaction()->dynamicalSystemsBegin();

  // look for ds and its position in G
  while (*itDS != ds && itDS != interaction()->dynamicalSystemsEnd())
  {
    k += (*itDS)->getDim();
    itDS++;
  }

  // check dimension (1)
  if ((*itDS)->getDim() != UnitaryBlock->size(0))
    RuntimeException::selfThrow("UnitaryRelation::getRightUnitaryBlockForDS(DS, UnitaryBlock, ...): inconsistent sizes between UnitaryBlock and DS");

  SP::SiconosMatrix originalMatrix; // Complete matrix, Relation member.
  RELATION::TYPES relationType = getRelationType();
  RELATION::SUBTYPES relationSubType = getRelationSubType();

  if (relationType == FirstOrder)
  {
    originalMatrix = interaction()->relation()->jacLG();
  }
  else if (relationType == Lagrangian || relationType == NewtonEuler)
  {
    RuntimeException::selfThrow("UnitaryRelation::getRightUnitaryBlockForDS, call not permit " + relationType);
  }
  else
    RuntimeException::selfThrow("UnitaryRelation::getRightUnitaryBlockForDS, not yet implemented for relations of type " + relationType);

  if (! originalMatrix)
    RuntimeException::selfThrow("UnitaryRelation::getRightUnitaryBlockForDS(DS, UnitaryBlock, ...): the right unitaryBlock is a NULL pointer (miss matrix B or H or gradients ...in relation ?)");

  // copy sub-unitaryBlock of originalMatrix into UnitaryBlock
  // dim of the sub-unitaryBlock
  Index subDim(2);
  subDim[0] = UnitaryBlock->size(0);
  subDim[1] = UnitaryBlock->size(1);
  // Position (row,col) of first element to be read in originalMatrix
  // and of first element to be set in UnitaryBlock
  Index subPos(4);
  subPos[0] = k;
  subPos[1] = _relativePosition;
  subPos[2] = 0;
  subPos[3] = 0;
  setBlock(originalMatrix, UnitaryBlock, subDim, subPos);
}

void UnitaryRelation::getExtraUnitaryBlock(SP::SiconosMatrix UnitaryBlock) const
{
  // !!! Warning: we suppose that D is unitaryBlock diagonal, ie that
  // there is no coupling between UnitaryRelation through D !!!  Any
  // coupling between relations through D must be taken into account
  // thanks to the nslaw (by "increasing" its dimension).

  RELATION::TYPES relationType = getRelationType();
  RELATION::SUBTYPES relationSubType = getRelationSubType();

  SP::SiconosMatrix D;
  //  if(interaction()->relation()->getNumberOfJacobiansForH()>1)
  D = interaction()->relation()->jacLH();

  if (! D)
  {
    UnitaryBlock->zero();
    return; //ie no extra unitaryBlock
  }

  // copy sub-unitaryBlock of originalMatrix into UnitaryBlock
  // dim of the sub-unitaryBlock
  Index subDim(2);
  subDim[0] = UnitaryBlock->size(0);
  subDim[1] = UnitaryBlock->size(1);
  // Position (row,col) of first element to be read in originalMatrix
  // and of first element to be set in UnitaryBlock
  Index subPos(4);
  subPos[0] = _relativePosition;
  subPos[1] = _relativePosition;
  subPos[2] = 0;
  subPos[3] = 0;
  setBlock(D, UnitaryBlock, subDim, subPos);
}

<|endoftext|>


<commit_before>//
// remote-stream-impl.cpp
//
//  Created by Peter Gusev on 17 June 2016.
//  Copyright 2013-2016 Regents of the University of California
//

#include "remote-stream-impl.hpp"

#include <ndn-cpp/face.hpp>
#include <ndn-cpp/security/key-chain.hpp>
#include <ndn-cpp/name.hpp>

#include "frame-buffer.hpp"
#include "buffer-control.hpp"
#include "drd-estimator.hpp"
#include "interest-control.hpp"
#include "latency-control.hpp"
#include "pipeline-control.hpp"
#include "pipeliner.hpp"
#include "sample-estimator.hpp"
#include "pipeline-control-state-machine.hpp"
#include "playout.hpp"
#include "playout-control.hpp"
#include "interest-queue.hpp"
#include "data-validator.hpp"
#include "clock.hpp"

using namespace ndnrtc;
using namespace ndnrtc::statistics;
using namespace ndn;
using namespace boost;

RemoteStreamImpl::RemoteStreamImpl(asio::io_service& io,
			const shared_ptr<ndn::Face>& face,
			const shared_ptr<ndn::KeyChain>& keyChain,
			const std::string& streamPrefix):
type_(MediaStreamParams::MediaStreamType::MediaStreamTypeUnknown),
face_(face),
keyChain_(keyChain),
streamPrefix_(streamPrefix),
needMeta_(true), isRunning_(false), cuedToRun_(false),
metaFetcher_(make_shared<MetaFetcher>()),
sstorage_(StatisticsStorage::createConsumerStatistics())
{
	assert(face.get());
	assert(keyChain.get());

	description_ = "remote-stream";

	segmentController_ = make_shared<SegmentController>(io, 500, sstorage_);
	buffer_ = make_shared<Buffer>(sstorage_, make_shared<SlotPool>(500));
	playbackQueue_ = make_shared<PlaybackQueue>(Name(streamPrefix),
                                               dynamic_pointer_cast<Buffer>(buffer_));
	// playout and playout-control created in subclasses

	interestQueue_ = make_shared<InterestQueue>(io, face, sstorage_);
	shared_ptr<DrdEstimator> drdEstimator(make_shared<DrdEstimator>());
	sampleEstimator_ = make_shared<SampleEstimator>(sstorage_);
	bufferControl_ = make_shared<BufferControl>(drdEstimator, buffer_, sstorage_);
	latencyControl_ = make_shared<LatencyControl>(1000, drdEstimator, sstorage_);
	interestControl_ = make_shared<InterestControl>(drdEstimator, sstorage_);

	// pipeliner and pipeline control created in subclasses

	segmentController_->attach(sampleEstimator_.get());
	segmentController_->attach(bufferControl_.get());

	drdEstimator->attach((InterestControl*)interestControl_.get());
	drdEstimator->attach((LatencyControl*)latencyControl_.get());

	bufferControl_->attach((InterestControl*)interestControl_.get());
	bufferControl_->attach((LatencyControl*)latencyControl_.get());
}

bool
RemoteStreamImpl::isMetaFetched() const
{
	return streamMeta_.get() &&
		streamMeta_->getThreads().size() == threadsMeta_.size();
}

std::vector<std::string>
RemoteStreamImpl::getThreads() const
{
	if (streamMeta_.get())
		return streamMeta_->getThreads();
	return std::vector<std::string>();
}

void RemoteStreamImpl::start(const std::string& threadName)
{
	if (isRunning_)
		throw std::runtime_error("Remote stream has been already started");

    cuedToRun_ = true;
    threadName_ = threadName;

	if (!needMeta_)
		initiateFetching();
}

void
RemoteStreamImpl::setThread(const std::string& threadName)
{
	threadName_ = threadName;
}

void RemoteStreamImpl::stop()
{
    cuedToRun_ = false;
	stopFetching();
}

void
RemoteStreamImpl::setInterestLifetime(unsigned int lifetimeMs)
{
	// pipeliner_->setInterestLifetime(lifetimeMs);
}

void
RemoteStreamImpl::setTargetBufferSize(unsigned int bufferSizeMs)
{
    playoutControl_->setThreshold(bufferSizeMs);
	LogDebugC << "set target buffer size to " << bufferSizeMs << "ms" << std::endl;
    (*sstorage_)[Indicator::BufferTargetSize] = bufferSizeMs;
}

void
RemoteStreamImpl::setLogger(boost::shared_ptr<ndnlog::new_api::Logger> logger)
{
	NdnRtcComponent::setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(buffer_)->setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(metaFetcher_)->setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(bufferControl_)->setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(interestQueue_)->setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(pipeliner_)->setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(latencyControl_)->setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(interestControl_)->setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(playbackQueue_)->setLogger(logger);
    if (pipelineControl_.get()) pipelineControl_->setLogger(logger);
}

bool
RemoteStreamImpl::isVerified() const
{
	return (validationInfo_.size() == 0);
}

statistics::StatisticsStorage
RemoteStreamImpl::getStatistics() const
{
    (*sstorage_)[Indicator::Timestamp] = clock::unixTimestamp();
    return *sstorage_;
}

#pragma mark - private
void
RemoteStreamImpl::fetchMeta()
{
	shared_ptr<RemoteStreamImpl> me = dynamic_pointer_cast<RemoteStreamImpl>(shared_from_this());
	metaFetcher_->fetch(face_, keyChain_, Name(streamPrefix_).append(NameComponents::NameComponentMeta),
		[me,this](NetworkData& meta,
			const std::vector<ValidationErrorInfo>& validationInfo){
			me->addValidationInfo(validationInfo);
			me->streamMetaFetched(meta);
		},
		[me,this](const std::string& msg){
			LogWarnC << "error fetching stream meta: " << msg << std::endl;
			if (needMeta_ && !metaFetcher_->hasPendingRequest()) me->fetchMeta();
		});
}

void
RemoteStreamImpl::streamMetaFetched(NetworkData& meta)
{
	streamMeta_ = make_shared<MediaStreamMeta>(move(meta));

	shared_ptr<RemoteStreamImpl> me = dynamic_pointer_cast<RemoteStreamImpl>(shared_from_this());
	std::stringstream ss;
	for (auto& t:streamMeta_->getThreads())
	{
		fetchThreadMeta(t);
		ss << t << " ";
	}
	LogInfoC << "received stream meta info. "
		<< streamMeta_->getThreads().size() << " thread(s): " << ss.str() << std::endl;
}

void
RemoteStreamImpl::fetchThreadMeta(const std::string& threadName)
{
	shared_ptr<RemoteStreamImpl> me = dynamic_pointer_cast<RemoteStreamImpl>(shared_from_this());
	metaFetcher_->fetch(face_, keyChain_, Name(streamPrefix_).append(threadName).append(NameComponents::NameComponentMeta),
		[threadName,me,this](NetworkData& meta,
			const std::vector<ValidationErrorInfo>& validationInfo){
			me->addValidationInfo(validationInfo);
			me->threadMetaFetched(threadName, meta);
		},
		[me,threadName,this](const std::string& msg){
			LogWarnC << "error fetching thread meta: " << msg << std::endl;
			if (needMeta_ && !metaFetcher_->hasPendingRequest()) me->fetchThreadMeta(threadName);
	});
}

void
RemoteStreamImpl::threadMetaFetched(const std::string& thread, NetworkData& meta)
{
    threadsMeta_[thread] = make_shared<NetworkData>(move(meta));
	LogInfoC << "received thread meta info for: " << thread << std::endl;

	if (threadsMeta_.size() == streamMeta_->getThreads().size())
	{
		needMeta_ = false;
		if (cuedToRun_ && !isRunning_)
			initiateFetching();
	}
}

void
RemoteStreamImpl::initiateFetching()
{
    if (threadsMeta_.find(threadName_) == threadsMeta_.end())
    {
        LogErrorC << "Can't find requested thread " << threadName_
            << " in received metadata" << std::endl;
        throw std::runtime_error("Can't find requested thread to fetch");
    }

    LogInfoC << "initiating fetching from " << streamPrefix_
        << " (thread " << threadName_ << ")" << std::endl;

    isRunning_ = true;
    segmentController_->setIsActive(true);

    if (type_ == MediaStreamParams::MediaStreamType::MediaStreamTypeVideo)
    {
        VideoThreadMeta meta(threadsMeta_[threadName_]->data());
        sampleEstimator_->bootstrapSegmentNumber(meta.getSegInfo().deltaAvgSegNum_,
            SampleClass::Delta, SegmentClass::Data);
        sampleEstimator_->bootstrapSegmentNumber(meta.getSegInfo().deltaAvgParitySegNum_,
            SampleClass::Delta, SegmentClass::Parity);
        sampleEstimator_->bootstrapSegmentNumber(meta.getSegInfo().keyAvgSegNum_,
            SampleClass::Key, SegmentClass::Data);
        sampleEstimator_->bootstrapSegmentNumber(meta.getSegInfo().keyAvgParitySegNum_,
            SampleClass::Key, SegmentClass::Parity);
    }
}

void
RemoteStreamImpl::stopFetching()
{
    if (isRunning_)
    {
        segmentController_->setIsActive(false);
        pipelineControl_->stop();
        interestQueue_->reset();
        isRunning_ = false;
        needMeta_ = false;
        streamMeta_.reset();
        threadsMeta_.clear();
    }
}

void
RemoteStreamImpl::addValidationInfo(const std::vector<ValidationErrorInfo>& validationInfo)
{
	for (auto& vi:validationInfo)
		LogWarnC << "failed to verify data packet " << vi.getData()->getName() << std::endl;
	std::copy(validationInfo.begin(), validationInfo.end(), std::back_inserter(validationInfo_));
}
<commit_msg>use milliseconds since epoch for statistics gathering timestamps<commit_after>//
// remote-stream-impl.cpp
//
//  Created by Peter Gusev on 17 June 2016.
//  Copyright 2013-2016 Regents of the University of California
//

#include "remote-stream-impl.hpp"

#include <ndn-cpp/face.hpp>
#include <ndn-cpp/security/key-chain.hpp>
#include <ndn-cpp/name.hpp>

#include "frame-buffer.hpp"
#include "buffer-control.hpp"
#include "drd-estimator.hpp"
#include "interest-control.hpp"
#include "latency-control.hpp"
#include "pipeline-control.hpp"
#include "pipeliner.hpp"
#include "sample-estimator.hpp"
#include "pipeline-control-state-machine.hpp"
#include "playout.hpp"
#include "playout-control.hpp"
#include "interest-queue.hpp"
#include "data-validator.hpp"
#include "clock.hpp"

using namespace ndnrtc;
using namespace ndnrtc::statistics;
using namespace ndn;
using namespace boost;

RemoteStreamImpl::RemoteStreamImpl(asio::io_service& io,
			const shared_ptr<ndn::Face>& face,
			const shared_ptr<ndn::KeyChain>& keyChain,
			const std::string& streamPrefix):
type_(MediaStreamParams::MediaStreamType::MediaStreamTypeUnknown),
face_(face),
keyChain_(keyChain),
streamPrefix_(streamPrefix),
needMeta_(true), isRunning_(false), cuedToRun_(false),
metaFetcher_(make_shared<MetaFetcher>()),
sstorage_(StatisticsStorage::createConsumerStatistics())
{
	assert(face.get());
	assert(keyChain.get());

	description_ = "remote-stream";

	segmentController_ = make_shared<SegmentController>(io, 500, sstorage_);
	buffer_ = make_shared<Buffer>(sstorage_, make_shared<SlotPool>(500));
	playbackQueue_ = make_shared<PlaybackQueue>(Name(streamPrefix),
                                               dynamic_pointer_cast<Buffer>(buffer_));
	// playout and playout-control created in subclasses

	interestQueue_ = make_shared<InterestQueue>(io, face, sstorage_);
	shared_ptr<DrdEstimator> drdEstimator(make_shared<DrdEstimator>());
	sampleEstimator_ = make_shared<SampleEstimator>(sstorage_);
	bufferControl_ = make_shared<BufferControl>(drdEstimator, buffer_, sstorage_);
	latencyControl_ = make_shared<LatencyControl>(1000, drdEstimator, sstorage_);
	interestControl_ = make_shared<InterestControl>(drdEstimator, sstorage_);

	// pipeliner and pipeline control created in subclasses

	segmentController_->attach(sampleEstimator_.get());
	segmentController_->attach(bufferControl_.get());

	drdEstimator->attach((InterestControl*)interestControl_.get());
	drdEstimator->attach((LatencyControl*)latencyControl_.get());

	bufferControl_->attach((InterestControl*)interestControl_.get());
	bufferControl_->attach((LatencyControl*)latencyControl_.get());
}

bool
RemoteStreamImpl::isMetaFetched() const
{
	return streamMeta_.get() &&
		streamMeta_->getThreads().size() == threadsMeta_.size();
}

std::vector<std::string>
RemoteStreamImpl::getThreads() const
{
	if (streamMeta_.get())
		return streamMeta_->getThreads();
	return std::vector<std::string>();
}

void RemoteStreamImpl::start(const std::string& threadName)
{
	if (isRunning_)
		throw std::runtime_error("Remote stream has been already started");

    cuedToRun_ = true;
    threadName_ = threadName;

	if (!needMeta_)
		initiateFetching();
}

void
RemoteStreamImpl::setThread(const std::string& threadName)
{
	threadName_ = threadName;
}

void RemoteStreamImpl::stop()
{
    cuedToRun_ = false;
	stopFetching();
}

void
RemoteStreamImpl::setInterestLifetime(unsigned int lifetimeMs)
{
	// pipeliner_->setInterestLifetime(lifetimeMs);
}

void
RemoteStreamImpl::setTargetBufferSize(unsigned int bufferSizeMs)
{
    playoutControl_->setThreshold(bufferSizeMs);
	LogDebugC << "set target buffer size to " << bufferSizeMs << "ms" << std::endl;
    (*sstorage_)[Indicator::BufferTargetSize] = bufferSizeMs;
}

void
RemoteStreamImpl::setLogger(boost::shared_ptr<ndnlog::new_api::Logger> logger)
{
	NdnRtcComponent::setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(buffer_)->setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(metaFetcher_)->setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(bufferControl_)->setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(interestQueue_)->setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(pipeliner_)->setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(latencyControl_)->setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(interestControl_)->setLogger(logger);
    dynamic_pointer_cast<NdnRtcComponent>(playbackQueue_)->setLogger(logger);
    if (pipelineControl_.get()) pipelineControl_->setLogger(logger);
}

bool
RemoteStreamImpl::isVerified() const
{
	return (validationInfo_.size() == 0);
}

statistics::StatisticsStorage
RemoteStreamImpl::getStatistics() const
{
    (*sstorage_)[Indicator::Timestamp] = clock::millisecSinceEpoch();
    return *sstorage_;
}

#pragma mark - private
void
RemoteStreamImpl::fetchMeta()
{
	shared_ptr<RemoteStreamImpl> me = dynamic_pointer_cast<RemoteStreamImpl>(shared_from_this());
	metaFetcher_->fetch(face_, keyChain_, Name(streamPrefix_).append(NameComponents::NameComponentMeta),
		[me,this](NetworkData& meta,
			const std::vector<ValidationErrorInfo>& validationInfo){
			me->addValidationInfo(validationInfo);
			me->streamMetaFetched(meta);
		},
		[me,this](const std::string& msg){
			LogWarnC << "error fetching stream meta: " << msg << std::endl;
			if (needMeta_ && !metaFetcher_->hasPendingRequest()) me->fetchMeta();
		});
}

void
RemoteStreamImpl::streamMetaFetched(NetworkData& meta)
{
	streamMeta_ = make_shared<MediaStreamMeta>(move(meta));

	shared_ptr<RemoteStreamImpl> me = dynamic_pointer_cast<RemoteStreamImpl>(shared_from_this());
	std::stringstream ss;
	for (auto& t:streamMeta_->getThreads())
	{
		fetchThreadMeta(t);
		ss << t << " ";
	}
	LogInfoC << "received stream meta info. "
		<< streamMeta_->getThreads().size() << " thread(s): " << ss.str() << std::endl;
}

void
RemoteStreamImpl::fetchThreadMeta(const std::string& threadName)
{
	shared_ptr<RemoteStreamImpl> me = dynamic_pointer_cast<RemoteStreamImpl>(shared_from_this());
	metaFetcher_->fetch(face_, keyChain_, Name(streamPrefix_).append(threadName).append(NameComponents::NameComponentMeta),
		[threadName,me,this](NetworkData& meta,
			const std::vector<ValidationErrorInfo>& validationInfo){
			me->addValidationInfo(validationInfo);
			me->threadMetaFetched(threadName, meta);
		},
		[me,threadName,this](const std::string& msg){
			LogWarnC << "error fetching thread meta: " << msg << std::endl;
			if (needMeta_ && !metaFetcher_->hasPendingRequest()) me->fetchThreadMeta(threadName);
	});
}

void
RemoteStreamImpl::threadMetaFetched(const std::string& thread, NetworkData& meta)
{
    threadsMeta_[thread] = make_shared<NetworkData>(move(meta));
	LogInfoC << "received thread meta info for: " << thread << std::endl;

	if (threadsMeta_.size() == streamMeta_->getThreads().size())
	{
		needMeta_ = false;
		if (cuedToRun_ && !isRunning_)
			initiateFetching();
	}
}

void
RemoteStreamImpl::initiateFetching()
{
    if (threadsMeta_.find(threadName_) == threadsMeta_.end())
    {
        LogErrorC << "Can't find requested thread " << threadName_
            << " in received metadata" << std::endl;
        throw std::runtime_error("Can't find requested thread to fetch");
    }

    LogInfoC << "initiating fetching from " << streamPrefix_
        << " (thread " << threadName_ << ")" << std::endl;

    isRunning_ = true;
    segmentController_->setIsActive(true);

    if (type_ == MediaStreamParams::MediaStreamType::MediaStreamTypeVideo)
    {
        VideoThreadMeta meta(threadsMeta_[threadName_]->data());
        sampleEstimator_->bootstrapSegmentNumber(meta.getSegInfo().deltaAvgSegNum_,
            SampleClass::Delta, SegmentClass::Data);
        sampleEstimator_->bootstrapSegmentNumber(meta.getSegInfo().deltaAvgParitySegNum_,
            SampleClass::Delta, SegmentClass::Parity);
        sampleEstimator_->bootstrapSegmentNumber(meta.getSegInfo().keyAvgSegNum_,
            SampleClass::Key, SegmentClass::Data);
        sampleEstimator_->bootstrapSegmentNumber(meta.getSegInfo().keyAvgParitySegNum_,
            SampleClass::Key, SegmentClass::Parity);
    }
}

void
RemoteStreamImpl::stopFetching()
{
    if (isRunning_)
    {
        segmentController_->setIsActive(false);
        pipelineControl_->stop();
        interestQueue_->reset();
        isRunning_ = false;
        needMeta_ = false;
        streamMeta_.reset();
        threadsMeta_.clear();
    }
}

void
RemoteStreamImpl::addValidationInfo(const std::vector<ValidationErrorInfo>& validationInfo)
{
	for (auto& vi:validationInfo)
		LogWarnC << "failed to verify data packet " << vi.getData()->getName() << std::endl;
	std::copy(validationInfo.begin(), validationInfo.end(), std::back_inserter(validationInfo_));
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>

#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/test/test_server.h"

using std::wstring;

namespace {

const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");

}  // namespace

class LoginPromptTest : public UITest {
 protected:
  LoginPromptTest()
      : username_basic_(L"basicuser"),
        username_digest_(L"digestuser"),
        password_(L"secret"),
        password_bad_(L"denyme"),
        test_server_(net::TestServer::TYPE_HTTP, FilePath(kDocRoot)) {
  }

  void AppendTab(const GURL& url) {
    scoped_refptr<BrowserProxy> window_proxy(automation()->GetBrowserWindow(0));
    ASSERT_TRUE(window_proxy.get());
    ASSERT_TRUE(window_proxy->AppendTab(url));
  }

 protected:
  wstring username_basic_;
  wstring username_digest_;
  wstring password_;
  wstring password_bad_;

  net::TestServer test_server_;
};

wstring ExpectedTitleFromAuth(const wstring& username,
                              const wstring& password) {
  // The TestServer sets the title to username/password on successful login.
  return username + L"/" + password;
}

// Test that "Basic" HTTP authentication works.
TEST_F(LoginPromptTest, TestBasicAuth) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_FALSE(tab->SetAuth(username_basic_, password_bad_));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->CancelAuth());
  EXPECT_EQ(L"Denied: wrong password", GetActiveTabTitle());

  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->SetAuth(username_basic_, password_));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_),
            GetActiveTabTitle());
}

// Test that "Digest" HTTP authentication works.
TEST_F(LoginPromptTest, TestDigestAuth) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-digest")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_FALSE(tab->SetAuth(username_digest_, password_bad_));
  EXPECT_TRUE(tab->CancelAuth());
  EXPECT_EQ(L"Denied: wrong password", GetActiveTabTitle());

  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-digest")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->SetAuth(username_digest_, password_));
  EXPECT_EQ(ExpectedTitleFromAuth(username_digest_, password_),
            GetActiveTabTitle());
}

// Test that logging in on 2 tabs at once works.
TEST_F(LoginPromptTest, TestTwoAuths) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> basic_tab(GetActiveTab());
  ASSERT_TRUE(basic_tab.get());
  ASSERT_TRUE(basic_tab->NavigateToURL(test_server_.GetURL("auth-basic")));

  AppendTab(GURL(chrome::kAboutBlankURL));
  scoped_refptr<TabProxy> digest_tab(GetActiveTab());
  ASSERT_TRUE(digest_tab.get());
  ASSERT_TRUE(
      digest_tab->NavigateToURL(test_server_.GetURL("auth-digest")));

  EXPECT_TRUE(basic_tab->NeedsAuth());
  EXPECT_TRUE(basic_tab->SetAuth(username_basic_, password_));
  EXPECT_TRUE(digest_tab->NeedsAuth());
  EXPECT_TRUE(digest_tab->SetAuth(username_digest_, password_));

  wstring title;
  EXPECT_TRUE(basic_tab->GetTabTitle(&title));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_), title);

  EXPECT_TRUE(digest_tab->GetTabTitle(&title));
  EXPECT_EQ(ExpectedTitleFromAuth(username_digest_, password_), title);
}

// Test that cancelling authentication works.
TEST_F(LoginPromptTest, TestCancelAuth) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());

  // First navigate to a test server page so we have something to go back to.
  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("a")));

  // Navigating while auth is requested is the same as cancelling.
  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("b")));
  EXPECT_FALSE(tab->NeedsAuth());

  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->GoBack());  // should bring us back to 'a'
  EXPECT_FALSE(tab->NeedsAuth());

  // Now add a page and go back, so we have something to go forward to.
  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("c")));
  EXPECT_TRUE(tab->GoBack());  // should bring us back to 'a'

  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->GoForward());  // should bring us to 'c'
  EXPECT_FALSE(tab->NeedsAuth());

  // Now test that cancelling works as expected.
  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->CancelAuth());
  EXPECT_FALSE(tab->NeedsAuth());
  EXPECT_EQ(L"Denied: no auth", GetActiveTabTitle());
}

// If multiple tabs are looking for the same auth, the user should only have to
// enter it once (http://crbug.com/8914).
TEST_F(LoginPromptTest, SupplyRedundantAuths) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> basic_tab1(GetActiveTab());
  ASSERT_TRUE(basic_tab1.get());
  ASSERT_TRUE(
      basic_tab1->NavigateToURL(test_server_.GetURL("auth-basic/1")));
  EXPECT_TRUE(basic_tab1->NeedsAuth());

  AppendTab(GURL(chrome::kAboutBlankURL));
  scoped_refptr<TabProxy> basic_tab2(GetActiveTab());
  ASSERT_TRUE(basic_tab2.get());
  ASSERT_TRUE(
      basic_tab2->NavigateToURL(test_server_.GetURL("auth-basic/2")));
  EXPECT_TRUE(basic_tab2->NeedsAuth());

  // Set the auth in only one of the tabs (but wait for the other to load).
  int64 last_navigation_time;
  ASSERT_TRUE(basic_tab2->GetLastNavigationTime(&last_navigation_time));
  EXPECT_TRUE(basic_tab1->SetAuth(username_basic_, password_));
  EXPECT_TRUE(basic_tab2->WaitForNavigation(last_navigation_time));

  // Now both tabs have loaded.
  wstring title1;
  EXPECT_TRUE(basic_tab1->GetTabTitle(&title1));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_), title1);
  wstring title2;
  EXPECT_TRUE(basic_tab2->GetTabTitle(&title2));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_), title2);
}

// If multiple tabs are looking for the same auth, and one is cancelled, the
// other should be cancelled as well.
TEST_F(LoginPromptTest, CancelRedundantAuths) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> basic_tab1(GetActiveTab());
  ASSERT_TRUE(basic_tab1.get());
  ASSERT_TRUE(
      basic_tab1->NavigateToURL(test_server_.GetURL("auth-basic/1")));
  EXPECT_TRUE(basic_tab1->NeedsAuth());

  AppendTab(GURL(chrome::kAboutBlankURL));
  scoped_refptr<TabProxy> basic_tab2(GetActiveTab());
  ASSERT_TRUE(basic_tab2.get());
  ASSERT_TRUE(
      basic_tab2->NavigateToURL(test_server_.GetURL("auth-basic/2")));
  EXPECT_TRUE(basic_tab2->NeedsAuth());

  // Cancel the auth in only one of the tabs (but wait for the other to load).
  int64 last_navigation_time;
  ASSERT_TRUE(basic_tab2->GetLastNavigationTime(&last_navigation_time));
  EXPECT_TRUE(basic_tab1->CancelAuth());
  EXPECT_TRUE(basic_tab2->WaitForNavigation(last_navigation_time));

  // Now both tabs have been denied.
  wstring title1;
  EXPECT_TRUE(basic_tab1->GetTabTitle(&title1));
  EXPECT_EQ(L"Denied: no auth", title1);
  wstring title2;
  EXPECT_TRUE(basic_tab2->GetTabTitle(&title2));
  EXPECT_EQ(L"Denied: no auth", title2);
}
<commit_msg>Failing fairly often due to tab->NavigateToURL(...) failing.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>

#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/test/test_server.h"

using std::wstring;

namespace {

const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");

}  // namespace

class LoginPromptTest : public UITest {
 protected:
  LoginPromptTest()
      : username_basic_(L"basicuser"),
        username_digest_(L"digestuser"),
        password_(L"secret"),
        password_bad_(L"denyme"),
        test_server_(net::TestServer::TYPE_HTTP, FilePath(kDocRoot)) {
  }

  void AppendTab(const GURL& url) {
    scoped_refptr<BrowserProxy> window_proxy(automation()->GetBrowserWindow(0));
    ASSERT_TRUE(window_proxy.get());
    ASSERT_TRUE(window_proxy->AppendTab(url));
  }

 protected:
  wstring username_basic_;
  wstring username_digest_;
  wstring password_;
  wstring password_bad_;

  net::TestServer test_server_;
};

wstring ExpectedTitleFromAuth(const wstring& username,
                              const wstring& password) {
  // The TestServer sets the title to username/password on successful login.
  return username + L"/" + password;
}

// Test that "Basic" HTTP authentication works.
TEST_F(LoginPromptTest, TestBasicAuth) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_FALSE(tab->SetAuth(username_basic_, password_bad_));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->CancelAuth());
  EXPECT_EQ(L"Denied: wrong password", GetActiveTabTitle());

  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->SetAuth(username_basic_, password_));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_),
            GetActiveTabTitle());
}

// Test that "Digest" HTTP authentication works.
TEST_F(LoginPromptTest, TestDigestAuth) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-digest")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_FALSE(tab->SetAuth(username_digest_, password_bad_));
  EXPECT_TRUE(tab->CancelAuth());
  EXPECT_EQ(L"Denied: wrong password", GetActiveTabTitle());

  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-digest")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->SetAuth(username_digest_, password_));
  EXPECT_EQ(ExpectedTitleFromAuth(username_digest_, password_),
            GetActiveTabTitle());
}

// Test that logging in on 2 tabs at once works.
TEST_F(LoginPromptTest, TestTwoAuths) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> basic_tab(GetActiveTab());
  ASSERT_TRUE(basic_tab.get());
  ASSERT_TRUE(basic_tab->NavigateToURL(test_server_.GetURL("auth-basic")));

  AppendTab(GURL(chrome::kAboutBlankURL));
  scoped_refptr<TabProxy> digest_tab(GetActiveTab());
  ASSERT_TRUE(digest_tab.get());
  ASSERT_TRUE(
      digest_tab->NavigateToURL(test_server_.GetURL("auth-digest")));

  EXPECT_TRUE(basic_tab->NeedsAuth());
  EXPECT_TRUE(basic_tab->SetAuth(username_basic_, password_));
  EXPECT_TRUE(digest_tab->NeedsAuth());
  EXPECT_TRUE(digest_tab->SetAuth(username_digest_, password_));

  wstring title;
  EXPECT_TRUE(basic_tab->GetTabTitle(&title));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_), title);

  EXPECT_TRUE(digest_tab->GetTabTitle(&title));
  EXPECT_EQ(ExpectedTitleFromAuth(username_digest_, password_), title);
}

// http://crbug.com/55380 - NavigateToURL is making this flaky.
#if defiend(OS_WIN)
#define MAYBE_TestCancelAuth FLAKY_TestCancelAuth
#elif defined(OS_LINUX)
#define MAYBE_TestCancelAuth FLAKY_TestCancelAuth
#else
#define MAYBE_TestCancelAuth TestCancelAuth
#endif
// Test that cancelling authentication works.
TEST_F(LoginPromptTest, MAYBE_TestCancelAuth) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());

  // First navigate to a test server page so we have something to go back to.
  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("a")));

  // Navigating while auth is requested is the same as cancelling.
  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("b")));
  EXPECT_FALSE(tab->NeedsAuth());

  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->GoBack());  // should bring us back to 'a'
  EXPECT_FALSE(tab->NeedsAuth());

  // Now add a page and go back, so we have something to go forward to.
  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("c")));
  EXPECT_TRUE(tab->GoBack());  // should bring us back to 'a'

  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->GoForward());  // should bring us to 'c'
  EXPECT_FALSE(tab->NeedsAuth());

  // Now test that cancelling works as expected.
  ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->CancelAuth());
  EXPECT_FALSE(tab->NeedsAuth());
  EXPECT_EQ(L"Denied: no auth", GetActiveTabTitle());
}

// If multiple tabs are looking for the same auth, the user should only have to
// enter it once (http://crbug.com/8914).
TEST_F(LoginPromptTest, SupplyRedundantAuths) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> basic_tab1(GetActiveTab());
  ASSERT_TRUE(basic_tab1.get());
  ASSERT_TRUE(
      basic_tab1->NavigateToURL(test_server_.GetURL("auth-basic/1")));
  EXPECT_TRUE(basic_tab1->NeedsAuth());

  AppendTab(GURL(chrome::kAboutBlankURL));
  scoped_refptr<TabProxy> basic_tab2(GetActiveTab());
  ASSERT_TRUE(basic_tab2.get());
  ASSERT_TRUE(
      basic_tab2->NavigateToURL(test_server_.GetURL("auth-basic/2")));
  EXPECT_TRUE(basic_tab2->NeedsAuth());

  // Set the auth in only one of the tabs (but wait for the other to load).
  int64 last_navigation_time;
  ASSERT_TRUE(basic_tab2->GetLastNavigationTime(&last_navigation_time));
  EXPECT_TRUE(basic_tab1->SetAuth(username_basic_, password_));
  EXPECT_TRUE(basic_tab2->WaitForNavigation(last_navigation_time));

  // Now both tabs have loaded.
  wstring title1;
  EXPECT_TRUE(basic_tab1->GetTabTitle(&title1));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_), title1);
  wstring title2;
  EXPECT_TRUE(basic_tab2->GetTabTitle(&title2));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_), title2);
}

// If multiple tabs are looking for the same auth, and one is cancelled, the
// other should be cancelled as well.
TEST_F(LoginPromptTest, CancelRedundantAuths) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> basic_tab1(GetActiveTab());
  ASSERT_TRUE(basic_tab1.get());
  ASSERT_TRUE(
      basic_tab1->NavigateToURL(test_server_.GetURL("auth-basic/1")));
  EXPECT_TRUE(basic_tab1->NeedsAuth());

  AppendTab(GURL(chrome::kAboutBlankURL));
  scoped_refptr<TabProxy> basic_tab2(GetActiveTab());
  ASSERT_TRUE(basic_tab2.get());
  ASSERT_TRUE(
      basic_tab2->NavigateToURL(test_server_.GetURL("auth-basic/2")));
  EXPECT_TRUE(basic_tab2->NeedsAuth());

  // Cancel the auth in only one of the tabs (but wait for the other to load).
  int64 last_navigation_time;
  ASSERT_TRUE(basic_tab2->GetLastNavigationTime(&last_navigation_time));
  EXPECT_TRUE(basic_tab1->CancelAuth());
  EXPECT_TRUE(basic_tab2->WaitForNavigation(last_navigation_time));

  // Now both tabs have been denied.
  wstring title1;
  EXPECT_TRUE(basic_tab1->GetTabTitle(&title1));
  EXPECT_EQ(L"Denied: no auth", title1);
  wstring title2;
  EXPECT_TRUE(basic_tab2->GetTabTitle(&title2));
  EXPECT_EQ(L"Denied: no auth", title2);
}
<|endoftext|>


<commit_before>#ifndef ALEPH_DISTANCES_DETAIL_MUNKRES_HH__
#define ALEPH_DISTANCES_DETAIL_MUNKRES_HH__

#include "Matrix.hh"

#include <algorithm>
#include <limits>
#include <vector>

namespace aleph
{

namespace distances
{

namespace detail
{

template <class T> class Munkres
{
public:

  Munkres( Matrix<T>& matrix )
    : _matrix( matrix )
    , _stars( matrix.n() )
    , _primes( matrix.n() )
    , _rowMask( std::vector<bool>( _matrix.n(), false ) )
    , _colMask( std::vector<bool>( _matrix.n(), false ) )
  {
  }

  void operator()()
  {
    subtractRowMinimum( _matrix );

    unsigned short step = 1;

    while( step != 0 )
    {
      std::size_t row = 0;
      std::size_t col = 0;

      std::cout << "Step " << step << "\n"
                << std::string(80, '-') << "\n"
                << "Matrix" << "\n"
                << std::string(80, '-') << "\n"
                << _matrix << "\n"
                << std::string(80, '-') << "\n";

      switch( step )
      {
      case 1:
        step = step1();
        break;
      case 2:
        step = step2();
        break;
      case 3:
        step = step3( _matrix, row, col );
        break;
      case 4:
        step = step4( _matrix, row, col );
        break;
      case 5:
        step = step5( _matrix );
        break;
      }
    }

    auto n = _matrix.n();

    for( std::size_t row = 0; row < n; row++ )
    {
      for( std::size_t col = 0; col < n; col++ )
      {
        if( _stars( row, col ) )
          _matrix( row, col ) = T( 0 );
        else
          _matrix( row, col ) = std::numeric_limits<T>::max();
      }
    }
  }

private:

  // Modifies matrix in-place by subtracting the minimum value in each
  // row. The function assumes that matrix is not empty.
  void subtractRowMinimum( Matrix<T>& matrix )
  {
    auto n = matrix.n();

    for( std::size_t row = 0; row < n; row++ )
    {
      auto min = matrix( row, 0 );

      for( std::size_t col = 0; col < n; col++ )
        min = std::min( min, matrix( row, col ) );

      for( std::size_t col = 0; col < n; col++ )
        matrix( row, col ) -= min;
    }
  }

  bool findUncoveredZeroInMatrix( std::size_t& row, std::size_t& col ) const
  {
    auto n = _matrix.n();

    for( row = 0; row < n; row++ )
    {
      if( !_rowMask[row] )
      {
        for( col = 0; col < n; col++ )
        {
          if( !_colMask[col] )
          {
            if( _matrix( row, col ) == T( 0 ) )
              return true;
          }
        }
      }
    }

    return false;
  }

  // Find zeroes in the current matrix. If there is no starred zero in
  // the row or column, star the current value.
  unsigned short step1()
  {
    auto n = _matrix.n();

    for( std::size_t row = 0; row < n; row++ )
    {
      for( std::size_t col = 0; col < n; col++ )
      {
        if( _matrix( row, col ) == T( 0 ) )
        {
          // Check whether another zero in the same _column_ is already
          // starred.
          for( std::size_t r = 0; r < n; r++ )
          {
            if( _stars( r, col ) )
              goto skipCurrentColumn;
          }

          // Check whether another zero in the same _row_ is already
          // starred.
          for( std::size_t c = 0; c < n; c++ )
          {
            if( _stars( row, c ) )
              goto skipCurrentRow;
          }

          _stars( row, col )  = true;
          _primes( row, col ) = false;
        }
        skipCurrentColumn:
          ;
      }

      skipCurrentRow:
        ;
    }

    return 2;
  }

  // Cover each column that contains a starred zero. If enough columns
  // have been covered, the starred zeroes give us the complete set of
  // assignments.
  unsigned short step2()
  {
    auto n                     = _matrix.n();
    std::size_t coveredColumns = 0;

    for( std::size_t row = 0; row < n; row++ )
    {
      for( std::size_t col = 0; col < n; col++ )
      {
        if( _stars( row, col ) )
        {
          _colMask[col] = true;
          ++coveredColumns;
        }
      }
    }

    if( coveredColumns >= n )
      return 0;

    return 3;
  }

  // Find an uncovered zero and prime it. If there is no starred zero in
  // the row containing this primed zero, go to step 5. Otherwise, cover
  // this row and uncover the column that contains the starred zero.
  unsigned short step3( Matrix<T>& matrix, std::size_t& row, std::size_t& col )
  {
    if( findUncoveredZeroInMatrix( row, col ) )
    {
      _primes( row, col ) = true;
      _stars( row, col )  = false;
    }
    else
      return 5;

    auto n = matrix.n();

    for( std::size_t c = 0; c < n; c++ )
    {
      if( _stars( row, c ) )
      {
        _rowMask[row] = true;
        _colMask[col] = false;

        return 3;
      }
    }

    return 4;
  }

  unsigned short step4( Matrix<T>& matrix, std::size_t row, std::size_t col )
  {
    auto n = matrix.n();

    using Pair     = std::pair<std::size_t, std::size_t>;
    using Sequence = std::vector<Pair>;

    Sequence sequence;

    sequence.push_back( std::make_pair( row, col ) );

    Pair p1 = std::make_pair( 0, 0 );
    Pair p2 = std::make_pair( 0, 0 );

    std::size_t r = 0;
    std::size_t c = col;

    bool havePair = false;

    do
    {
      havePair = false;
      for ( r = 0; r < n; r++ )
      {
        if( _stars(r,c) )
        {
          p1.first  = r;
          p1.second = c;

          if( std::find( sequence.begin(), sequence.end(), p1 ) != sequence.end() )
            continue;

          havePair = true;

          sequence.push_back( p1 );
          break;
        }
      }

      if( !havePair )
        break;

      havePair = false;

      for( c = 0; c < n; c++ )
      {
        if( _primes(r,c) )
        {
          p2.first  = r;
          p2.second = c;

          if( std::find( sequence.begin(), sequence.end(), p2 ) != sequence.end() )
            continue;

          havePair = true;

          sequence.push_back( p2 );
          break;
        }
      }
    }
    while ( havePair );

    for( auto&& pair : sequence )
    {
      // Un-star
      if( _stars(pair.first, pair.second) )
        _stars(pair.first, pair.second) = false;

      // Star each primed zero
      if( _primes(pair.first, pair.second) )
        _stars(pair.first, pair.second) = true;
    }

    // Erase all primes & uncover all columns and rows -----------------

    for( std::size_t row = 0; row < n; row++ )
    {
      for( std::size_t col = 0; col < n; col++ )
        _primes(row, col) = false;

      _rowMask[row] = false;
      _colMask[row] = false;
    }

    return 2;
  }

  unsigned short step5( Matrix<T>& matrix )
  {
    auto n = matrix.n();
    T v    = std::numeric_limits<T>::max();

    for( std::size_t row = 0; row < n; row++ )
    {
      if( !_rowMask[row] )
      {
        for( std::size_t col = 0; col < n; col++ )
        {
          if( !_colMask[col] )
            if( matrix( row, col ) != T( 0 ) && matrix( row, col ) < v )
              v = matrix( row, col );
        }
      }
    }

    for( std::size_t row = 0; row < n; row++ )
    {
      if( _rowMask[row] )
      {
        for( std::size_t col = 0; col < n; col++ )
          matrix( row, col ) += v;
      }
    }

    for( std::size_t col = 0; col < n; col++ )
    {
      if( !_colMask[col] )
      {
        for( std::size_t row = 0; row < n; row++ )
          matrix( row, col ) -= v;
      }
    }

    return 3;
  }

  Matrix<T>& _matrix;

  Matrix<bool> _stars;
  Matrix<bool> _primes;

  std::vector<bool> _rowMask;
  std::vector<bool> _colMask;
};

}

}

}

#endif
<commit_msg>Further debugging attempts<commit_after>#ifndef ALEPH_DISTANCES_DETAIL_MUNKRES_HH__
#define ALEPH_DISTANCES_DETAIL_MUNKRES_HH__

#include "Matrix.hh"

#include <algorithm>
#include <limits>
#include <vector>

namespace aleph
{

namespace distances
{

namespace detail
{

template <class T> class Munkres
{
public:

  Munkres( Matrix<T>& matrix )
    : _matrix( matrix )
    , _stars( matrix.n() )
    , _primes( matrix.n() )
    , _rowMask( std::vector<bool>( _matrix.n(), false ) )
    , _colMask( std::vector<bool>( _matrix.n(), false ) )
  {
  }

  void operator()()
  {
    subtractRowMinimum( _matrix );

    unsigned short step = 1;

    while( step != 0 )
    {
      std::size_t row = 0;
      std::size_t col = 0;

      std::cout << "Step " << step << "\n"
                << std::string(80, '-') << "\n";

      switch( step )
      {
      case 1:
        step = step1();
        break;
      case 2:
        step = step2();
        break;
      case 3:
        step = step3( _matrix, row, col );
        break;
      case 4:
        step = step4( _matrix, row, col );
        break;
      case 5:
        step = step5( _matrix );
        break;
      }

      std::cout << "Matrix" << "\n"
                << std::string(80, '-') << "\n"
                << _matrix << "\n"
                << std::string(80, '-') << "\n";
    }

    auto n = _matrix.n();

    for( std::size_t row = 0; row < n; row++ )
    {
      for( std::size_t col = 0; col < n; col++ )
      {
        if( _stars( row, col ) )
          _matrix( row, col ) = T( 0 );
        else
          _matrix( row, col ) = std::numeric_limits<T>::max();
      }
    }
  }

private:

  // Modifies matrix in-place by subtracting the minimum value in each
  // row. The function assumes that matrix is not empty.
  void subtractRowMinimum( Matrix<T>& matrix )
  {
    auto n = matrix.n();

    for( std::size_t row = 0; row < n; row++ )
    {
      auto min = matrix( row, 0 );

      for( std::size_t col = 0; col < n; col++ )
        min = std::min( min, matrix( row, col ) );

      for( std::size_t col = 0; col < n; col++ )
        matrix( row, col ) -= min;
    }
  }

  bool findUncoveredZeroInMatrix( std::size_t& row, std::size_t& col ) const
  {
    auto n = _matrix.n();

    for( row = 0; row < n; row++ )
    {
      if( !_rowMask[row] )
      {
        for( col = 0; col < n; col++ )
        {
          if( !_colMask[col] )
          {
            if( _matrix( row, col ) == T( 0 ) )
              return true;
          }
        }
      }
    }

    return false;
  }

  // Find zeroes in the current matrix. If there is no starred zero in
  // the row or column, star the current value.
  unsigned short step1()
  {
    auto n = _matrix.n();

    for( std::size_t row = 0; row < n; row++ )
    {
      for( std::size_t col = 0; col < n; col++ )
      {
        if( _matrix( row, col ) == T( 0 ) )
        {
          // Check whether another zero in the same _column_ is already
          // starred.
          for( std::size_t r = 0; r < n; r++ )
          {
            if( _stars( r, col ) )
              goto skipCurrentColumn;
          }

          // Check whether another zero in the same _row_ is already
          // starred.
          for( std::size_t c = 0; c < n; c++ )
          {
            if( _stars( row, c ) )
              goto skipCurrentRow;
          }

          _stars( row, col )  = true;
          _primes( row, col ) = false;

          std::cout << "0* at (" << row << "," << col << ")\n";
        }
        skipCurrentColumn:
          ;
      }

      skipCurrentRow:
        ;
    }

    return 2;
  }

  // Cover each column that contains a starred zero. If enough columns
  // have been covered, the starred zeroes give us the complete set of
  // assignments.
  unsigned short step2()
  {
    auto n                     = _matrix.n();
    std::size_t coveredColumns = 0;

    for( std::size_t row = 0; row < n; row++ )
    {
      for( std::size_t col = 0; col < n; col++ )
      {
        if( _stars( row, col ) )
        {
          _colMask[col] = true;
          ++coveredColumns;
        }
      }
    }

    std::cout << "I have " << coveredColumns << " covered columns\n";

    if( coveredColumns >= n )
      return 0;

    return 3;
  }

  // Find an uncovered zero and prime it. If there is no starred zero in
  // the row containing this primed zero, go to step 5. Otherwise, cover
  // this row and uncover the column that contains the starred zero.
  unsigned short step3( Matrix<T>& matrix, std::size_t& row, std::size_t& col )
  {
    if( findUncoveredZeroInMatrix( row, col ) )
    {
      _primes( row, col ) = true;
      _stars( row, col )  = false;

      std::cout << "0' at (" << row << "," << col << ")\n";
    }
    else
      return 5;

    auto n = matrix.n();

    for( std::size_t c = 0; c < n; c++ )
    {
      if( _stars( row, c ) )
      {
        _rowMask[row] = true;
        _colMask[c]   = false;

        return 3;
      }
    }

    return 4;
  }

  unsigned short step4( Matrix<T>& matrix, std::size_t row, std::size_t col )
  {
    auto n = matrix.n();

    using Pair     = std::pair<std::size_t, std::size_t>;
    using Sequence = std::vector<Pair>;

    Sequence sequence;

    sequence.push_back( std::make_pair( row, col ) );

    Pair p1 = std::make_pair( 0, 0 );
    Pair p2 = std::make_pair( 0, 0 );

    std::size_t r = 0;
    std::size_t c = col;

    bool havePair = false;

    do
    {
      havePair = false;
      for ( r = 0; r < n; r++ )
      {
        if( _stars(r,c) )
        {
          p1.first  = r;
          p1.second = c;

          if( std::find( sequence.begin(), sequence.end(), p1 ) != sequence.end() )
            continue;

          havePair = true;

          sequence.push_back( p1 );
          break;
        }
      }

      if( !havePair )
        break;

      havePair = false;

      for( c = 0; c < n; c++ )
      {
        if( _primes(r,c) )
        {
          p2.first  = r;
          p2.second = c;

          if( std::find( sequence.begin(), sequence.end(), p2 ) != sequence.end() )
            continue;

          havePair = true;

          sequence.push_back( p2 );
          break;
        }
      }
    }
    while ( havePair );

    for( auto&& pair : sequence )
    {
      std::cout << "- (" << pair.first << "," << pair.second << ")\n";

      // Un-star
      if( _stars(pair.first, pair.second) )
      {
        _stars(pair.first, pair.second)  = false;
        _primes(pair.first, pair.second) = false;
      }

      // Star each primed zero
      if( _primes(pair.first, pair.second) )
      {
        _stars(pair.first, pair.second)  = true;
        _primes(pair.first, pair.second) = false;
      }
    }

    // Erase all primes & uncover all columns and rows -----------------

    for( std::size_t row = 0; row < n; row++ )
    {
      for( std::size_t col = 0; col < n; col++ )
      {
        if( _primes( row, col ) )
        {
          _primes(row, col) = false;
          _stars(row, col)  = false;
        }
      }

      _rowMask[row] = false;
      _colMask[row] = false;
    }

    return 2;
  }

  unsigned short step5( Matrix<T>& matrix )
  {
    auto n = matrix.n();
    T v    = std::numeric_limits<T>::max();

    for( std::size_t row = 0; row < n; row++ )
    {
      if( !_rowMask[row] )
      {
        for( std::size_t col = 0; col < n; col++ )
        {
          if( !_colMask[col] )
            if( matrix( row, col ) != T( 0 ) && matrix( row, col ) < v )
              v = matrix( row, col );
        }
      }
    }

    for( std::size_t row = 0; row < n; row++ )
    {
      if( _rowMask[row] )
      {
        for( std::size_t col = 0; col < n; col++ )
          matrix( row, col ) += v;
      }
    }

    for( std::size_t col = 0; col < n; col++ )
    {
      if( !_colMask[col] )
      {
        for( std::size_t row = 0; row < n; row++ )
          matrix( row, col ) -= v;
      }
    }

    return 3;
  }

  Matrix<T>& _matrix;

  Matrix<bool> _stars;
  Matrix<bool> _primes;

  std::vector<bool> _rowMask;
  std::vector<bool> _colMask;
};

}

}

}

#endif
<|endoftext|>


<commit_before>/*******************************************************************
 KNotes -- Notes for the KDE project

 Copyright (c) 2005, Michael Brade <brade@kde.org>

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

 In addition, as a special exception, the copyright holders give
 permission to link the code of this program with any edition of
 the Qt library by Trolltech AS, Norway (or with modified versions
 of Qt that use the same license as Qt), and distribute linked
 combinations including the two.  You must obey the GNU General
 Public License in all respects for all of the code used other than
 Qt.  If you modify this file, you may extend this exception to
 your version of the file, but you are not obligated to do so.  If
 you do not wish to do so, delete this exception statement from
 your version.
*******************************************************************/

#include <qlabel.h>
#include <qradiobutton.h>
#include <qbuttongroup.h>
#include <qvbox.h>

#include <klocale.h>

#include <libkdepim/kdateedit.h>
#include <libkdepim/ktimeedit.h>

#include <libkcal/journal.h>
#include <libkcal/alarm.h>

#include "knotealarmdlg.h"

KNoteAlarmDlg::KNoteAlarmDlg( const QString& caption, QWidget *parent, const char *name )
    : KDialogBase( parent, name, true, caption, Ok|Cancel, Ok )
{
    QVBox *page = makeVBoxMainWidget();
    QGroupBox *group = new QGroupBox( 3, Vertical, i18n("Scheduled Alarm"), page );
    m_buttons = new QButtonGroup( page );
    m_buttons->hide();

    QRadioButton *none = new QRadioButton( i18n("&No alarm"), group );
    m_buttons->insert( none );

    QHBox *at = new QHBox( group );
    QRadioButton *label_at = new QRadioButton( i18n("Alarm &at:"), at );
    m_buttons->insert( label_at );
    m_atDate = new KDateEdit( at );
    m_atTime = new KTimeEdit( at );
    at->setStretchFactor( m_atDate, 1 );

    QHBox *in = new QHBox( group );
    QRadioButton *label_in = new QRadioButton( i18n("Alarm &in:"), in );
    m_buttons->insert( label_in );
    m_inTime = new KTimeEdit( in );
    QLabel *in_min = new QLabel( i18n("hours/minutes"), in );

    connect( m_buttons, SIGNAL(clicked( int )), SLOT(slotButtonChanged( int )) );
}

void KNoteAlarmDlg::setIncidence( KCal::Journal *journal )
{
    m_journal = journal;

    if ( !m_journal->alarms().isEmpty() )
    {
        KCal::Alarm *alarm = m_journal->alarms().first();
        if ( alarm->hasTime() )
        {
            m_buttons->setButton( 1 );
            m_atDate->setDate( alarm->time().date() );
            m_atTime->setTime( alarm->time().time() );
        }
        else if ( alarm->hasStartOffset() )
            m_buttons->setButton( 2 );
        else
            m_buttons->setButton( 0 );
    }
    else
        m_buttons->setButton( 0 );

    slotButtonChanged( m_buttons->selectedId() );
}

void KNoteAlarmDlg::slotButtonChanged( int id )
{
    switch ( id )
    {
    case 0:
        m_atDate->setEnabled( false );
        m_atTime->setEnabled( false );
        m_inTime->setEnabled( false );
        break;
    case 1:
        m_atDate->setEnabled( true );
        m_atTime->setEnabled( true );
        m_inTime->setEnabled( false );
        break;
    case 2:
        m_atDate->setEnabled( false );
        m_atTime->setEnabled( false );
        m_inTime->setEnabled( true );
    }
}

void KNoteAlarmDlg::slotOk()
{
    if ( m_buttons->selectedId() == 0 )
    {
        m_journal->clearAlarms();
        KDialogBase::slotOk();
        return;
    }

    KCal::Alarm *alarm;
    if ( m_journal->alarms().isEmpty() )
    {
        alarm = m_journal->newAlarm();
        alarm->setEnabled( true );
        alarm->setType( KCal::Alarm::Display );
    }
    else
        alarm = m_journal->alarms().first();

    if ( m_buttons->selectedId() == 1 )
        alarm->setTime( QDateTime( m_atDate->date(), m_atTime->getTime() ) );
    else
    {
        // TODO
    }

    KDialogBase::slotOk();
}

#include "knotealarmdlg.moc"
<commit_msg>Nope, too late, dunno how to do that ATM. I'm too tired. Something for KDE 3.4.1.<commit_after>/*******************************************************************
 KNotes -- Notes for the KDE project

 Copyright (c) 2005, Michael Brade <brade@kde.org>

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

 In addition, as a special exception, the copyright holders give
 permission to link the code of this program with any edition of
 the Qt library by Trolltech AS, Norway (or with modified versions
 of Qt that use the same license as Qt), and distribute linked
 combinations including the two.  You must obey the GNU General
 Public License in all respects for all of the code used other than
 Qt.  If you modify this file, you may extend this exception to
 your version of the file, but you are not obligated to do so.  If
 you do not wish to do so, delete this exception statement from
 your version.
*******************************************************************/

#include <qlabel.h>
#include <qradiobutton.h>
#include <qbuttongroup.h>
#include <qvbox.h>

#include <klocale.h>

#include <libkdepim/kdateedit.h>
#include <libkdepim/ktimeedit.h>

#include <libkcal/journal.h>
#include <libkcal/alarm.h>

#include "knotealarmdlg.h"

KNoteAlarmDlg::KNoteAlarmDlg( const QString& caption, QWidget *parent, const char *name )
    : KDialogBase( parent, name, true, caption, Ok|Cancel, Ok )
{
    QVBox *page = makeVBoxMainWidget();
    QGroupBox *group = new QGroupBox( 3, Vertical, i18n("Scheduled Alarm"), page );
    m_buttons = new QButtonGroup( page );
    m_buttons->hide();

    QRadioButton *none = new QRadioButton( i18n("&No alarm"), group );
    m_buttons->insert( none );

    QHBox *at = new QHBox( group );
    QRadioButton *label_at = new QRadioButton( i18n("Alarm &at:"), at );
    m_buttons->insert( label_at );
    m_atDate = new KDateEdit( at );
    m_atTime = new KTimeEdit( at );
    at->setStretchFactor( m_atDate, 1 );

    QHBox *in = new QHBox( group );
    QRadioButton *label_in = new QRadioButton( i18n("Alarm &in:"), in );
    m_buttons->insert( label_in );
    m_inTime = new KTimeEdit( in );
    QLabel *in_min = new QLabel( i18n("hours/minutes"), in );

    label_in->setEnabled( false ); // TODO

    connect( m_buttons, SIGNAL(clicked( int )), SLOT(slotButtonChanged( int )) );
}

void KNoteAlarmDlg::setIncidence( KCal::Journal *journal )
{
    m_journal = journal;

    if ( !m_journal->alarms().isEmpty() )
    {
        KCal::Alarm *alarm = m_journal->alarms().first();
        if ( alarm->hasTime() )
        {
            m_buttons->setButton( 1 );
            m_atDate->setDate( alarm->time().date() );
            m_atTime->setTime( alarm->time().time() );
        }
        else if ( alarm->hasStartOffset() )
            m_buttons->setButton( 2 );
        else
            m_buttons->setButton( 0 );
    }
    else
        m_buttons->setButton( 0 );

    slotButtonChanged( m_buttons->selectedId() );
}

void KNoteAlarmDlg::slotButtonChanged( int id )
{
    switch ( id )
    {
    case 0:
        m_atDate->setEnabled( false );
        m_atTime->setEnabled( false );
        m_inTime->setEnabled( false );
        break;
    case 1:
        m_atDate->setEnabled( true );
        m_atTime->setEnabled( true );
        m_inTime->setEnabled( false );
        break;
    case 2:
        m_atDate->setEnabled( false );
        m_atTime->setEnabled( false );
        m_inTime->setEnabled( true );
    }
}

void KNoteAlarmDlg::slotOk()
{
    if ( m_buttons->selectedId() == 0 )
    {
        m_journal->clearAlarms();
        KDialogBase::slotOk();
        return;
    }

    KCal::Alarm *alarm;
    if ( m_journal->alarms().isEmpty() )
    {
        alarm = m_journal->newAlarm();
        alarm->setEnabled( true );
        alarm->setType( KCal::Alarm::Display );
    }
    else
        alarm = m_journal->alarms().first();

    if ( m_buttons->selectedId() == 1 )
        alarm->setTime( QDateTime( m_atDate->date(), m_atTime->getTime() ) );
    else
    {
        // TODO
    }

    KDialogBase::slotOk();
}

#include "knotealarmdlg.moc"
<|endoftext|>


<commit_before>/*
 * Copyright 2015-2017 Two Pore Guys, Inc.
 * All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted providing that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "catch.hpp"

#include <glib.h>
#include <string.h>
#include <rpc/object.h>
#include "../src/serializer/json.h"
#include "../src/internal.h"

static char json_dict_gold[] = "{"
    "\"null\":null,"
    "\"int\":-123,"
    "\"uint\":{\"$uint\":123},"
    "\"date\":{\"$date\":456},"
    "\"binary\":{\"bin\":\"MTIzNA==\"},"
    "\"fd\":{\"$fd\":1},"
    "\"double\":12.0,"
    "\"string\":\"deadbeef\","
    "\"array\":[\"woopwoop\",-1234,{\"$fd\":2}]"
    "}";

static char json_array_gold[] = "["
    "null,"
    "-123,"
    "{\"$uint\":123},"
    "{\"$date\":456},"
    "{\"bin\":\"MTIzNA==\"},"
    "{\"$fd\":1},"
    "12.0,"
    "\"deadbeef\","
    "{\"string\":\"woopwoop\",\"int\":-1234,\"fd\":{\"$fd\":2}}"
    "]";

static char json_single_gold[] = "\"asd\"";

static char json_single_ext_gold[] = "{\"$uint\":123}";

SCENARIO("JSON_DICT_TEST", "Deserialize golden reference, serialize it again, and compare result") {
	GIVEN("JSON object") {
		rpc_object_t object;
		rpc_object_t object_mirror;
		size_t buf_size;
		void *buf;

		WHEN("Golden reference JSON is deserialized") {
			object = rpc_json_deserialize((void *) json_dict_gold,
			    strlen(json_dict_gold));

			REQUIRE(object != NULL);

			AND_WHEN("Returned RPC object is serialized again") {
				rpc_json_serialize(object, &buf, &buf_size);

				AND_WHEN("Output buffer is deserialized again") {
					object_mirror = rpc_json_deserialize(
					    buf, buf_size);

					REQUIRE(object_mirror != NULL);

					THEN("Both RPC object and its mirror retrieved from deserialized JSON are equal") {
						REQUIRE(rpc_equal(object, object_mirror));
					}
				}
			}
		}
	}
}

SCENARIO("JSON_ARRAY_TEST", "Deserialize golden reference, serialize it again, and compare result") {
	GIVEN("JSON object") {
		rpc_object_t object;
		rpc_object_t object_mirror;
		size_t buf_size;
		void *buf;

		WHEN("Golden reference JSON is deserialized") {
			object = rpc_json_deserialize((void *) json_array_gold,
			    strlen(json_array_gold));

			REQUIRE(object != NULL);

			AND_WHEN("Returned RPC object is serialized again") {
				rpc_json_serialize(object, &buf, &buf_size);

				AND_WHEN("Output buffer is deserialized again") {
					object_mirror = rpc_json_deserialize(
					    buf, buf_size);

					REQUIRE(object_mirror != NULL);

					THEN("Both RPC object and its mirror retrieved from deserialized JSON are equal") {
						REQUIRE(rpc_equal(object, object_mirror));
					}
				}
			}
		}
	}
}

SCENARIO("JSON_SINGLE_TEST", "Deserialize golden reference, serialize it again, and compare result") {
	GIVEN("JSON object") {
		rpc_object_t object;
		rpc_object_t object_mirror;
		size_t buf_size;
		void *buf;

		WHEN("Golden reference JSON is deserialized") {
			object = rpc_json_deserialize((void *) json_single_gold,
			    strlen(json_single_gold));

			REQUIRE(object != NULL);

			AND_WHEN("Returned RPC object is serialized again") {
				rpc_json_serialize(object, &buf, &buf_size);

				AND_WHEN("Output buffer is deserialized again") {
					object_mirror = rpc_json_deserialize(
					    buf, buf_size);

					REQUIRE(object_mirror != NULL);

					THEN("Both RPC object and its mirror retrieved from deserialized JSON are equal") {
						REQUIRE(rpc_equal(object, object_mirror));
					}
				}
			}
		}
	}
}

SCENARIO("JSON_SINGLE_EXT_TEST", "Deserialize golden reference, serialize it again, and compare result") {
	GIVEN("JSON object") {
		rpc_object_t object;
		rpc_object_t object_mirror;
		size_t buf_size;
		void *buf;

		WHEN("Golden reference JSON is deserialized") {
			object = rpc_json_deserialize((void *) json_single_ext_gold,
			    strlen(json_single_ext_gold));

			REQUIRE(object != NULL);

			AND_WHEN("Returned RPC object is serialized again") {
				rpc_json_serialize(object, &buf, &buf_size);

				AND_WHEN("Output buffer is deserialized again") {
					object_mirror = rpc_json_deserialize(
					    buf, buf_size);

					REQUIRE(object_mirror != NULL);

					THEN("Both RPC object and its mirror retrieved from deserialized JSON are equal") {
						REQUIRE(rpc_equal(object, object_mirror));
					}
				}
			}
		}
	}
}
<commit_msg>UPDATED: free resources in json test<commit_after>/*
 * Copyright 2015-2017 Two Pore Guys, Inc.
 * All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted providing that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "catch.hpp"

#include <glib.h>
#include <string.h>
#include <rpc/object.h>
#include "../src/serializer/json.h"
#include "../src/internal.h"

static char json_dict_gold[] = "{"
    "\"null\":null,"
    "\"int\":-123,"
    "\"uint\":{\"$uint\":123},"
    "\"date\":{\"$date\":456},"
    "\"binary\":{\"bin\":\"MTIzNA==\"},"
    "\"fd\":{\"$fd\":1},"
    "\"double\":12.0,"
    "\"string\":\"deadbeef\","
    "\"array\":[\"woopwoop\",-1234,{\"$fd\":2}]"
    "}";

static char json_array_gold[] = "["
    "null,"
    "-123,"
    "{\"$uint\":123},"
    "{\"$date\":456},"
    "{\"bin\":\"MTIzNA==\"},"
    "{\"$fd\":1},"
    "12.0,"
    "\"deadbeef\","
    "{\"string\":\"woopwoop\",\"int\":-1234,\"fd\":{\"$fd\":2}}"
    "]";

static char json_single_gold[] = "\"asd\"";

static char json_single_ext_gold[] = "{\"$uint\":123}";

SCENARIO("JSON_DICT_TEST", "Deserialize golden reference, serialize it again, and compare result") {
	GIVEN("JSON object") {
		rpc_object_t object = NULL;
		rpc_object_t object_mirror = NULL;
		size_t buf_size;
		void *buf = NULL;

		WHEN("Golden reference JSON is deserialized") {
			object = rpc_json_deserialize((void *) json_dict_gold,
			    strlen(json_dict_gold));

			REQUIRE(object != NULL);

			AND_WHEN("Returned RPC object is serialized again") {
				rpc_json_serialize(object, &buf, &buf_size);

				AND_WHEN("Output buffer is deserialized again") {
					object_mirror = rpc_json_deserialize(
					    buf, buf_size);

					REQUIRE(object_mirror != NULL);

					THEN("Both RPC object and its mirror retrieved from deserialized JSON are equal") {
						REQUIRE(rpc_equal(object, object_mirror));
					}
				}
			}
		}

		g_free(buf);
		rpc_release(object);
		rpc_release(object_mirror);
	}
}

SCENARIO("JSON_ARRAY_TEST", "Deserialize golden reference, serialize it again, and compare result") {
	GIVEN("JSON object") {
		rpc_object_t object = NULL;
		rpc_object_t object_mirror = NULL;
		size_t buf_size;
		void *buf = NULL;

		WHEN("Golden reference JSON is deserialized") {
			object = rpc_json_deserialize((void *) json_array_gold,
			    strlen(json_array_gold));

			REQUIRE(object != NULL);

			AND_WHEN("Returned RPC object is serialized again") {
				rpc_json_serialize(object, &buf, &buf_size);

				AND_WHEN("Output buffer is deserialized again") {
					object_mirror = rpc_json_deserialize(
					    buf, buf_size);

					REQUIRE(object_mirror != NULL);

					THEN("Both RPC object and its mirror retrieved from deserialized JSON are equal") {
						REQUIRE(rpc_equal(object, object_mirror));
					}
				}
			}
		}

		g_free(buf);
		rpc_release(object);
		rpc_release(object_mirror);
	}
}

SCENARIO("JSON_SINGLE_TEST", "Deserialize golden reference, serialize it again, and compare result") {
	GIVEN("JSON object") {
		rpc_object_t object = NULL;
		rpc_object_t object_mirror = NULL;
		size_t buf_size;
		void *buf = NULL;

		WHEN("Golden reference JSON is deserialized") {
			object = rpc_json_deserialize((void *) json_single_gold,
			    strlen(json_single_gold));

			REQUIRE(object != NULL);

			AND_WHEN("Returned RPC object is serialized again") {
				rpc_json_serialize(object, &buf, &buf_size);

				AND_WHEN("Output buffer is deserialized again") {
					object_mirror = rpc_json_deserialize(
					    buf, buf_size);

					REQUIRE(object_mirror != NULL);

					THEN("Both RPC object and its mirror retrieved from deserialized JSON are equal") {
						REQUIRE(rpc_equal(object, object_mirror));
					}
				}
			}
		}

		g_free(buf);
		rpc_release(object);
		rpc_release(object_mirror);
	}
}

SCENARIO("JSON_SINGLE_EXT_TEST", "Deserialize golden reference, serialize it again, and compare result") {
	GIVEN("JSON object") {
		rpc_object_t object = NULL;
		rpc_object_t object_mirror = NULL;
		size_t buf_size;
		void *buf = NULL;

		WHEN("Golden reference JSON is deserialized") {
			object = rpc_json_deserialize((void *) json_single_ext_gold,
			    strlen(json_single_ext_gold));

			REQUIRE(object != NULL);

			AND_WHEN("Returned RPC object is serialized again") {
				rpc_json_serialize(object, &buf, &buf_size);

				AND_WHEN("Output buffer is deserialized again") {
					object_mirror = rpc_json_deserialize(
					    buf, buf_size);

					REQUIRE(object_mirror != NULL);

					THEN("Both RPC object and its mirror retrieved from deserialized JSON are equal") {
						REQUIRE(rpc_equal(object, object_mirror));
					}
				}
			}
		}

		g_free(buf);
		rpc_release(object);
		rpc_release(object_mirror);
	}
}
<|endoftext|>