<commit_before>/// \file Canvas.cxx
/// \ingroup Gpad ROOT7
/// \author Axel Naumann <axel@cern.ch>
/// \date 2015-07-10
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome!

/*************************************************************************
 * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "ROOT/Canvas.h"

#include "ROOT/TDrawable.h"
#include "TCanvas.h"
#include "TROOT.h"

#include "ROOT/TLogger.h"

#include <memory>

namespace {
static
std::vector<std::shared_ptr<ROOT::Experimental::TCanvas>>& GetHeldCanvases() {
  static std::vector<std::shared_ptr<ROOT::Experimental::TCanvas>> sCanvases;
  return sCanvases;
}

}

namespace ROOT {
namespace Experimental {
namespace Internal {

class TV5CanvasAdaptor: public TObject {
  ROOT::Experimental::TCanvas& fNewCanv;
  ::TCanvas* fOldCanv; // ROOT owns them.

public:
  /// Construct an old TCanvas, append TV5CanvasAdaptor to its primitives.
  /// That way, TV5CanvasAdaptor::Paint() is called when the TCanvas paints its
  /// primitives, and TV5CanvasAdaptor::Paint() can forward to
  /// Experimental::TCanvas::Paint().
  TV5CanvasAdaptor(ROOT::Experimental::TCanvas& canv):
    fNewCanv(canv),
    fOldCanv(new ::TCanvas())
  {
    fOldCanv->SetTitle(canv.GetTitle().c_str());
    AppendPad();
  }

  ~TV5CanvasAdaptor() {
    // Make sure static destruction hasn't already destroyed the old TCanvases.
    if (gROOT && gROOT->GetListOfCanvases() && !gROOT->GetListOfCanvases()->IsEmpty())
      fOldCanv->RecursiveRemove(this);
  }

  void Paint(Option_t */*option*/="") override {
    fNewCanv.Paint();
  }
};
}
}
}

const std::vector<std::shared_ptr<ROOT::Experimental::TCanvas>> &
ROOT::Experimental::TCanvas::GetCanvases() {
  return GetHeldCanvases();
}

ROOT::Experimental::TCanvas::TCanvas() {
  fAdaptor = std::make_unique<Internal::TV5CanvasAdaptor>(*this);
}
ROOT::Experimental::TCanvas::~TCanvas() //= default;
{
}

void ROOT::Experimental::TCanvas::Paint() {
  for (auto&& drw: fPrimitives) {
    drw->Paint(*this);
  }
}

std::shared_ptr<ROOT::Experimental::TCanvas>
ROOT::Experimental::TCanvas::Create(const std::string& title) {
  auto pCanvas = std::make_shared<TCanvas>();
  pCanvas->SetTitle(title);
  GetHeldCanvases().emplace_back(pCanvas);
  return pCanvas;
}

// TODO: removal from GetHeldCanvases().<commit_msg>Rewrite default implementation as =default.<commit_after>/// \file Canvas.cxx
/// \ingroup Gpad ROOT7
/// \author Axel Naumann <axel@cern.ch>
/// \date 2015-07-10
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome!

/*************************************************************************
 * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "ROOT/Canvas.h"

#include "ROOT/TDrawable.h"
#include "TCanvas.h"
#include "TROOT.h"

#include "ROOT/TLogger.h"

#include <memory>

namespace {
static
std::vector<std::shared_ptr<ROOT::Experimental::TCanvas>>& GetHeldCanvases() {
  static std::vector<std::shared_ptr<ROOT::Experimental::TCanvas>> sCanvases;
  return sCanvases;
}

}

namespace ROOT {
namespace Experimental {
namespace Internal {

class TV5CanvasAdaptor: public TObject {
  ROOT::Experimental::TCanvas& fNewCanv;
  ::TCanvas* fOldCanv; // ROOT owns them.

public:
  /// Construct an old TCanvas, append TV5CanvasAdaptor to its primitives.
  /// That way, TV5CanvasAdaptor::Paint() is called when the TCanvas paints its
  /// primitives, and TV5CanvasAdaptor::Paint() can forward to
  /// Experimental::TCanvas::Paint().
  TV5CanvasAdaptor(ROOT::Experimental::TCanvas& canv):
    fNewCanv(canv),
    fOldCanv(new ::TCanvas())
  {
    fOldCanv->SetTitle(canv.GetTitle().c_str());
    AppendPad();
  }

  ~TV5CanvasAdaptor() {
    // Make sure static destruction hasn't already destroyed the old TCanvases.
    if (gROOT && gROOT->GetListOfCanvases() && !gROOT->GetListOfCanvases()->IsEmpty())
      fOldCanv->RecursiveRemove(this);
  }

  void Paint(Option_t */*option*/="") override {
    fNewCanv.Paint();
  }
};
}
}
}

const std::vector<std::shared_ptr<ROOT::Experimental::TCanvas>> &
ROOT::Experimental::TCanvas::GetCanvases() {
  return GetHeldCanvases();
}

ROOT::Experimental::TCanvas::TCanvas() {
  fAdaptor = std::make_unique<Internal::TV5CanvasAdaptor>(*this);
}

ROOT::Experimental::TCanvas::~TCanvas() = default;

void ROOT::Experimental::TCanvas::Paint() {
  for (auto&& drw: fPrimitives) {
    drw->Paint(*this);
  }
}

std::shared_ptr<ROOT::Experimental::TCanvas>
ROOT::Experimental::TCanvas::Create(const std::string& title) {
  auto pCanvas = std::make_shared<TCanvas>();
  pCanvas->SetTitle(title);
  GetHeldCanvases().emplace_back(pCanvas);
  return pCanvas;
}

// TODO: removal from GetHeldCanvases().<|endoftext|>


<commit_before>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "otbImage.h"
#include "otbDrawLineSpatialObjectListFilter.h"
#include "otbLineSpatialObjectList.h"

#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"

//  Software Guide : BeginCommandLineArgs
//    INPUTS: {QB_Suburb.png}
//    OUTPUTS: {QB_SuburbLSD.png}
//  Software Guide : EndCommandLineArgs

// Software Guide : BeginLatex
//
// This example illustrates the use of the
// \doxygen{otb}{LineSegmentDetector}\cite{LSD}, also known as {\em Lucy in the
// Sky with Diamonds}.
//
// The first step required to use this filter is to include its header file.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "otbLineSegmentDetector.h"
// Software Guide : EndCodeSnippet

int main( int argc, char * argv[] )
{
  const   char * infname  = argv[1];
  const   char * outfname  = argv[2];

  typedef unsigned char   InputPixelType;
  typedef double   PrecisionType;
  const   unsigned int    Dimension = 2;

// Software Guide : BeginLatex
//
// As usual, we start by defining the types for the input image and
// the image file reader.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  typedef otb::Image< InputPixelType,  Dimension >    ImageType;
  typedef otb::ImageFileReader<ImageType>        ReaderType;
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// We instantiate the reader and set the file name for the input image.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet

  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName(infname);
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// We define now the type for the segment detector filter. It is
// templated over the input image type and the precision with which
// the coordinates of the detected segments will be given. It is
// recommended to set this precision to a real type. The output of the
// filter will be a list of \doxygen{itk}{LineSpatialObject}s.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet

  typedef otb::LineSegmentDetector<ImageType,
                                                 PrecisionType> LsdFilterType;

  LsdFilterType::Pointer  lsdFilter = LsdFilterType::New();

  // Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// In order to be able to display the results, we will draw the
// detected segments on top of the input image. For this matter, we
// will use the \doxygen{otb}{DrawLineSpatialObjectListFilter} which
// is templated over the input and output image types.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet

  typedef otb::DrawLineSpatialObjectListFilter< ImageType,
                                       ImageType > DrawLineListType;
  DrawLineListType::Pointer drawLineFilter =   DrawLineListType::New();

  // Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// We can now define the type for the writer, instantiate it and set
// the file name for the output image.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet

  typedef otb::ImageFileWriter<ImageType>        WriterType;
  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName(outfname);

  // Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// We plug the pipeline.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet

  lsdFilter->SetInput(reader->GetOutput());
  writer->SetInput(drawLineFilter->GetOutput());

  drawLineFilter->SetInput(reader->GetOutput());
  drawLineFilter->SetInputLineSpatialObjectList(lsdFilter->GetOutput());
  drawLineFilter->SetValue(1000);

  // Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// Before calling the \code{Update()} method of the writer in order to
// trigger the pipeline execution, we call the
// \doxygen{GenerateOutputInformation()} of the reader, so the LSD
// filter gets the information about image size and spacing.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet

  reader->GenerateOutputInformation();
  writer->Update();

  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  // Figure~\ref{fig:LSD} shows the result of applying the line segment
  // detection to a small patch extracted from a VHR image.
  // \begin{figure}
  // \center
  // \includegraphics[width=0.35\textwidth]{QB_Suburb.eps}
  // \includegraphics[width=0.35\textwidth]{QB_SuburbLSD.eps}
  // \itkcaption[LSD Application]{Result of applying the
  // \doxygen{otb}{LineSegmentDetector} to a VHR image of a suburb.}
  // \label{fig:LSD}
  // \end{figure}
  //
  //  Software Guide : EndLatex

  return EXIT_SUCCESS;
}

<commit_msg>ENH : no need to set a value for the DrawLineFilter<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "otbImage.h"
#include "otbDrawLineSpatialObjectListFilter.h"
#include "otbLineSpatialObjectList.h"

#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"

//  Software Guide : BeginCommandLineArgs
//    INPUTS: {QB_Suburb.png}
//    OUTPUTS: {QB_SuburbLSD.png}
//  Software Guide : EndCommandLineArgs

// Software Guide : BeginLatex
//
// This example illustrates the use of the
// \doxygen{otb}{LineSegmentDetector}\cite{LSD}, also known as {\em Lucy in the
// Sky with Diamonds}.
//
// The first step required to use this filter is to include its header file.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "otbLineSegmentDetector.h"
// Software Guide : EndCodeSnippet

int main( int argc, char * argv[] )
{
  const   char * infname  = argv[1];
  const   char * outfname  = argv[2];

  typedef unsigned char   InputPixelType;
  typedef double   PrecisionType;
  const   unsigned int    Dimension = 2;

// Software Guide : BeginLatex
//
// As usual, we start by defining the types for the input image and
// the image file reader.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  typedef otb::Image< InputPixelType,  Dimension >    ImageType;
  typedef otb::ImageFileReader<ImageType>        ReaderType;
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// We instantiate the reader and set the file name for the input image.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet

  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName(infname);
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// We define now the type for the segment detector filter. It is
// templated over the input image type and the precision with which
// the coordinates of the detected segments will be given. It is
// recommended to set this precision to a real type. The output of the
// filter will be a list of \doxygen{itk}{LineSpatialObject}s.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet

  typedef otb::LineSegmentDetector<ImageType,
                                                 PrecisionType> LsdFilterType;

  LsdFilterType::Pointer  lsdFilter = LsdFilterType::New();

  // Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// In order to be able to display the results, we will draw the
// detected segments on top of the input image. For this matter, we
// will use the \doxygen{otb}{DrawLineSpatialObjectListFilter} which
// is templated over the input and output image types.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet

  typedef otb::DrawLineSpatialObjectListFilter< ImageType,
                                       ImageType > DrawLineListType;
  DrawLineListType::Pointer drawLineFilter =   DrawLineListType::New();

  // Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// We can now define the type for the writer, instantiate it and set
// the file name for the output image.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet

  typedef otb::ImageFileWriter<ImageType>        WriterType;
  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName(outfname);

  // Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// We plug the pipeline.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet

  lsdFilter->SetInput(reader->GetOutput());
  writer->SetInput(drawLineFilter->GetOutput());

  drawLineFilter->SetInput(reader->GetOutput());
  drawLineFilter->SetInputLineSpatialObjectList(lsdFilter->GetOutput());

  // Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// Before calling the \code{Update()} method of the writer in order to
// trigger the pipeline execution, we call the
// \doxygen{GenerateOutputInformation()} of the reader, so the LSD
// filter gets the information about image size and spacing.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet

  reader->GenerateOutputInformation();
  writer->Update();

  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  // Figure~\ref{fig:LSD} shows the result of applying the line segment
  // detection to a small patch extracted from a VHR image.
  // \begin{figure}
  // \center
  // \includegraphics[width=0.35\textwidth]{QB_Suburb.eps}
  // \includegraphics[width=0.35\textwidth]{QB_SuburbLSD.eps}
  // \itkcaption[LSD Application]{Result of applying the
  // \doxygen{otb}{LineSegmentDetector} to a VHR image of a suburb.}
  // \label{fig:LSD}
  // \end{figure}
  //
  //  Software Guide : EndLatex

  return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>// Copyright (c) 2015-2016 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Common validation fixtures for unit tests

#include "val_fixtures.h"

#include <functional>
#include <tuple>
#include <utility>

#include "test_fixture.h"

namespace spvtest {

template <typename T>
ValidateBase<T>::ValidateBase() : binary_(), diagnostic_() {
  // Initialize to default command line options. Different tests can then
  // specialize specific options as necessary.
  options_ = spvValidatorOptionsCreate();
}

template <typename T>
spv_const_binary ValidateBase<T>::get_const_binary() {
  return spv_const_binary(binary_);
}

template <typename T>
void ValidateBase<T>::TearDown() {
  if (diagnostic_) {
    spvDiagnosticPrint(diagnostic_);
  }
  spvDiagnosticDestroy(diagnostic_);
  spvBinaryDestroy(binary_);
  spvValidatorOptionsDestroy(options_);
}

template <typename T>
void ValidateBase<T>::CompileSuccessfully(std::string code,
                                          spv_target_env env) {
  spv_diagnostic diagnostic = nullptr;
  ASSERT_EQ(SPV_SUCCESS,
            spvTextToBinary(ScopedContext(env).context, code.c_str(),
                            code.size(), &binary_, &diagnostic))
      << "ERROR: " << diagnostic->error
      << "\nSPIR-V could not be compiled into binary:\n"
      << code;
}

template <typename T>
void ValidateBase<T>::OverwriteAssembledBinary(uint32_t index, uint32_t word) {
  ASSERT_TRUE(index < binary_->wordCount)
      << "OverwriteAssembledBinary: The given index is larger than the binary "
         "word count.";
  binary_->code[index] = word;
}

template <typename T>
spv_result_t ValidateBase<T>::ValidateInstructions(spv_target_env env) {
  return spvValidateWithOptions(ScopedContext(env).context, options_,
                                get_const_binary(), &diagnostic_);
}

template <typename T>
spv_result_t ValidateBase<T>::ValidateAndRetrieveValidationState(
    spv_target_env env) {
  return spvtools::ValidateBinaryAndKeepValidationState(
      ScopedContext(env).context, options_, get_const_binary()->code,
      get_const_binary()->wordCount, &diagnostic_, &vstate_);
}

template <typename T>
std::string ValidateBase<T>::getDiagnosticString() {
  return std::string(diagnostic_->error);
}

template <typename T>
spv_validator_options ValidateBase<T>::getValidatorOptions() {
  return options_;
}

template <typename T>
spv_position_t ValidateBase<T>::getErrorPosition() {
  return diagnostic_->position;
}

template class spvtest::ValidateBase<bool>;
template class spvtest::ValidateBase<int>;
template class spvtest::ValidateBase<std::string>;
template class spvtest::ValidateBase<std::pair<std::string, bool>>;
template class spvtest::ValidateBase<
    std::tuple<std::string, std::pair<std::string, std::vector<std::string>>>>;
template class spvtest::ValidateBase<
    std::tuple<int, std::tuple<std::string, std::function<spv_result_t(int)>,
                               std::function<spv_result_t(int)>>>>;
template class spvtest::ValidateBase<SpvCapability>;
template class spvtest::ValidateBase<std::pair<std::string, std::string>>;
}
<commit_msg>Fix nullptr dereferencing in val_fixtures.cpp<commit_after>// Copyright (c) 2015-2016 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Common validation fixtures for unit tests

#include "val_fixtures.h"

#include <functional>
#include <tuple>
#include <utility>

#include "test_fixture.h"

namespace spvtest {

template <typename T>
ValidateBase<T>::ValidateBase() : binary_(), diagnostic_() {
  // Initialize to default command line options. Different tests can then
  // specialize specific options as necessary.
  options_ = spvValidatorOptionsCreate();
}

template <typename T>
spv_const_binary ValidateBase<T>::get_const_binary() {
  return spv_const_binary(binary_);
}

template <typename T>
void ValidateBase<T>::TearDown() {
  if (diagnostic_) {
    spvDiagnosticPrint(diagnostic_);
  }
  spvDiagnosticDestroy(diagnostic_);
  spvBinaryDestroy(binary_);
  spvValidatorOptionsDestroy(options_);
}

template <typename T>
void ValidateBase<T>::CompileSuccessfully(std::string code,
                                          spv_target_env env) {
  spv_diagnostic diagnostic = nullptr;
  ASSERT_EQ(SPV_SUCCESS,
            spvTextToBinary(ScopedContext(env).context, code.c_str(),
                            code.size(), &binary_, &diagnostic))
      << "ERROR: " << diagnostic->error
      << "\nSPIR-V could not be compiled into binary:\n"
      << code;
}

template <typename T>
void ValidateBase<T>::OverwriteAssembledBinary(uint32_t index, uint32_t word) {
  ASSERT_TRUE(index < binary_->wordCount)
      << "OverwriteAssembledBinary: The given index is larger than the binary "
         "word count.";
  binary_->code[index] = word;
}

template <typename T>
spv_result_t ValidateBase<T>::ValidateInstructions(spv_target_env env) {
  return spvValidateWithOptions(ScopedContext(env).context, options_,
                                get_const_binary(), &diagnostic_);
}

template <typename T>
spv_result_t ValidateBase<T>::ValidateAndRetrieveValidationState(
    spv_target_env env) {
  return spvtools::ValidateBinaryAndKeepValidationState(
      ScopedContext(env).context, options_, get_const_binary()->code,
      get_const_binary()->wordCount, &diagnostic_, &vstate_);
}

template <typename T>
std::string ValidateBase<T>::getDiagnosticString() {
  return diagnostic_ == nullptr ?
      std::string() : std::string(diagnostic_->error);
}

template <typename T>
spv_validator_options ValidateBase<T>::getValidatorOptions() {
  return options_;
}

template <typename T>
spv_position_t ValidateBase<T>::getErrorPosition() {
  return diagnostic_ == nullptr ? spv_position_t() : diagnostic_->position;
}

template class spvtest::ValidateBase<bool>;
template class spvtest::ValidateBase<int>;
template class spvtest::ValidateBase<std::string>;
template class spvtest::ValidateBase<std::pair<std::string, bool>>;
template class spvtest::ValidateBase<
    std::tuple<std::string, std::pair<std::string, std::vector<std::string>>>>;
template class spvtest::ValidateBase<
    std::tuple<int, std::tuple<std::string, std::function<spv_result_t(int)>,
                               std::function<spv_result_t(int)>>>>;
template class spvtest::ValidateBase<SpvCapability>;
template class spvtest::ValidateBase<std::pair<std::string, std::string>>;
}
<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2017 Roman Lebedev

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifdef HAVE_JPEG

#include "decompressors/JpegDecompressor.h"
#include "common/Common.h"                // for uchar8, uint32, ushort16
#include "common/Memory.h"                // for alignedFree, alignedMalloc...
#include "common/Point.h"                 // for iPoint2D
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "io/ByteStream.h"                // for ByteStream
#include "io/IOException.h"               // for ThrowIOE
#include <algorithm>                      // for min
#include <cstdio>                         // for size_t
#include <memory>                         // for unique_ptr
#include <vector>                         // for vector

extern "C" {
#include <jpeglib.h> // for jpeg_source_mgr, jpeg_decompress_struct
// IWYU pragma: no_include <jconfig.h>
// IWYU pragma: no_include <jmorecfg.h>
}

using namespace std;

namespace RawSpeed {

#ifdef HAVE_JPEG_MEM_SRC

#define JPEG_MEMSRC(A, B, C) jpeg_mem_src(A, B, C)

#else

#define JPEG_MEMSRC(A, B, C) jpeg_mem_src_int(A, B, C)
/* Read JPEG image from a memory segment */

static void init_source(j_decompress_ptr cinfo) {}
static boolean fill_input_buffer(j_decompress_ptr cinfo) {
  auto* src = (struct jpeg_source_mgr*)cinfo->src;
  return (boolean) !!src->bytes_in_buffer;
}
static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
  auto* src = (struct jpeg_source_mgr*)cinfo->src;

  if (num_bytes > (int)src->bytes_in_buffer)
    ThrowIOE("JPEG Decoder - read out of buffer");
  if (num_bytes > 0) {
    src->next_input_byte += (size_t)num_bytes;
    src->bytes_in_buffer -= (size_t)num_bytes;
  }
}
static void term_source(j_decompress_ptr cinfo) {}
static void jpeg_mem_src_int(j_decompress_ptr cinfo,
                             const unsigned char* buffer, long nbytes) {
  struct jpeg_source_mgr* src;

  if (cinfo->src == nullptr) { /* first time for this JPEG object? */
    cinfo->src = (struct jpeg_source_mgr*)(*cinfo->mem->alloc_small)(
        (j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(struct jpeg_source_mgr));
  }

  src = (struct jpeg_source_mgr*)cinfo->src;
  src->init_source = init_source;
  src->fill_input_buffer = fill_input_buffer;
  src->skip_input_data = skip_input_data;
  src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
  src->term_source = term_source;
  src->bytes_in_buffer = nbytes;
  src->next_input_byte = (JOCTET*)buffer;
}

#endif

METHODDEF(void)
my_error_throw(j_common_ptr cinfo) { ThrowRDE("JPEG decoder error!"); }

struct JpegDecompressStruct : jpeg_decompress_struct {
  struct jpeg_error_mgr jerr;
  JpegDecompressStruct() {
    jpeg_create_decompress(this);

    err = jpeg_std_error(&jerr);
    jerr.error_exit = my_error_throw;
  }
  ~JpegDecompressStruct() { jpeg_destroy_decompress(this); }
};

void JpegDecompressor::decode(uint32 offX,
                              uint32 offY) { /* Each slice is a JPEG image */
  struct JpegDecompressStruct dinfo;

  vector<JSAMPROW> buffer(1);

  JPEG_MEMSRC(&dinfo, (unsigned char*)input.getData(input.getRemainSize()),
              input.getRemainSize());

  if (JPEG_HEADER_OK != jpeg_read_header(&dinfo, static_cast<boolean>(true)))
    ThrowRDE("JpegDecompressor: Unable to read JPEG header");

  jpeg_start_decompress(&dinfo);
  if (dinfo.output_components != (int)mRaw->getCpp())
    ThrowRDE("JpegDecompressor: Component count doesn't match");
  int row_stride = dinfo.output_width * dinfo.output_components;

  unique_ptr<uchar8[], decltype(&alignedFree)> complete_buffer(
      (uchar8*)alignedMallocArray<16>(dinfo.output_height, row_stride),
      alignedFree);
  while (dinfo.output_scanline < dinfo.output_height) {
    buffer[0] = (JSAMPROW)(
        &complete_buffer[(size_t)dinfo.output_scanline * row_stride]);
    if (0 == jpeg_read_scanlines(&dinfo, &buffer[0], 1))
      ThrowRDE("JpegDecompressor: JPEG Error while decompressing image.");
  }
  jpeg_finish_decompress(&dinfo);

  // Now the image is decoded, and we copy the image data
  int copy_w = min(mRaw->dim.x - offX, dinfo.output_width);
  int copy_h = min(mRaw->dim.y - offY, dinfo.output_height);
  for (int y = 0; y < copy_h; y++) {
    uchar8* src = &complete_buffer[(size_t)row_stride * y];
    auto* dst = (ushort16*)mRaw->getData(offX, y + offY);
    for (int x = 0; x < copy_w; x++) {
      for (int c = 0; c < dinfo.output_components; c++)
        *dst++ = (*src++);
    }
  }
}

} // namespace RawSpeed

#else

#pragma message                                                                \
    "JPEG is not present! Lossy JPEG compression will not be supported!"

#endif
<commit_msg>JpegDecompressor: ThrowIOE is only needed if not HAVE_JPEG_MEM_SRC<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2017 Roman Lebedev

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifdef HAVE_JPEG

#include "decompressors/JpegDecompressor.h"
#include "common/Common.h"                // for uchar8, uint32, ushort16
#include "common/Memory.h"                // for alignedFree, alignedMalloc...
#include "common/Point.h"                 // for iPoint2D
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "io/ByteStream.h"                // for ByteStream
#include <algorithm>                      // for min
#include <cstdio>                         // for size_t
#include <memory>                         // for unique_ptr
#include <vector>                         // for vector

#ifndef HAVE_JPEG_MEM_SRC
#include "io/IOException.h" // for ThrowIOE
#endif

extern "C" {
#include <jpeglib.h> // for jpeg_source_mgr, jpeg_decompress_struct
// IWYU pragma: no_include <jconfig.h>
// IWYU pragma: no_include <jmorecfg.h>
}

using namespace std;

namespace RawSpeed {

#ifdef HAVE_JPEG_MEM_SRC

#define JPEG_MEMSRC(A, B, C) jpeg_mem_src(A, B, C)

#else

#define JPEG_MEMSRC(A, B, C) jpeg_mem_src_int(A, B, C)
/* Read JPEG image from a memory segment */

static void init_source(j_decompress_ptr cinfo) {}
static boolean fill_input_buffer(j_decompress_ptr cinfo) {
  auto* src = (struct jpeg_source_mgr*)cinfo->src;
  return (boolean) !!src->bytes_in_buffer;
}
static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
  auto* src = (struct jpeg_source_mgr*)cinfo->src;

  if (num_bytes > (int)src->bytes_in_buffer)
    ThrowIOE("JPEG Decoder - read out of buffer");
  if (num_bytes > 0) {
    src->next_input_byte += (size_t)num_bytes;
    src->bytes_in_buffer -= (size_t)num_bytes;
  }
}
static void term_source(j_decompress_ptr cinfo) {}
static void jpeg_mem_src_int(j_decompress_ptr cinfo,
                             const unsigned char* buffer, long nbytes) {
  struct jpeg_source_mgr* src;

  if (cinfo->src == nullptr) { /* first time for this JPEG object? */
    cinfo->src = (struct jpeg_source_mgr*)(*cinfo->mem->alloc_small)(
        (j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(struct jpeg_source_mgr));
  }

  src = (struct jpeg_source_mgr*)cinfo->src;
  src->init_source = init_source;
  src->fill_input_buffer = fill_input_buffer;
  src->skip_input_data = skip_input_data;
  src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
  src->term_source = term_source;
  src->bytes_in_buffer = nbytes;
  src->next_input_byte = (JOCTET*)buffer;
}

#endif

METHODDEF(void)
my_error_throw(j_common_ptr cinfo) { ThrowRDE("JPEG decoder error!"); }

struct JpegDecompressStruct : jpeg_decompress_struct {
  struct jpeg_error_mgr jerr;
  JpegDecompressStruct() {
    jpeg_create_decompress(this);

    err = jpeg_std_error(&jerr);
    jerr.error_exit = my_error_throw;
  }
  ~JpegDecompressStruct() { jpeg_destroy_decompress(this); }
};

void JpegDecompressor::decode(uint32 offX,
                              uint32 offY) { /* Each slice is a JPEG image */
  struct JpegDecompressStruct dinfo;

  vector<JSAMPROW> buffer(1);

  JPEG_MEMSRC(&dinfo, (unsigned char*)input.getData(input.getRemainSize()),
              input.getRemainSize());

  if (JPEG_HEADER_OK != jpeg_read_header(&dinfo, static_cast<boolean>(true)))
    ThrowRDE("JpegDecompressor: Unable to read JPEG header");

  jpeg_start_decompress(&dinfo);
  if (dinfo.output_components != (int)mRaw->getCpp())
    ThrowRDE("JpegDecompressor: Component count doesn't match");
  int row_stride = dinfo.output_width * dinfo.output_components;

  unique_ptr<uchar8[], decltype(&alignedFree)> complete_buffer(
      (uchar8*)alignedMallocArray<16>(dinfo.output_height, row_stride),
      alignedFree);
  while (dinfo.output_scanline < dinfo.output_height) {
    buffer[0] = (JSAMPROW)(
        &complete_buffer[(size_t)dinfo.output_scanline * row_stride]);
    if (0 == jpeg_read_scanlines(&dinfo, &buffer[0], 1))
      ThrowRDE("JpegDecompressor: JPEG Error while decompressing image.");
  }
  jpeg_finish_decompress(&dinfo);

  // Now the image is decoded, and we copy the image data
  int copy_w = min(mRaw->dim.x - offX, dinfo.output_width);
  int copy_h = min(mRaw->dim.y - offY, dinfo.output_height);
  for (int y = 0; y < copy_h; y++) {
    uchar8* src = &complete_buffer[(size_t)row_stride * y];
    auto* dst = (ushort16*)mRaw->getData(offX, y + offY);
    for (int x = 0; x < copy_w; x++) {
      for (int c = 0; c < dinfo.output_components; c++)
        *dst++ = (*src++);
    }
  }
}

} // namespace RawSpeed

#else

#pragma message                                                                \
    "JPEG is not present! Lossy JPEG compression will not be supported!"

#endif
<|endoftext|>


<commit_before>#ifndef ELEKTRA_BASENOTIFICATION_HPP
#define ELEKTRA_BASENOTIFICATION_HPP

#include <string>
#include <key.hpp>
#include <utility>
#include <kdbtypes.h> // for kdb-types, code and description constants

namespace kdb
{
namespace tools
{
namespace errors
{
/* common abstract class for warnings and errors */
/* Because warning and errors share the same data members, a method can accept a ErrBase argument and the caller
 * can create an Error or a Warning based on the provided object. */
class BaseNotification
{
public:
	/* constructor */
	BaseNotification (std::string  reason, std::string  module, std::string  file, std::string mountPoint,
			  std::string configFile, kdb::long_t line);

	/* setters */
	void setData (const std::string & reason, const std::string & module, const std::string & file,
		      const std::string & mountPoint, const std::string & configFile, kdb::long_t line);

	/* get references (for setting and getting member values) */
	std::string & reason();
	std::string & module();
	std::string & file();
	std::string & mountPoint();
	std::string & configFile();
	kdb::long_t & line();
	const std::string & reason () const;
	const std::string & module () const;
	const std::string & file () const;
	const std::string & mountPoint () const;
	const std::string & configFile () const;
	const kdb::long_t & line () const;

	/* fixed values per Class, taken from C-makro definitions in /src/include/kdberrors.h */
	virtual std::string code() const = 0;
	virtual std::string description() const = 0;

	/* string representation */
	friend std::ostream& operator<< (std::ostream& outputStream, const BaseNotification& eb);
	/* compare */

	/**
	 * @brief Compare fields of notification objects
	 *
	 * Also incorporates the compare method to enable subclasses to add constraints to the comparison.
	 *
	 * @param other the notification to compare
	 *
	 * @return true if objects are equal
	 */
	bool operator== (const BaseNotification& other) const;
	bool operator!= (const BaseNotification& other) const;

protected:
	BaseNotification () = default;

	/* Can be overwritten by subclasses to change the text representation */
	std::ostream& toString (std::ostream& outputStream) const;

	/**
	 * @brief Compare to another notification object
	 *
	 * Is used in operator==.
	 * Can be overloaded by subclasses to check additional constraints.
	 * At least the types of the two objects that get compared should be checked for equality!
	 *
	 * @param other the notification to compare to
	 *
	 * @return true if objects are equal
	 */
	virtual bool compare(const BaseNotification& other) const;

private:
	std::string m_reason;
	std::string m_module;
	std::string m_file;
	std::string m_mountPoint;
	std::string m_configFile;
	kdb::long_t m_line = 0;
};

} // namespace errors
} // namespace tools
} // namespace kdb
#endif // ELEKTRA_BASENOTIFICATION_HPP<commit_msg>libtool: remove small unnecassary comment<commit_after>#ifndef ELEKTRA_BASENOTIFICATION_HPP
#define ELEKTRA_BASENOTIFICATION_HPP

#include <string>
#include <key.hpp>
#include <utility>
#include <kdbtypes.h>

namespace kdb
{
namespace tools
{
namespace errors
{
/* common abstract class for warnings and errors */
/* Because warning and errors share the same data members, a method can accept a ErrBase argument and the caller
 * can create an Error or a Warning based on the provided object. */
class BaseNotification
{
public:
	/* constructor */
	BaseNotification (std::string  reason, std::string  module, std::string  file, std::string mountPoint,
			  std::string configFile, kdb::long_t line);

	/* setters */
	void setData (const std::string & reason, const std::string & module, const std::string & file,
		      const std::string & mountPoint, const std::string & configFile, kdb::long_t line);

	/* get references (for setting and getting member values) */
	std::string & reason();
	std::string & module();
	std::string & file();
	std::string & mountPoint();
	std::string & configFile();
	kdb::long_t & line();
	const std::string & reason () const;
	const std::string & module () const;
	const std::string & file () const;
	const std::string & mountPoint () const;
	const std::string & configFile () const;
	const kdb::long_t & line () const;

	/* fixed values per Class, taken from C-makro definitions in /src/include/kdberrors.h */
	virtual std::string code() const = 0;
	virtual std::string description() const = 0;

	/* string representation */
	friend std::ostream& operator<< (std::ostream& outputStream, const BaseNotification& eb);
	/* compare */

	/**
	 * @brief Compare fields of notification objects
	 *
	 * Also incorporates the compare method to enable subclasses to add constraints to the comparison.
	 *
	 * @param other the notification to compare
	 *
	 * @return true if objects are equal
	 */
	bool operator== (const BaseNotification& other) const;
	bool operator!= (const BaseNotification& other) const;

protected:
	BaseNotification () = default;

	/* Can be overwritten by subclasses to change the text representation */
	std::ostream& toString (std::ostream& outputStream) const;

	/**
	 * @brief Compare to another notification object
	 *
	 * Is used in operator==.
	 * Can be overloaded by subclasses to check additional constraints.
	 * At least the types of the two objects that get compared should be checked for equality!
	 *
	 * @param other the notification to compare to
	 *
	 * @return true if objects are equal
	 */
	virtual bool compare(const BaseNotification& other) const;

private:
	std::string m_reason;
	std::string m_module;
	std::string m_file;
	std::string m_mountPoint;
	std::string m_configFile;
	kdb::long_t m_line = 0;
};

} // namespace errors
} // namespace tools
} // namespace kdb
#endif // ELEKTRA_BASENOTIFICATION_HPP
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/document/base/testdocman.h>
#include <vespa/document/fieldset/fieldsetrepo.h>
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <algorithm>
#include <gtest/gtest.h>

using vespalib::nbostream;

namespace document {

class FieldSetTest : public ::testing::Test {

protected:
    std::string stringifyFields(const Document& doc) const;
    std::string doCopyFields(const Document& src,
                             const DocumentTypeRepo& docRepo,
                             const std::string& fieldSetStr,
                             Document* dest = 0) const;
    std::string doCopyDocument(const Document& src,
                               const DocumentTypeRepo& docRepo,
                               const std::string& fieldSetStr);
    std::string doStripFields(const Document& doc,
                              const DocumentTypeRepo& docRepo,
                              const std::string& fieldSetStr);
    Document::UP createTestDocument(const TestDocMan& testDocMan) const;
};

TEST_F(FieldSetTest, testParsing)
{
    TestDocMan testDocMan;
    const DocumentTypeRepo& docRepo = testDocMan.getTypeRepo();

    FieldSetRepo repo;

    (void) dynamic_cast<AllFields&>(*repo.parse(docRepo, AllFields::NAME));
    (void) dynamic_cast<NoFields&>(*repo.parse(docRepo, NoFields::NAME));
    (void) dynamic_cast<DocIdOnly&>(*repo.parse(docRepo, DocIdOnly::NAME));

    FieldSet::UP set = repo.parse(docRepo, "testdoctype1:headerval,content");
    FieldCollection& coll = dynamic_cast<FieldCollection&>(*set);

    std::ostringstream ost;
    for (Field::Set::const_iterator iter = coll.getFields().begin();
         iter != coll.getFields().end();
         ++iter) {
        ost << (*iter)->getName() << " ";
    }

    EXPECT_EQ(std::string("content headerval "), ost.str());
}

namespace {

bool checkContains(FieldSetRepo& r, const DocumentTypeRepo& repo,
                   const std::string& str1, const std::string str2) {
    FieldSet::UP set1 = r.parse(repo, str1);
    FieldSet::UP set2 = r.parse(repo, str2);

    return set1->contains(*set2);
}

bool checkError(FieldSetRepo& r, const DocumentTypeRepo& repo,
                const std::string& str) {
    try {
        r.parse(repo, str);
        return false;
    } catch (...) {
        return true;
    }
}

}

TEST_F(FieldSetTest, testContains)
{
    TestDocMan testDocMan;
    const DocumentTypeRepo& repo = testDocMan.getTypeRepo();
    const DocumentType& type = *repo.getDocumentType("testdoctype1");

    const Field& headerField = type.getField("headerval");

    NoFields none;
    AllFields all;
    DocIdOnly id;

    EXPECT_EQ(false, headerField.contains(type.getField("headerlongval")));
    EXPECT_EQ(true, headerField.contains(headerField));
    EXPECT_EQ(true, headerField.contains(id));
    EXPECT_EQ(false, headerField.contains(all));
    EXPECT_EQ(true, headerField.contains(none));
    EXPECT_EQ(false, none.contains(headerField));
    EXPECT_EQ(true, all.contains(headerField));
    EXPECT_EQ(true, all.contains(none));
    EXPECT_EQ(false, none.contains(all));
    EXPECT_EQ(true, all.contains(id));
    EXPECT_EQ(false, none.contains(id));
    EXPECT_EQ(true, id.contains(none));

    FieldSetRepo r;
    EXPECT_EQ(true, checkContains(r, repo,
                                             "testdoctype1:content,headerval",
                                             "testdoctype1:content"));
    EXPECT_EQ(false, checkContains(r, repo,
                                              "testdoctype1:content",
                                              "testdoctype1:content,headerval"));
    EXPECT_EQ(true, checkContains(r, repo,
                                             "testdoctype1:headerval,content",
                                             "testdoctype1:content,headerval"));

    EXPECT_TRUE(checkError(r, repo, "nodoctype"));
    EXPECT_TRUE(checkError(r, repo, "unknowndoctype:foo"));
    EXPECT_TRUE(checkError(r, repo, "testdoctype1:unknownfield"));
    EXPECT_TRUE(checkError(r, repo, "[badid]"));
}

std::string
FieldSetTest::stringifyFields(const Document& doc) const
{
    std::vector<std::string> output;
    const StructFieldValue& fields(doc.getFields());
    for (StructFieldValue::const_iterator
             it(fields.begin()), e(fields.end());
         it != e; ++it)
    {
        std::ostringstream ss;
        const Field& f(it.field());
        ss << f.getName() << ": ";
        FieldValue::UP val(fields.getValue(f));
        if (val.get()) {
            ss << val->toString();
        } else {
            ss << "(null)";
        }
        output.push_back(ss.str());
    }
    std::ostringstream ret;
    std::sort(output.begin(), output.end());
    std::copy(output.begin(), output.end(),
              std::ostream_iterator<std::string>(ret, "\n"));
    return ret.str();
}

std::string
FieldSetTest::doCopyFields(const Document& src,
                           const DocumentTypeRepo& docRepo,
                           const std::string& fieldSetStr,
                           Document* dest) const
{
    Document destDoc(src.getType(), DocumentId("id:ns:" + src.getType().getName() + "::fieldset"));
    if (!dest) {
        dest = &destDoc;
    }
    FieldSetRepo repo;
    FieldSet::UP fset = repo.parse(docRepo, fieldSetStr);
    FieldSet::copyFields(*dest, src, *fset);
    return stringifyFields(*dest);
}

std::string
FieldSetTest::doStripFields(const Document& doc,
                            const DocumentTypeRepo& docRepo,
                            const std::string& fieldSetStr)
{
    Document::UP copy(doc.clone());
    FieldSetRepo repo;
    FieldSet::UP fset = repo.parse(docRepo, fieldSetStr);
    FieldSet::stripFields(*copy, *fset);
    return stringifyFields(*copy);
}

Document::UP
FieldSetTest::createTestDocument(const TestDocMan& testDocMan) const
{
    Document::UP doc(testDocMan.createDocument("megafoo megabar",
                                               "id:ns:testdoctype1::1",
                                               "testdoctype1"));
    doc->setValue(doc->getField("headerval"), IntFieldValue(5678));
    doc->setValue(doc->getField("hstringval"),
                  StringFieldValue("hello fantastic world"));
    return doc;
}

TEST_F(FieldSetTest, testCopyDocumentFields)
{
    TestDocMan testDocMan;
    const DocumentTypeRepo& repo = testDocMan.getTypeRepo();
    Document::UP src(createTestDocument(testDocMan));

    EXPECT_EQ(std::string(""),
              doCopyFields(*src, repo, NoFields::NAME));
    EXPECT_EQ(std::string("content: megafoo megabar\n"
                          "headerval: 5678\n"
                          "hstringval: hello fantastic world\n"),
              doCopyFields(*src, repo, AllFields::NAME));
    EXPECT_EQ(std::string("content: megafoo megabar\n"
                          "hstringval: hello fantastic world\n"),
              doCopyFields(*src, repo, "testdoctype1:hstringval,content"));
    // Test that we overwrite already set fields in destination document
    {
        Document dest(src->getType(), DocumentId("id:ns:" + src->getType().getName() + "::bar"));
        dest.setValue(dest.getField("content"), StringFieldValue("overwriteme"));
        EXPECT_EQ(std::string("content: megafoo megabar\n"),
                  doCopyFields(*src, repo, src->getType().getName() + ":content", &dest));
    }
}

std::string
FieldSetTest::doCopyDocument(const Document& src,
                             const DocumentTypeRepo& docRepo,
                             const std::string& fieldSetStr)
{
    FieldSetRepo repo;
    FieldSet::UP fset = repo.parse(docRepo, fieldSetStr);
    Document::UP doc(FieldSet::createDocumentSubsetCopy(src, *fset));
    return stringifyFields(*doc);
}

TEST_F(FieldSetTest, testDocumentSubsetCopy)
{
    TestDocMan testDocMan;
    const DocumentTypeRepo& repo = testDocMan.getTypeRepo();
    Document::UP src(createTestDocument(testDocMan));

    {
        Document::UP doc(FieldSet::createDocumentSubsetCopy(*src, AllFields()));
        // Test that document id and type are copied correctly.
        EXPECT_TRUE(doc.get());
        EXPECT_EQ(src->getId(), doc->getId());
        EXPECT_EQ(src->getType(), doc->getType());
        EXPECT_EQ(doCopyFields(*src, repo, AllFields::NAME),
                  stringifyFields(*doc));
    }

    const char* fieldSets[] = {
        AllFields::NAME,
        NoFields::NAME,
        "testdoctype1:hstringval,content"
    };
    for (size_t i = 0; i < sizeof(fieldSets) / sizeof(fieldSets[0]); ++i) {
        EXPECT_EQ(doCopyFields(*src, repo, fieldSets[i]),
                  doCopyDocument(*src, repo, fieldSets[i]));
    }
}

TEST_F(FieldSetTest, testSerialize)
{
    TestDocMan testDocMan;
    const DocumentTypeRepo& docRepo = testDocMan.getTypeRepo();

    const char* fieldSets[] = {
        AllFields::NAME,
        NoFields::NAME,
        DocIdOnly::NAME,
        "testdoctype1:content",
        "testdoctype1:content,hstringval"
    };

    FieldSetRepo repo;
    for (size_t i = 0; i < sizeof(fieldSets) / sizeof(fieldSets[0]); ++i) {
        FieldSet::UP fs = repo.parse(docRepo, fieldSets[i]);
        EXPECT_EQ(vespalib::string(fieldSets[i]), repo.serialize(*fs));
    }
}

TEST_F(FieldSetTest, testStripFields)
{
    TestDocMan testDocMan;
    const DocumentTypeRepo& repo = testDocMan.getTypeRepo();
    Document::UP src(createTestDocument(testDocMan));

    EXPECT_EQ(std::string(""),
              doStripFields(*src, repo, NoFields::NAME));
    EXPECT_EQ(std::string(""),
              doStripFields(*src, repo, DocIdOnly::NAME));
    EXPECT_EQ(std::string("content: megafoo megabar\n"
                          "headerval: 5678\n"
                          "hstringval: hello fantastic world\n"),
              doStripFields(*src, repo, AllFields::NAME));
    EXPECT_EQ(std::string("content: megafoo megabar\n"
                          "hstringval: hello fantastic world\n"),
              doStripFields(*src, repo, "testdoctype1:hstringval,content"));
}

TEST(FieldCollectionTest, testHash ) {
    TestDocMan testDocMan;
    const DocumentTypeRepo& repo = testDocMan.getTypeRepo();
    const DocumentType & type = *repo.getDocumentType("testdoctype1");
    Field::Set set;
    EXPECT_EQ(0ul, FieldCollection(type, set).hash());
    set.insert(&type.getField("headerval"));
    EXPECT_EQ(0x548599858c77ef83ul, FieldCollection(type, set).hash());
    set.insert(&type.getField("hstringval"));
    EXPECT_EQ(0x4a7ff2406d36a9b0ul, FieldCollection(type, set).hash());
    set.erase(&type.getField("headerval"));
    EXPECT_EQ(0x1e0918531b19734ul, FieldCollection(type, set).hash());
}

} // document
<commit_msg>Follow clion advise<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/document/base/testdocman.h>
#include <vespa/document/fieldset/fieldsetrepo.h>
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <algorithm>
#include <gtest/gtest.h>

using vespalib::nbostream;

namespace document {

class FieldSetTest : public ::testing::Test {

protected:
    static std::string stringifyFields(const Document& doc);
    static std::string doCopyFields(const Document& src, const DocumentTypeRepo& docRepo,
                                    const std::string& fieldSetStr,Document* dest = nullptr);
    static std::string doCopyDocument(const Document& src, const DocumentTypeRepo& docRepo, const std::string& fieldSetStr);
    static std::string doStripFields(const Document& doc, const DocumentTypeRepo& docRepo, const std::string& fieldSetStr);
    static Document::UP createTestDocument(const TestDocMan& testDocMan);
};

TEST_F(FieldSetTest, testParsing)
{
    TestDocMan testDocMan;
    const DocumentTypeRepo& docRepo = testDocMan.getTypeRepo();

    (void) dynamic_cast<AllFields&>(*FieldSetRepo::parse(docRepo, AllFields::NAME));
    (void) dynamic_cast<NoFields&>(*FieldSetRepo::parse(docRepo, NoFields::NAME));
    (void) dynamic_cast<DocIdOnly&>(*FieldSetRepo::parse(docRepo, DocIdOnly::NAME));

    FieldSet::UP set = FieldSetRepo::parse(docRepo, "testdoctype1:headerval,content");
    auto & coll = dynamic_cast<FieldCollection&>(*set);

    std::ostringstream ost;
    for (const Field * field : coll.getFields()) {
        ost << field->getName() << " ";
    }

    EXPECT_EQ(std::string("content headerval "), ost.str());
}

namespace {

bool checkContains(const DocumentTypeRepo& repo,
                   const std::string& str1, const std::string & str2) {
    FieldSet::UP set1 = FieldSetRepo::parse(repo, str1);
    FieldSet::UP set2 = FieldSetRepo::parse(repo, str2);

    return set1->contains(*set2);
}

bool checkError(const DocumentTypeRepo& repo, const std::string& str) {
    try {
        FieldSetRepo::parse(repo, str);
        return false;
    } catch (...) {
        return true;
    }
}

}

TEST_F(FieldSetTest, testContains)
{
    TestDocMan testDocMan;
    const DocumentTypeRepo& repo = testDocMan.getTypeRepo();
    const DocumentType& type = *repo.getDocumentType("testdoctype1");

    const Field& headerField = type.getField("headerval");

    NoFields none;
    AllFields all;
    DocIdOnly id;

    EXPECT_EQ(false, headerField.contains(type.getField("headerlongval")));
    EXPECT_EQ(true, headerField.contains(headerField));
    EXPECT_EQ(true, headerField.contains(id));
    EXPECT_EQ(false, headerField.contains(all));
    EXPECT_EQ(true, headerField.contains(none));
    EXPECT_EQ(false, none.contains(headerField));
    EXPECT_EQ(true, all.contains(headerField));
    EXPECT_EQ(true, all.contains(none));
    EXPECT_EQ(false, none.contains(all));
    EXPECT_EQ(true, all.contains(id));
    EXPECT_EQ(false, none.contains(id));
    EXPECT_EQ(true, id.contains(none));

    EXPECT_EQ(true, checkContains(repo,
                                             "testdoctype1:content,headerval",
                                             "testdoctype1:content"));
    EXPECT_EQ(false, checkContains(repo,
                                              "testdoctype1:content",
                                              "testdoctype1:content,headerval"));
    EXPECT_EQ(true, checkContains(repo,
                                             "testdoctype1:headerval,content",
                                             "testdoctype1:content,headerval"));

    EXPECT_TRUE(checkError(repo, "nodoctype"));
    EXPECT_TRUE(checkError(repo, "unknowndoctype:foo"));
    EXPECT_TRUE(checkError(repo, "testdoctype1:unknownfield"));
    EXPECT_TRUE(checkError(repo, "[badid]"));
}

std::string
FieldSetTest::stringifyFields(const Document& doc)
{
    std::vector<std::string> output;
    const StructFieldValue& fields(doc.getFields());
    for (StructFieldValue::const_iterator
             it(fields.begin()), e(fields.end());
         it != e; ++it)
    {
        std::ostringstream ss;
        const Field& f(it.field());
        ss << f.getName() << ": ";
        FieldValue::UP val(fields.getValue(f));
        if (val.get()) {
            ss << val->toString();
        } else {
            ss << "(null)";
        }
        output.push_back(ss.str());
    }
    std::ostringstream ret;
    std::sort(output.begin(), output.end());
    std::copy(output.begin(), output.end(),
              std::ostream_iterator<std::string>(ret, "\n"));
    return ret.str();
}

std::string
FieldSetTest::doCopyFields(const Document& src,
                           const DocumentTypeRepo& docRepo,
                           const std::string& fieldSetStr,
                           Document* dest)
{
    Document destDoc(src.getType(), DocumentId("id:ns:" + src.getType().getName() + "::fieldset"));
    if (!dest) {
        dest = &destDoc;
    }
    FieldSet::UP fset = FieldSetRepo::parse(docRepo, fieldSetStr);
    FieldSet::copyFields(*dest, src, *fset);
    return stringifyFields(*dest);
}

std::string
FieldSetTest::doStripFields(const Document& doc,
                            const DocumentTypeRepo& docRepo,
                            const std::string& fieldSetStr)
{
    Document::UP copy(doc.clone());
    FieldSet::UP fset = FieldSetRepo::parse(docRepo, fieldSetStr);
    FieldSet::stripFields(*copy, *fset);
    return stringifyFields(*copy);
}

Document::UP
FieldSetTest::createTestDocument(const TestDocMan& testDocMan)
{
    Document::UP doc(testDocMan.createDocument("megafoo megabar",
                                               "id:ns:testdoctype1::1",
                                               "testdoctype1"));
    doc->setValue(doc->getField("headerval"), IntFieldValue(5678));
    doc->setValue(doc->getField("hstringval"),
                  StringFieldValue("hello fantastic world"));
    return doc;
}

TEST_F(FieldSetTest, testCopyDocumentFields)
{
    TestDocMan testDocMan;
    const DocumentTypeRepo& repo = testDocMan.getTypeRepo();
    Document::UP src(createTestDocument(testDocMan));

    EXPECT_EQ(std::string(""),
              doCopyFields(*src, repo, NoFields::NAME));
    EXPECT_EQ(std::string("content: megafoo megabar\n"
                          "headerval: 5678\n"
                          "hstringval: hello fantastic world\n"),
              doCopyFields(*src, repo, AllFields::NAME));
    EXPECT_EQ(std::string("content: megafoo megabar\n"
                          "hstringval: hello fantastic world\n"),
              doCopyFields(*src, repo, "testdoctype1:hstringval,content"));
    // Test that we overwrite already set fields in destination document
    {
        Document dest(src->getType(), DocumentId("id:ns:" + src->getType().getName() + "::bar"));
        dest.setValue(dest.getField("content"), StringFieldValue("overwriteme"));
        EXPECT_EQ(std::string("content: megafoo megabar\n"),
                  doCopyFields(*src, repo, src->getType().getName() + ":content", &dest));
    }
}

std::string
FieldSetTest::doCopyDocument(const Document& src,
                             const DocumentTypeRepo& docRepo,
                             const std::string& fieldSetStr)
{
    FieldSet::UP fset = FieldSetRepo::parse(docRepo, fieldSetStr);
    Document::UP doc(FieldSet::createDocumentSubsetCopy(src, *fset));
    return stringifyFields(*doc);
}

TEST_F(FieldSetTest, testDocumentSubsetCopy)
{
    TestDocMan testDocMan;
    const DocumentTypeRepo& repo = testDocMan.getTypeRepo();
    Document::UP src(createTestDocument(testDocMan));

    {
        Document::UP doc(FieldSet::createDocumentSubsetCopy(*src, AllFields()));
        // Test that document id and type are copied correctly.
        EXPECT_TRUE(doc.get());
        EXPECT_EQ(src->getId(), doc->getId());
        EXPECT_EQ(src->getType(), doc->getType());
        EXPECT_EQ(doCopyFields(*src, repo, AllFields::NAME),
                  stringifyFields(*doc));
    }

    const char* fieldSets[] = {
        AllFields::NAME,
        NoFields::NAME,
        "testdoctype1:hstringval,content"
    };
    for (const char * fieldSet : fieldSets) {
        EXPECT_EQ(doCopyFields(*src, repo, fieldSet),
                  doCopyDocument(*src, repo, fieldSet));
    }
}

TEST_F(FieldSetTest, testSerialize)
{
    TestDocMan testDocMan;
    const DocumentTypeRepo& docRepo = testDocMan.getTypeRepo();

    const char* fieldSets[] = {
        AllFields::NAME,
        NoFields::NAME,
        DocIdOnly::NAME,
        "testdoctype1:content",
        "testdoctype1:content,hstringval"
    };

    FieldSetRepo repo;
    for (const char * fieldSet : fieldSets) {
        FieldSet::UP fs = FieldSetRepo::parse(docRepo, fieldSet);
        EXPECT_EQ(vespalib::string(fieldSet), repo.serialize(*fs));
    }
}

TEST_F(FieldSetTest, testStripFields)
{
    TestDocMan testDocMan;
    const DocumentTypeRepo& repo = testDocMan.getTypeRepo();
    Document::UP src(createTestDocument(testDocMan));

    EXPECT_EQ(std::string(""),
              doStripFields(*src, repo, NoFields::NAME));
    EXPECT_EQ(std::string(""),
              doStripFields(*src, repo, DocIdOnly::NAME));
    EXPECT_EQ(std::string("content: megafoo megabar\n"
                          "headerval: 5678\n"
                          "hstringval: hello fantastic world\n"),
              doStripFields(*src, repo, AllFields::NAME));
    EXPECT_EQ(std::string("content: megafoo megabar\n"
                          "hstringval: hello fantastic world\n"),
              doStripFields(*src, repo, "testdoctype1:hstringval,content"));
}

TEST(FieldCollectionTest, testHash ) {
    TestDocMan testDocMan;
    const DocumentTypeRepo& repo = testDocMan.getTypeRepo();
    const DocumentType & type = *repo.getDocumentType("testdoctype1");
    Field::Set set;
    EXPECT_EQ(0ul, FieldCollection(type, set).hash());
    set.insert(&type.getField("headerval"));
    EXPECT_EQ(0x548599858c77ef83ul, FieldCollection(type, set).hash());
    set.insert(&type.getField("hstringval"));
    EXPECT_EQ(0x4a7ff2406d36a9b0ul, FieldCollection(type, set).hash());
    set.erase(&type.getField("headerval"));
    EXPECT_EQ(0x1e0918531b19734ul, FieldCollection(type, set).hash());
}

} // document
<|endoftext|>


<commit_before>
#include "LCMSystem.h"
#include "RigidBodySystem.h"
#include "LinearSystem.h"
#include "BotVisualizer.h"
#include "drakeAppUtil.h"
#include "lcmtypes/drake/lcmt_driving_control_cmd_t.hpp"

using namespace std;
using namespace Eigen;
using namespace Drake;

template <typename ScalarType = double>
class DrivingCommand {
public:
  typedef drake::lcmt_driving_control_cmd_t LCMMessageType;
  static std::string channel() { return "DRIVING_COMMAND"; };

  DrivingCommand(void) : throttle(0), brake(0), steering_angle(0) {};
  template <typename Derived>
  DrivingCommand(const Eigen::MatrixBase<Derived>& x) : steering_angle(x(0)), throttle(x(1)), brake(x(2)) {};

  template <typename Derived>
  DrivingCommand& operator=(const Eigen::MatrixBase<Derived>& x) {
    steering_angle = x(0);
    throttle = x(1);
    brake = x(2);
    return *this;
  }

  friend Eigen::Vector3d toEigen(const DrivingCommand<ScalarType>& vec) {
    Eigen::Vector3d x;
    x << vec.steering_angle, vec.throttle, vec.brake;
    return x;
  }

  friend std::string getCoordinateName(const DrivingCommand<ScalarType>& vec, unsigned int index) {
    switch (index) {
      case 0: return "steering_angle";
      case 1: return "throttle";
      case 2: return "brake";
    }
    return "error";
  }
  const static int RowsAtCompileTime = 3;

  ScalarType steering_angle;
  ScalarType throttle;
  ScalarType brake;
};

bool decode(const drake::lcmt_driving_control_cmd_t& msg, double& t, DrivingCommand<double>& x) {
  t = double(msg.timestamp)/1000.0;
  x.steering_angle = msg.steering_angle;
  x.throttle = msg.throttle_value;
  x.brake = msg.brake_value;
  return true;
}

/** Driving Simulator
 * Usage:  simulateLCM vehicle_urdf [world_urdf files ...]
 */

int main(int argc, char* argv[]) {
  if (argc < 2) {
    std::cerr << "Usage: " << argv[0] << " vehicle_urdf [world_urdf files ...]" << std::endl;
    return 1;
  }

  // todo: consider moving this logic into the RigidBodySystem class so it can be reused
  DrakeJoint::FloatingBaseType floating_base_type = DrakeJoint::QUATERNION;

  auto rigid_body_sys = make_shared<RigidBodySystem>(argv[1],floating_base_type);
  auto const & tree = rigid_body_sys->getRigidBodyTree();
  for (int i=2; i<argc; i++)
    tree->addRobotFromURDF(argv[i],DrakeJoint::FIXED);  // add environment

  { // add flat terrain
    double box_width = 1000;
    double box_depth = 10;
    DrakeShapes::Box geom(Vector3d(box_width, box_width, box_depth));
    Isometry3d T_element_to_link = Isometry3d::Identity();
    T_element_to_link.translation() << 0,0,-box_depth/2;  // top of the box is at z=0
    auto & world = tree->bodies[0];
    Vector4d color;  color <<  0.9297, 0.7930, 0.6758, 1;  // was hex2dec({'ee','cb','ad'})'/256 in matlab
    world->addVisualElement(DrakeShapes::VisualElement(geom,T_element_to_link,color));
    tree->addCollisionElement(RigidBody::CollisionElement(geom,T_element_to_link,world),world,"terrain");
    tree->updateStaticCollisionElements();
  }

  shared_ptr<lcm::LCM> lcm = make_shared<lcm::LCM>();

  MatrixXd Kp(getNumInputs(*rigid_body_sys),tree->num_positions),
      Kd(getNumInputs(*rigid_body_sys),tree->num_velocities);
  Matrix<double,Eigen::Dynamic,3> map_driving_cmd_to_x_d(tree->num_positions+tree->num_velocities,3);
  { // setup PD controller for throttle and steering
    double kpSteering = 100, kdSteering = 20, kThrottle = 100;
    Kp.setZero();
    Kd.setZero();
    map_driving_cmd_to_x_d.setZero();

    for (int actuator_idx=0; actuator_idx<tree->actuators.size(); actuator_idx++) {
      if (strcmp(tree->actuators[actuator_idx].name.c_str(),"steering_angle")==0) {
        auto const &b = tree->actuators[actuator_idx].body;
        Kp(actuator_idx,b->position_num_start) = kpSteering;   // steering
        Kd(actuator_idx,b->velocity_num_start) = kdSteering;   // steeringdot
        map_driving_cmd_to_x_d(b->position_num_start,0) = 1;   // steering command
      } else if (strncmp(tree->actuators[actuator_idx].name.c_str(),"throttle",8)==0) { // intentionally match all throttle_ inputs
        auto const &b = tree->actuators[actuator_idx].body;
        Kd(actuator_idx,b->velocity_num_start) = kThrottle;   // throttle
        map_driving_cmd_to_x_d(tree->num_positions+b->velocity_num_start,1) = 20;  // throttle (velocity) command
        map_driving_cmd_to_x_d(tree->num_positions+b->velocity_num_start,2) = -20; // braking (velocity) command
      }
    }
    }
  auto vehicle_with_pd = make_shared<PDControlSystem<RigidBodySystem>>(rigid_body_sys,Kp,Kd);
  auto vehicle_sys = cascade(make_shared<Gain<DrivingCommand,PDControlSystem<RigidBodySystem>::InputVector>>(map_driving_cmd_to_x_d),vehicle_with_pd);
  auto visualizer = make_shared<BotVisualizer<RigidBodySystem::StateVector>>(lcm,tree);
  auto sys = cascade(vehicle_sys, visualizer);

  SimulationOptions options = default_simulation_options;
  rigid_body_sys->penetration_stiffness = 5000.0;
  rigid_body_sys->penetration_damping = rigid_body_sys->penetration_stiffness/10.0;
  options.initial_step_size = 5e-3;
  options.timeout_seconds = numeric_limits<double>::infinity();

  VectorXd x0(rigid_body_sys->getNumStates());
  x0.head(tree->num_positions) = tree->getZeroConfiguration();
  // todo:  call getInitialState instead?  (but currently, that would require snopt).  needs #1627
  // I'm getting away without it, but might be generating large internal forces initially as the ackerman constraint (hopefully) gets enforced by the stabilization terms.

  runLCM(sys,lcm,0,std::numeric_limits<double>::infinity(),x0,options);
//  simulate(*sys,0,std::numeric_limits<double>::infinity(),x0,options);

  return 0;
}
<commit_msg>Increased steering PD controller strength to counteract straightening forces from front wheel drive<commit_after>
#include "LCMSystem.h"
#include "RigidBodySystem.h"
#include "LinearSystem.h"
#include "BotVisualizer.h"
#include "drakeAppUtil.h"
#include "lcmtypes/drake/lcmt_driving_control_cmd_t.hpp"

using namespace std;
using namespace Eigen;
using namespace Drake;

template <typename ScalarType = double>
class DrivingCommand {
public:
  typedef drake::lcmt_driving_control_cmd_t LCMMessageType;
  static std::string channel() { return "DRIVING_COMMAND"; };

  DrivingCommand(void) : throttle(0), brake(0), steering_angle(0) {};
  template <typename Derived>
  DrivingCommand(const Eigen::MatrixBase<Derived>& x) : steering_angle(x(0)), throttle(x(1)), brake(x(2)) {};

  template <typename Derived>
  DrivingCommand& operator=(const Eigen::MatrixBase<Derived>& x) {
    steering_angle = x(0);
    throttle = x(1);
    brake = x(2);
    return *this;
  }

  friend Eigen::Vector3d toEigen(const DrivingCommand<ScalarType>& vec) {
    Eigen::Vector3d x;
    x << vec.steering_angle, vec.throttle, vec.brake;
    return x;
  }

  friend std::string getCoordinateName(const DrivingCommand<ScalarType>& vec, unsigned int index) {
    switch (index) {
      case 0: return "steering_angle";
      case 1: return "throttle";
      case 2: return "brake";
    }
    return "error";
  }
  const static int RowsAtCompileTime = 3;

  ScalarType steering_angle;
  ScalarType throttle;
  ScalarType brake;
};

bool decode(const drake::lcmt_driving_control_cmd_t& msg, double& t, DrivingCommand<double>& x) {
  t = double(msg.timestamp)/1000.0;
  x.steering_angle = msg.steering_angle;
  x.throttle = msg.throttle_value;
  x.brake = msg.brake_value;
  return true;
}

/** Driving Simulator
 * Usage:  simulateLCM vehicle_urdf [world_urdf files ...]
 */

int main(int argc, char* argv[]) {
  if (argc < 2) {
    std::cerr << "Usage: " << argv[0] << " vehicle_urdf [world_urdf files ...]" << std::endl;
    return 1;
  }

  // todo: consider moving this logic into the RigidBodySystem class so it can be reused
  DrakeJoint::FloatingBaseType floating_base_type = DrakeJoint::QUATERNION;

  auto rigid_body_sys = make_shared<RigidBodySystem>(argv[1],floating_base_type);
  auto const & tree = rigid_body_sys->getRigidBodyTree();
  for (int i=2; i<argc; i++)
    tree->addRobotFromURDF(argv[i],DrakeJoint::FIXED);  // add environment

  if (argc < 2)
  { // add flat terrain
    double box_width = 1000;
    double box_depth = 10;
    DrakeShapes::Box geom(Vector3d(box_width, box_width, box_depth));
    Isometry3d T_element_to_link = Isometry3d::Identity();
    T_element_to_link.translation() << 0,0,-box_depth/2;  // top of the box is at z=0
    auto & world = tree->bodies[0];
    Vector4d color;  color <<  0.9297, 0.7930, 0.6758, 1;  // was hex2dec({'ee','cb','ad'})'/256 in matlab
    world->addVisualElement(DrakeShapes::VisualElement(geom,T_element_to_link,color));
    tree->addCollisionElement(RigidBody::CollisionElement(geom,T_element_to_link,world),world,"terrain");
    tree->updateStaticCollisionElements();
  }

  shared_ptr<lcm::LCM> lcm = make_shared<lcm::LCM>();

  MatrixXd Kp(getNumInputs(*rigid_body_sys),tree->num_positions),
      Kd(getNumInputs(*rigid_body_sys),tree->num_velocities);
  Matrix<double,Eigen::Dynamic,3> map_driving_cmd_to_x_d(tree->num_positions+tree->num_velocities,3);
  { // setup PD controller for throttle and steering
    double kpSteering = 400, kdSteering = 80, kThrottle = 100;
    Kp.setZero();
    Kd.setZero();
    map_driving_cmd_to_x_d.setZero();

    for (int actuator_idx=0; actuator_idx<tree->actuators.size(); actuator_idx++) {
      if (strcmp(tree->actuators[actuator_idx].name.c_str(),"steering_angle")==0) {
        auto const &b = tree->actuators[actuator_idx].body;
        Kp(actuator_idx,b->position_num_start) = kpSteering;   // steering
        Kd(actuator_idx,b->velocity_num_start) = kdSteering;   // steeringdot
        map_driving_cmd_to_x_d(b->position_num_start,0) = 1;   // steering command
      } else if (strncmp(tree->actuators[actuator_idx].name.c_str(),"throttle",8)==0) { // intentionally match all throttle_ inputs
        auto const &b = tree->actuators[actuator_idx].body;
        Kd(actuator_idx,b->velocity_num_start) = kThrottle;   // throttle
        map_driving_cmd_to_x_d(tree->num_positions+b->velocity_num_start,1) = 20;  // throttle (velocity) command
        map_driving_cmd_to_x_d(tree->num_positions+b->velocity_num_start,2) = -20; // braking (velocity) command
      }
    }
    }
  auto vehicle_with_pd = make_shared<PDControlSystem<RigidBodySystem>>(rigid_body_sys,Kp,Kd);
  auto vehicle_sys = cascade(make_shared<Gain<DrivingCommand,PDControlSystem<RigidBodySystem>::InputVector>>(map_driving_cmd_to_x_d),vehicle_with_pd);
  auto visualizer = make_shared<BotVisualizer<RigidBodySystem::StateVector>>(lcm,tree);
  auto sys = cascade(vehicle_sys, visualizer);

  SimulationOptions options = default_simulation_options;
  rigid_body_sys->penetration_stiffness = 5000.0;
  rigid_body_sys->penetration_damping = rigid_body_sys->penetration_stiffness/10.0;
  options.initial_step_size = 5e-3;
  options.timeout_seconds = numeric_limits<double>::infinity();

  VectorXd x0(rigid_body_sys->getNumStates());
  x0.head(tree->num_positions) = tree->getZeroConfiguration();
  // todo:  call getInitialState instead?  (but currently, that would require snopt).  needs #1627
  // I'm getting away without it, but might be generating large internal forces initially as the ackerman constraint (hopefully) gets enforced by the stabilization terms.

  runLCM(sys,lcm,0,std::numeric_limits<double>::infinity(),x0,options);
//  simulate(*sys,0,std::numeric_limits<double>::infinity(),x0,options);

  return 0;
}
<|endoftext|>


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

#include "CppUTest/TestHarness.h"
#include "CppUTest/JUnitTestOutput.h"
#include "CppUTest/TestResult.h"
#include "CppUTest/PlatformSpecificFunctions.h"

static long millisTime;

static const char* theTime = "1978-10-03T00:00:00";

static long MockGetPlatformSpecificTimeInMillis()
{
	return millisTime;
}

static const char* MockGetPlatformSpecificTimeString()
{
	return theTime;
}

TEST_GROUP(JUnitOutputTest)
{
	class MockJUnitTestOutput: public JUnitTestOutput
	{
	public:
		enum
		{
			testGroupSize = 10
		};
		enum
		{
			defaultSize = 7
		};

		int filesOpened;
		int fileBalance;

		SimpleString fileName_;
		SimpleString buffer_;

		TestResult* res_;
		struct TestData
		{
			TestData() :
				tst_(0), testName_(0), failure_(0)
			{
			}
			;
			UtestShell* tst_;
			SimpleString* testName_;
			TestFailure* failure_;
		};

		struct TestGroupData
		{
			TestGroupData() :
				numberTests_(0), totalFailures_(0), name_(""), testData_(0)
			{
			}
			;

			int numberTests_;
			int totalFailures_;
			SimpleString name_;

			TestData* testData_;
		};

		TestGroupData testGroupData_[testGroupSize];

		TestGroupData& currentGroup()
		{
			return testGroupData_[filesOpened - 1];
		}

		void resetXmlFile()
		{
			buffer_ = "";
		}

		MockJUnitTestOutput() :
			filesOpened(0), fileBalance(0), res_(0)
		{
			for (int i = 0; i < testGroupSize; i++) {
				testGroupData_[i].numberTests_ = 0;
				testGroupData_[i].totalFailures_ = 0;
			}
		}
		;

		void setResult(TestResult* testRes)
		{
			res_ = testRes;
		}

		virtual ~MockJUnitTestOutput()
		{
			for (int i = 0; i < testGroupSize; i++) {
				for (int j = 0; j < testGroupData_[i].numberTests_; j++) {
					delete testGroupData_[i].testData_[j].tst_;
					delete testGroupData_[i].testData_[j].testName_;
					if (testGroupData_[i].testData_[j].failure_) delete testGroupData_[i].testData_[j].failure_;
				}
				if (testGroupData_[i].testData_) delete[] testGroupData_[i].testData_;
			}

			LONGS_EQUAL(0, fileBalance);
		}

		void writeToFile(const SimpleString& buf)
		{
			buffer_ += buf;
		}

		void openFileForWrite(const SimpleString& in_FileName)
		{
			filesOpened++;
			fileBalance++;
			fileName_ = in_FileName;
		}

		void closeFile()
		{
			CHECK_XML_FILE();
			resetXmlFile();
			fileBalance--;
		}

		void createTestsInGroup(int index, int amount, const char* group, const char* basename)
		{
			testGroupData_[index].name_ = group;
			testGroupData_[index].numberTests_ = amount;

			testGroupData_[index].testData_ = new TestData[amount];
			for (int i = 0; i < amount; i++) {
				TestData& testData = testGroupData_[index].testData_[i];
				testData.testName_ = new SimpleString(basename);
				*testData.testName_ += StringFrom((long) i);
				testData.tst_ = new UtestShell(group, testData.testName_->asCharString(), "file", 1);
			}
		}
		void runTests()
		{
			res_->testsStarted();
			for (int i = 0; i < testGroupSize; i++) {
				TestGroupData& data = testGroupData_[i];
				if (data.numberTests_ == 0) continue;

				millisTime = 0;
				res_->currentGroupStarted(data.testData_[0].tst_);
				for (int j = 0; j < data.numberTests_; j++) {
					TestData& testData = data.testData_[j];

					millisTime = 0;
					res_->currentTestStarted(testData.tst_);
					if (testData.failure_) print(*testData.failure_);
					millisTime = 10;
					res_->currentTestEnded(testData.tst_);
				}
				millisTime = 50;
				res_->currentGroupEnded(data.testData_[0].tst_);
			}
			res_->testsEnded();
		}

		void setFailure(int groupIndex, int testIndex, const char* fileName, int lineNumber, const char* message)
		{
			TestData& data = testGroupData_[groupIndex].testData_[testIndex];
			data.failure_ = new TestFailure(data.tst_, fileName, lineNumber, message);
			testGroupData_[groupIndex].totalFailures_++;
		}

		void CHECK_HAS_XML_HEADER(SimpleString string)
		{
			STRCMP_EQUAL("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n", string.asCharString());
		}

		void CHECK_TEST_SUITE_START(SimpleString output)
		{
			TestGroupData& group = currentGroup();
			SimpleString buf = StringFromFormat("<testsuite errors=\"0\" failures=\"%d\" hostname=\"localhost\" name=\"%s\" tests=\"%d\" time=\"0.050\" timestamp=\"%s\">\n", group.totalFailures_,
					group.name_.asCharString(), group.numberTests_, theTime);
			CHECK_EQUAL(buf, output);
		}

		void CHECK_XML_FILE()
		{
			size_t totalSize = currentGroup().numberTests_ + defaultSize + (currentGroup().totalFailures_ * 2);
			SimpleStringCollection col;
			buffer_.split("\n", col);
			CHECK(col.size() >= totalSize);
			CHECK_HAS_XML_HEADER(col[0]);
			CHECK_TEST_SUITE_START(col[1]);
			CHECK_PROPERTIES_START(col[2]);
			CHECK_PROPERTIES_END(col[3]);
			CHECK_TESTS(&col[4]);
			CHECK_SYSTEM_OUT(col[col.size() - 3]);
			CHECK_SYSTEM_ERR(col[col.size() - 2]);
			CHECK_TEST_SUITE_END(col[col.size() - 1]);
		}

		void CHECK_PROPERTIES_START(const SimpleString& output)
		{
			STRCMP_EQUAL("<properties>\n", output.asCharString());
		}

		void CHECK_PROPERTIES_END(const SimpleString& output)
		{
			STRCMP_EQUAL("</properties>\n", output.asCharString());
		}

		void CHECK_SYSTEM_OUT(const SimpleString& output)
		{
			STRCMP_EQUAL("<system-out></system-out>\n", output.asCharString());
		}

		void CHECK_SYSTEM_ERR(const SimpleString& output)
		{
			STRCMP_EQUAL("<system-err></system-err>\n", output.asCharString());
		}

		void CHECK_TEST_SUITE_END(const SimpleString& output)
		{
			STRCMP_EQUAL("</testsuite>", output.asCharString());
		}
		void CHECK_TESTS(SimpleString* arr)
		{
			for (int index = 0, curTest = 0; curTest < currentGroup().numberTests_; curTest++, index++) {
				SimpleString buf = StringFromFormat("<testcase classname=\"%s\" name=\"%s\" time=\"0.010\">\n", currentGroup().name_.asCharString(),
						currentGroup().testData_[curTest].tst_->getName().asCharString());
				CHECK_EQUAL(buf, arr[index]);
				if (currentGroup().testData_[curTest].failure_) {
					CHECK_FAILURE(arr, index, curTest);
				}
				buf = "</testcase>\n";
				CHECK_EQUAL(buf, arr[++index]);

			}
		}
		void CHECK_FAILURE(SimpleString* arr, int& i, int curTest)
		{
			TestFailure& f = *currentGroup().testData_[curTest].failure_;
			i++;
			SimpleString message = f.getMessage().asCharString();
			message.replace('"', '\'');
			message.replace('<', '[');
			message.replace('>', ']');
			message.replace("\n", "{newline}");
			SimpleString buf = StringFromFormat("<failure message=\"%s:%d: %s\" type=\"AssertionFailedError\">\n", f.getFileName().asCharString(), f.getFailureLineNumber(), message.asCharString());
			CHECK_EQUAL(buf, arr[i]);
			i++;
			STRCMP_EQUAL("</failure>\n", arr[i].asCharString());
		}
	};

	MockJUnitTestOutput * output;
	TestResult *res;

	void setup()
	{
		output = new MockJUnitTestOutput();
		res = new TestResult(*output);
		output->setResult(res);
		SetPlatformSpecificTimeInMillisMethod(MockGetPlatformSpecificTimeInMillis);
		SetPlatformSpecificTimeStringMethod(MockGetPlatformSpecificTimeString);
	}
	void teardown()
	{
		delete output;
		delete res;
		SetPlatformSpecificTimeInMillisMethod(0);
		SetPlatformSpecificTimeStringMethod(0);
	}

	void runTests()
	{
		output->printTestsStarted();
		output->runTests();
		output->printTestsEnded(*res);
	}
};

TEST(JUnitOutputTest, oneTestInOneGroupAllPass)
{
	output->createTestsInGroup(0, 1, "group", "name");
	runTests();
	STRCMP_EQUAL("cpputest_group.xml", output->fileName_.asCharString());
	LONGS_EQUAL(1, output->filesOpened);
}

TEST(JUnitOutputTest, fiveTestsInOneGroupAllPass)
{
	output->createTestsInGroup(0, 5, "group", "name");
	runTests();
}

TEST(JUnitOutputTest, multipleTestsInTwoGroupAllPass)
{
	output->createTestsInGroup(0, 3, "group", "name");
	output->createTestsInGroup(1, 8, "secondGroup", "secondName");
	runTests();
	LONGS_EQUAL(2, output->filesOpened);
}

TEST(JUnitOutputTest, oneTestInOneGroupFailed)
{
	output->createTestsInGroup(0, 1, "failedGroup", "failedName");
	output->setFailure(0, 0, "file", 1, "Test <\"just\"> failed");
	runTests();
}

TEST(JUnitOutputTest, fiveTestsInOneGroupAndThreeFail)
{
	output->printTestsStarted();
	output->createTestsInGroup(0, 5, "failedGroup", "failedName");
	output->setFailure(0, 0, "file", 1, "Test just failed");
	output->setFailure(0, 1, "file", 5, "Also failed");
	output->setFailure(0, 4, "file", 8, "And failed again");
	runTests();
}

TEST(JUnitOutputTest, fourGroupsAndSomePassAndSomeFail)
{
	output->printTestsStarted();
	output->createTestsInGroup(0, 5, "group1", "firstName");
	output->createTestsInGroup(1, 50, "group2", "secondName");
	output->createTestsInGroup(2, 3, "group3", "thirdName");
	output->createTestsInGroup(3, 5, "group4", "fourthName");

	output->setFailure(0, 0, "file", 1, "Test just failed");
	output->printTestsEnded(*res);
	runTests();
}

TEST(JUnitOutputTest, messageWithNewLine)
{
	output->createTestsInGroup(0, 1, "failedGroup", "failedName");
	output->setFailure(0, 0, "file", 1, "Test \n failed");
	runTests();
}

TEST(JUnitOutputTest, createNormalFilename)
{
	STRCMP_EQUAL("cpputest_group.xml", output->createFileName("group").asCharString());
}

TEST(JUnitOutputTest, escapeSlashesInFilenames)
{
	STRCMP_EQUAL("cpputest_group_weird_name.xml", output->createFileName("group/weird/name").asCharString());
}

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

#include "CppUTest/TestHarness.h"
#include "CppUTest/JUnitTestOutput.h"
#include "CppUTest/TestResult.h"
#include "CppUTest/PlatformSpecificFunctions.h"

static long millisTime;

static const char* theTime = "1978-10-03T00:00:00";

static long MockGetPlatformSpecificTimeInMillis()
{
	return millisTime;
}

static const char* MockGetPlatformSpecificTimeString()
{
	return theTime;
}

TEST_GROUP(JUnitOutputTest)
{
	class MockJUnitTestOutput: public JUnitTestOutput
	{
	public:
		enum
		{
			testGroupSize = 10
		};
		enum
		{
			defaultSize = 7
		};

		int filesOpened;
		int fileBalance;

		SimpleString fileName_;
		SimpleString buffer_;

		TestResult* res_;
		struct TestData
		{
			TestData() :
				tst_(0), testName_(0), failure_(0)
			{
			}
			;
			UtestShell* tst_;
			SimpleString* testName_;
			TestFailure* failure_;
		};

		struct TestGroupData
		{
			TestGroupData() :
				numberTests_(0), totalFailures_(0), name_(""), testData_(0)
			{
			}
			;

			int numberTests_;
			int totalFailures_;
			SimpleString name_;

			TestData* testData_;
		};

		TestGroupData testGroupData_[testGroupSize];

		TestGroupData& currentGroup()
		{
			return testGroupData_[filesOpened - 1];
		}

		void resetXmlFile()
		{
			buffer_ = "";
		}

		MockJUnitTestOutput() :
			filesOpened(0), fileBalance(0), res_(0)
		{
			for (int i = 0; i < testGroupSize; i++) {
				testGroupData_[i].numberTests_ = 0;
				testGroupData_[i].totalFailures_ = 0;
			}
		}
		;

		void setResult(TestResult* testRes)
		{
			res_ = testRes;
		}

		virtual ~MockJUnitTestOutput()
		{
			for (int i = 0; i < testGroupSize; i++) {
				for (int j = 0; j < testGroupData_[i].numberTests_; j++) {
					delete testGroupData_[i].testData_[j].tst_;
					delete testGroupData_[i].testData_[j].testName_;
					if (testGroupData_[i].testData_[j].failure_) delete testGroupData_[i].testData_[j].failure_;
				}
				if (testGroupData_[i].testData_) delete[] testGroupData_[i].testData_;
			}

			LONGS_EQUAL(0, fileBalance);
		}

		void writeToFile(const SimpleString& buf)
		{
			buffer_ += buf;
		}

		void openFileForWrite(const SimpleString& in_FileName)
		{
			filesOpened++;
			fileBalance++;
			fileName_ = in_FileName;
		}

		void closeFile()
		{
			CHECK_XML_FILE();
			resetXmlFile();
			fileBalance--;
		}

		void createTestsInGroup(int index, int amount, const char* group, const char* basename)
		{
			testGroupData_[index].name_ = group;
			testGroupData_[index].numberTests_ = amount;

			testGroupData_[index].testData_ = new TestData[amount];
			for (int i = 0; i < amount; i++) {
				TestData& testData = testGroupData_[index].testData_[i];
				testData.testName_ = new SimpleString(basename);
				*testData.testName_ += StringFrom((long) i);
				testData.tst_ = new UtestShell(group, testData.testName_->asCharString(), "file", 1);
			}
		}
		void runTests()
		{
			res_->testsStarted();
			for (int i = 0; i < testGroupSize; i++) {
				TestGroupData& data = testGroupData_[i];
				if (data.numberTests_ == 0) continue;

				millisTime = 0;
				res_->currentGroupStarted(data.testData_[0].tst_);
				for (int j = 0; j < data.numberTests_; j++) {
					TestData& testData = data.testData_[j];

					millisTime = 0;
					res_->currentTestStarted(testData.tst_);
					if (testData.failure_) print(*testData.failure_);
					millisTime = 10;
					res_->currentTestEnded(testData.tst_);
				}
				millisTime = 50;
				res_->currentGroupEnded(data.testData_[0].tst_);
			}
			res_->testsEnded();
		}

		void setFailure(int groupIndex, int testIndex, const char* fileName, int lineNumber, const char* message)
		{
			TestData& data = testGroupData_[groupIndex].testData_[testIndex];
			data.failure_ = new TestFailure(data.tst_, fileName, lineNumber, message);
			testGroupData_[groupIndex].totalFailures_++;
		}

		void CHECK_HAS_XML_HEADER(SimpleString string)
		{
			STRCMP_EQUAL("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n", string.asCharString());
		}

		void CHECK_TEST_SUITE_START(SimpleString out)
		{
			TestGroupData& group = currentGroup();
			SimpleString buf = StringFromFormat("<testsuite errors=\"0\" failures=\"%d\" hostname=\"localhost\" name=\"%s\" tests=\"%d\" time=\"0.050\" timestamp=\"%s\">\n", group.totalFailures_,
					group.name_.asCharString(), group.numberTests_, theTime);
			CHECK_EQUAL(buf, out);
		}

		void CHECK_XML_FILE()
		{
			size_t totalSize = currentGroup().numberTests_ + defaultSize + (currentGroup().totalFailures_ * 2);
			SimpleStringCollection col;
			buffer_.split("\n", col);
			CHECK(col.size() >= totalSize);
			CHECK_HAS_XML_HEADER(col[0]);
			CHECK_TEST_SUITE_START(col[1]);
			CHECK_PROPERTIES_START(col[2]);
			CHECK_PROPERTIES_END(col[3]);
			CHECK_TESTS(&col[4]);
			CHECK_SYSTEM_OUT(col[col.size() - 3]);
			CHECK_SYSTEM_ERR(col[col.size() - 2]);
			CHECK_TEST_SUITE_END(col[col.size() - 1]);
		}

		void CHECK_PROPERTIES_START(const SimpleString& out)
		{
			STRCMP_EQUAL("<properties>\n", out.asCharString());
		}

		void CHECK_PROPERTIES_END(const SimpleString& out)
		{
			STRCMP_EQUAL("</properties>\n", out.asCharString());
		}

		void CHECK_SYSTEM_OUT(const SimpleString& out)
		{
			STRCMP_EQUAL("<system-out></system-out>\n", out.asCharString());
		}

		void CHECK_SYSTEM_ERR(const SimpleString& out)
		{
			STRCMP_EQUAL("<system-err></system-err>\n", out.asCharString());
		}

		void CHECK_TEST_SUITE_END(const SimpleString& out)
		{
			STRCMP_EQUAL("</testsuite>", out.asCharString());
		}

		void CHECK_TESTS(SimpleString* arr)
		{
			for (int index = 0, curTest = 0; curTest < currentGroup().numberTests_; curTest++, index++) {
				SimpleString buf = StringFromFormat("<testcase classname=\"%s\" name=\"%s\" time=\"0.010\">\n", currentGroup().name_.asCharString(),
						currentGroup().testData_[curTest].tst_->getName().asCharString());
				CHECK_EQUAL(buf, arr[index]);
				if (currentGroup().testData_[curTest].failure_) {
					CHECK_FAILURE(arr, index, curTest);
				}
				buf = "</testcase>\n";
				CHECK_EQUAL(buf, arr[++index]);

			}
		}
		void CHECK_FAILURE(SimpleString* arr, int& i, int curTest)
		{
			TestFailure& f = *currentGroup().testData_[curTest].failure_;
			i++;
			SimpleString message = f.getMessage().asCharString();
			message.replace('"', '\'');
			message.replace('<', '[');
			message.replace('>', ']');
			message.replace("\n", "{newline}");
			SimpleString buf = StringFromFormat("<failure message=\"%s:%d: %s\" type=\"AssertionFailedError\">\n", f.getFileName().asCharString(), f.getFailureLineNumber(), message.asCharString());
			CHECK_EQUAL(buf, arr[i]);
			i++;
			STRCMP_EQUAL("</failure>\n", arr[i].asCharString());
		}
	};

	MockJUnitTestOutput * output;
	TestResult *res;

	void setup()
	{
		output = new MockJUnitTestOutput();
		res = new TestResult(*output);
		output->setResult(res);
		SetPlatformSpecificTimeInMillisMethod(MockGetPlatformSpecificTimeInMillis);
		SetPlatformSpecificTimeStringMethod(MockGetPlatformSpecificTimeString);
	}
	void teardown()
	{
		delete output;
		delete res;
		SetPlatformSpecificTimeInMillisMethod(0);
		SetPlatformSpecificTimeStringMethod(0);
	}

	void runTests()
	{
		output->printTestsStarted();
		output->runTests();
		output->printTestsEnded(*res);
	}
};

TEST(JUnitOutputTest, oneTestInOneGroupAllPass)
{
	output->createTestsInGroup(0, 1, "group", "name");
	runTests();
	STRCMP_EQUAL("cpputest_group.xml", output->fileName_.asCharString());
	LONGS_EQUAL(1, output->filesOpened);
}

TEST(JUnitOutputTest, fiveTestsInOneGroupAllPass)
{
	output->createTestsInGroup(0, 5, "group", "name");
	runTests();
}

TEST(JUnitOutputTest, multipleTestsInTwoGroupAllPass)
{
	output->createTestsInGroup(0, 3, "group", "name");
	output->createTestsInGroup(1, 8, "secondGroup", "secondName");
	runTests();
	LONGS_EQUAL(2, output->filesOpened);
}

TEST(JUnitOutputTest, oneTestInOneGroupFailed)
{
	output->createTestsInGroup(0, 1, "failedGroup", "failedName");
	output->setFailure(0, 0, "file", 1, "Test <\"just\"> failed");
	runTests();
}

TEST(JUnitOutputTest, fiveTestsInOneGroupAndThreeFail)
{
	output->printTestsStarted();
	output->createTestsInGroup(0, 5, "failedGroup", "failedName");
	output->setFailure(0, 0, "file", 1, "Test just failed");
	output->setFailure(0, 1, "file", 5, "Also failed");
	output->setFailure(0, 4, "file", 8, "And failed again");
	runTests();
}

TEST(JUnitOutputTest, fourGroupsAndSomePassAndSomeFail)
{
	output->printTestsStarted();
	output->createTestsInGroup(0, 5, "group1", "firstName");
	output->createTestsInGroup(1, 50, "group2", "secondName");
	output->createTestsInGroup(2, 3, "group3", "thirdName");
	output->createTestsInGroup(3, 5, "group4", "fourthName");

	output->setFailure(0, 0, "file", 1, "Test just failed");
	output->printTestsEnded(*res);
	runTests();
}

TEST(JUnitOutputTest, messageWithNewLine)
{
	output->createTestsInGroup(0, 1, "failedGroup", "failedName");
	output->setFailure(0, 0, "file", 1, "Test \n failed");
	runTests();
}

TEST(JUnitOutputTest, createNormalFilename)
{
	STRCMP_EQUAL("cpputest_group.xml", output->createFileName("group").asCharString());
}

TEST(JUnitOutputTest, escapeSlashesInFilenames)
{
	STRCMP_EQUAL("cpputest_group_weird_name.xml", output->createFileName("group/weird/name").asCharString());
}

<|endoftext|>