<commit_before>// This file is part of the AliceVision project.
// Copyright (c) 2016 AliceVision contributors.
// Copyright (c) 2012 openMVG contributors.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#pragma once

//#include "aliceVision/multiview/homographyKernelSolver.hpp"
//#include "aliceVision/robustEstimation/ACRansac.hpp"
//#include "aliceVision/robustEstimation/ACRansacKernelAdaptator.hpp"
//#include "aliceVision/robustEstimation/guidedMatching.hpp"

#include "aliceVision/matching/IndMatch.hpp"
//#include "aliceVision/matching/IndMatchDecorator.hpp"
#include "aliceVision/sfm/SfMData.hpp"
#include "aliceVision/feature/RegionsPerView.hpp"
#include "aliceVision/matchingImageCollection/GeometricFilterMatrix.hpp"

namespace aliceVision {
namespace matchingImageCollection {

//-- Multiple homography matrices estimation template functor, based on homography growing, used for filter pair of putative correspondences
struct GeometricFilterMatrix_HGrowing : public GeometricFilterMatrix
{
  GeometricFilterMatrix_HGrowing(
    double dPrecision = std::numeric_limits<double>::infinity(),
    size_t iteration = 1024)
    : GeometricFilterMatrix(dPrecision, std::numeric_limits<double>::infinity(), iteration)
    , _maxNbHomographies(10)
    , _minRemainingMatches(20)
    , _similarityTolerance(10)
    , _affinityTolerance(10)
    , _homographyTolerance(5)
    , _minNbPlanarMatches(6)
    , _nbIterations(8)
    , _maxFractionPlanarMatches(0.7)
  {
    _Hs.push_back(Mat3::Identity());
  }
/**
   * @brief Given two sets of image points, it estimates the homography matrix
   * relating them using a robust method (like A Contrario Ransac).
   */
  template<typename Regions_or_Features_ProviderT>
  EstimationStatus geometricEstimation(
    const sfm::SfMData * sfmData,
    const Regions_or_Features_ProviderT& regionsPerView,
    const Pair pairIndex,
    const matching::MatchesPerDescType & putativeMatchesPerType,
    matching::MatchesPerDescType & out_geometricInliersPerType)
  {

    using namespace aliceVision;
    using namespace aliceVision::robustEstimation;
    out_geometricInliersPerType.clear();

    // Get back corresponding view index
    const IndexT viewId_I = pairIndex.first;
    const IndexT viewId_J = pairIndex.second;

    const std::vector<feature::EImageDescriberType> descTypes = regionsPerView.getCommonDescTypes(pairIndex);
    if(descTypes.empty())
      return EstimationStatus(false, false);

    // Retrieve all 2D features as undistorted positions into flat arrays
    Mat xI, xJ;
    MatchesPairToMat(pairIndex, putativeMatchesPerType, sfmData, regionsPerView, descTypes, xI, xJ);

    std::cout << "Pair id. : " << pairIndex << std::endl;
    std::cout << "|- putative: " << putativeMatchesPerType.at(feature::EImageDescriberType::SIFT).size() << std::endl;
    std::cout << "|- xI: " << xI.rows() << "x" << xI.cols() << std::endl;
    std::cout << "|- xJ: " << xJ.rows() << "x" << xJ.cols() << std::endl;

    const feature::Regions& regionsSIFT_I = regionsPerView.getRegions(viewId_I, descTypes.at(0));
    const feature::Regions& regionsSIFT_J = regionsPerView.getRegions(viewId_J, descTypes.at(0));
    const std::vector<feature::SIOPointFeature> allSIFTFeaturesI = getSIOPointFeatures(regionsSIFT_I);
    const std::vector<feature::SIOPointFeature> allSIFTfeaturesJ = getSIOPointFeatures(regionsSIFT_J);

    matching::IndMatches putativeSIFTMatches = putativeMatchesPerType.at(feature::EImageDescriberType::SIFT);
//    std::vector<feature::SIOPointFeature> putativeFeaturesI, putativeFeaturesJ;
//    putativeFeaturesI.reserve(putativeSIFTMatches.size());
//    putativeFeaturesJ.reserve(putativeSIFTMatches.size());

//    for (const matching::IndMatch & idMatch : putativeSIFTMatches)
//    {
//      putativeFeaturesI.push_back(allSIFTFeaturesI.at(idMatch._i));
//      putativeFeaturesJ.push_back(allSIFTfeaturesJ.at(idMatch._j));
//    }

    if (viewId_I == 200563944 && viewId_J == 1112206013) // MATLAB exemple
    {
      std::cout << "|- #matches: " << putativeSIFTMatches.size() << std::endl;
      std::cout << "|- allSIFTFeaturesI : " << allSIFTFeaturesI.size() << std::endl;
      std::cout << "|- allSIFTfeaturesJ : " << allSIFTfeaturesJ.size() << std::endl;
//      std::cout << "|- putativeFeaturesI : " << putativeFeaturesI.size() << std::endl;
//      std::cout << "|- putativeFeaturesJ : " << putativeFeaturesJ.size() << std::endl;
      //      std::cout << "-------" << std::endl;
      //      std::cout << "xI : " << std::endl;
      //      std::cout << xI << std::endl;
      //      std::cout << "putativeFeaturesI : " << std::endl;
      //      std::cout << putativeFeaturesI << std::endl;

      std::size_t nbMatches = putativeSIFTMatches.size();

      // (?) make a map
      std::vector<Mat3> homographies;
      std::vector<std::vector<IndexT>> planarMatchesPerH;

      for (IndexT iTransform = 0; iTransform < _maxNbHomographies; ++iTransform)
      {
        for (IndexT iMatch = 0; iMatch < nbMatches; ++iMatch)
        {
          // [TODO] Add 1st improvment

          // Growing a homography from one match ([F.Srajer, 2016] algo. 1, p. 20)
          std::vector<IndexT> planarMatchesIds;
          Mat3 homographie;

          growHomography(allSIFTFeaturesI, allSIFTfeaturesJ, putativeSIFTMatches, iMatch, planarMatchesIds, homographie);

          if (!planarMatchesIds.empty())
          {
            homographies.push_back(homographie);
            planarMatchesPerH.push_back(planarMatchesIds);
          }
        }
      }
    }

    // Check if resection has strong support
    const bool hasStrongSupport = true;
    return EstimationStatus(true, hasStrongSupport);
  }

  /**
   * @brief Geometry_guided_matching
   * @param sfm_data
   * @param regionsPerView
   * @param pairIndex
   * @param dDistanceRatio
   * @param matches
   * @return
   */
  bool Geometry_guided_matching
  (
    const sfm::SfMData * sfmData,
    const feature::RegionsPerView & regionsPerView,
    const Pair imageIdsPair,
    const double dDistanceRatio,
    matching::MatchesPerDescType & matches) override
  {

    /* ... */
    return matches.getNbAllMatches() != 0;
  }

private:

  // Growing a homography from one match ([F.Srajer, 2016] algo. 1, p. 20)
  //-- See: YASM/relative_pose.h
  void growHomography(const std::vector<feature::SIOPointFeature> & featuresI,
                      const std::vector<feature::SIOPointFeature> & featuresJ,
                      const matching::IndMatches & putativeMatches,
                      const IndexT & seedMatchId,
                      std::vector<IndexT> & out_planarMatchesIndices,
                      Mat3 & out_transformation)
  {

    assert(seedMatchId <= putativeMatches.size());
    out_planarMatchesIndices.clear();
    out_transformation = Mat3::Identity();

    const matching::IndMatch & seedMatch = putativeMatches.at(seedMatchId);
    const feature::SIOPointFeature & seedFeatureI = featuresI.at(seedMatch._i);
    const feature::SIOPointFeature & seedFeatureJ = featuresJ.at(seedMatch._j);

    std::size_t currentTolerance;

    for (IndexT iRefineStep = 0; iRefineStep < _nbIterations; ++iRefineStep)
    {
      if (iRefineStep == 0)
      {
        computeSimilarityFromMatch(seedFeatureI, seedFeatureJ, out_transformation);
        std::cout << "featI: " << seedFeatureI << std::endl;
        std::cout << "featJ: " << seedFeatureJ << std::endl;
        std::cout << "S = " << out_transformation << std::endl;
        getchar();
        currentTolerance = _similarityTolerance;
      }
      else if (iRefineStep <= 4)
      {
        estimateAffinity();
        currentTolerance = _affinityTolerance;
      }
      else
      {
        estimateHomography();
        currentTolerance = _homographyTolerance;
      }

      findTransformationInliers();

    }
  }

  /**
   * @brief computeSimilarityFromMatch
   * see: alicevision::sfm::computeSimilarity() [sfm/utils/alignment.cpp]
   *      alicevision::geometry::ACRansac_FindRTS() [geometry/rigidTransformation3D(_test).hpp]
   */

  void computeSimilarityFromMatch(const feature::SIOPointFeature & feat1,
                                  const feature::SIOPointFeature & feat2,
                                  Mat3 & S)
  {
    computeSimilarityFromMatch(feat1.coords(), feat1.scale(), feat1.orientation(),
                               feat2.coords(), feat2.scale(), feat2.orientation(),
                               S);
  }

  /**
   * @brief computeSimilarityFromMatch
   * Source: https://github.com/fsrajer/yasfm/blob/master/YASFM/relative_pose.cpp#L1649
   * @param coord1
   * @param scale1
   * @param orientation1
   * @param coord2
   * @param scale2
   * @param orientation2
   * @param S
   */
  void computeSimilarityFromMatch(const Vec2f & coord1, double scale1, double orientation1,
                                  const Vec2f & coord2, double scale2, double orientation2,
                                  Mat3 & S)
  {
    double c1 = cos(orientation1),
        s1 = sin(orientation1),
        c2 = cos(orientation2),
        s2 = sin(orientation2);

    Mat3 A1,A2;
    A1 << scale1*c1,scale1*(-s1),coord1(0),
        scale1*s1,scale1*c1,coord1(1),
        0,0,1;
    A2 << scale2*c2,scale2*(-s2),coord2(0),
        scale2*s2,scale2*c2,coord2(1),
        0,0,1;

    S = A2*A1.inverse();
  }

  /**
   * @brief estimateAffinity
   * see: alicevision::Affine2DFromCorrespondencesLinear() [multiview/affineSolver(_test).hpp]
   */
  void estimateAffinity()
  {
//    std::cout << "estimateAffinity" << std::endl;
  }

  /**
   * @brief estimateHomography
   * see: by DLT: alicevision::homography::kernel::FourPointSolver::Solve() [multiview/homographyKernelSolver.hpp]
   *      by RANSAC: alicevision::matchingImageCOllection::geometricEstimation() [matchingImageCollection/GeometricFilterMatrix_H_AC.hpp]
   */
  void estimateHomography()
  {
//    std::cout << "estimateHomography" << std::endl;
  }

  /**
   * @brief findHomographyInliers Test the reprojection error
   */
  void findTransformationInliers()
  {
//    std::cout << "findHomographyInliers" << std::endl;

  }

  //-- Stored data
  std::vector<Mat3> _Hs;

  //-- Options

  std::size_t _maxNbHomographies; // = MaxHoms
  std::size_t _minRemainingMatches; // = MinInsNum

  // growHomography function:
  std::size_t _similarityTolerance; // = SimTol
  std::size_t _affinityTolerance;   // = AffTol
  std::size_t _homographyTolerance; // = HomTol

  std::size_t _minNbPlanarMatches; // = MinIns
  std::size_t _nbIterations; // = RefIterNum
  std::size_t _maxFractionPlanarMatches; // = StopInsFrac

};

} // namespace matchingImageCollection
} // namespace aliceVision

<commit_msg>[Hgrowing] 'findTransformationInliers' integration<commit_after>// This file is part of the AliceVision project.
// Copyright (c) 2016 AliceVision contributors.
// Copyright (c) 2012 openMVG contributors.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#pragma once

//#include "aliceVision/multiview/homographyKernelSolver.hpp"
//#include "aliceVision/robustEstimation/ACRansac.hpp"
//#include "aliceVision/robustEstimation/ACRansacKernelAdaptator.hpp"
//#include "aliceVision/robustEstimation/guidedMatching.hpp"

#include "aliceVision/matching/IndMatch.hpp"
//#include "aliceVision/matching/IndMatchDecorator.hpp"
#include "aliceVision/sfm/SfMData.hpp"
#include "aliceVision/feature/RegionsPerView.hpp"
#include "aliceVision/matchingImageCollection/GeometricFilterMatrix.hpp"
#include "Eigen/Geometry"

namespace aliceVision {
namespace matchingImageCollection {

//-- Multiple homography matrices estimation template functor, based on homography growing, used for filter pair of putative correspondences
struct GeometricFilterMatrix_HGrowing : public GeometricFilterMatrix
{
  GeometricFilterMatrix_HGrowing(
    double dPrecision = std::numeric_limits<double>::infinity(),
    size_t iteration = 1024)
    : GeometricFilterMatrix(dPrecision, std::numeric_limits<double>::infinity(), iteration)
    , _maxNbHomographies(10)
    , _minRemainingMatches(20)
    , _similarityTolerance(10)
    , _affinityTolerance(10)
    , _homographyTolerance(5)
    , _minNbPlanarMatches(6)
    , _nbIterations(8)
    , _maxFractionPlanarMatches(0.7)
  {
    _Hs.push_back(Mat3::Identity());
  }
/**
   * @brief Given two sets of image points, it estimates the homography matrix
   * relating them using a robust method (like A Contrario Ransac).
   */
  template<typename Regions_or_Features_ProviderT>
  EstimationStatus geometricEstimation(
    const sfm::SfMData * sfmData,
    const Regions_or_Features_ProviderT& regionsPerView,
    const Pair pairIndex,
    const matching::MatchesPerDescType & putativeMatchesPerType,
    matching::MatchesPerDescType & out_geometricInliersPerType)
  {

    using namespace aliceVision;
    using namespace aliceVision::robustEstimation;
    out_geometricInliersPerType.clear();

    // Get back corresponding view index
    const IndexT viewId_I = pairIndex.first;
    const IndexT viewId_J = pairIndex.second;

    const std::vector<feature::EImageDescriberType> descTypes = regionsPerView.getCommonDescTypes(pairIndex);
    if(descTypes.empty())
      return EstimationStatus(false, false);

    // Retrieve all 2D features as undistorted positions into flat arrays
    Mat xI, xJ;
    MatchesPairToMat(pairIndex, putativeMatchesPerType, sfmData, regionsPerView, descTypes, xI, xJ);

    std::cout << "Pair id. : " << pairIndex << std::endl;
    std::cout << "|- putative: " << putativeMatchesPerType.at(feature::EImageDescriberType::SIFT).size() << std::endl;
    std::cout << "|- xI: " << xI.rows() << "x" << xI.cols() << std::endl;
    std::cout << "|- xJ: " << xJ.rows() << "x" << xJ.cols() << std::endl;

    const feature::Regions& regionsSIFT_I = regionsPerView.getRegions(viewId_I, descTypes.at(0));
    const feature::Regions& regionsSIFT_J = regionsPerView.getRegions(viewId_J, descTypes.at(0));
    const std::vector<feature::SIOPointFeature> allSIFTFeaturesI = getSIOPointFeatures(regionsSIFT_I);
    const std::vector<feature::SIOPointFeature> allSIFTfeaturesJ = getSIOPointFeatures(regionsSIFT_J);

    matching::IndMatches putativeSIFTMatches = putativeMatchesPerType.at(feature::EImageDescriberType::SIFT);
//    std::vector<feature::SIOPointFeature> putativeFeaturesI, putativeFeaturesJ;
//    putativeFeaturesI.reserve(putativeSIFTMatches.size());
//    putativeFeaturesJ.reserve(putativeSIFTMatches.size());

//    for (const matching::IndMatch & idMatch : putativeSIFTMatches)
//    {
//      putativeFeaturesI.push_back(allSIFTFeaturesI.at(idMatch._i));
//      putativeFeaturesJ.push_back(allSIFTfeaturesJ.at(idMatch._j));
//    }

    if (viewId_I == 200563944 && viewId_J == 1112206013) // MATLAB exemple
    {
      std::cout << "|- #matches: " << putativeSIFTMatches.size() << std::endl;
      std::cout << "|- allSIFTFeaturesI : " << allSIFTFeaturesI.size() << std::endl;
      std::cout << "|- allSIFTfeaturesJ : " << allSIFTfeaturesJ.size() << std::endl;
//      std::cout << "|- putativeFeaturesI : " << putativeFeaturesI.size() << std::endl;
//      std::cout << "|- putativeFeaturesJ : " << putativeFeaturesJ.size() << std::endl;
      //      std::cout << "-------" << std::endl;
      //      std::cout << "xI : " << std::endl;
      //      std::cout << xI << std::endl;
      //      std::cout << "putativeFeaturesI : " << std::endl;
      //      std::cout << putativeFeaturesI << std::endl;

      std::size_t nbMatches = putativeSIFTMatches.size();

      // (?) make a map
      std::vector<Mat3> homographies;
      std::vector<std::vector<IndexT>> planarMatchesPerH;

      for (IndexT iTransform = 0; iTransform < _maxNbHomographies; ++iTransform)
      {
        for (IndexT iMatch = 0; iMatch < nbMatches; ++iMatch)
        {
          // [TODO] Add 1st improvment

          // Growing a homography from one match ([F.Srajer, 2016] algo. 1, p. 20)
          std::vector<IndexT> planarMatchesIds;
          Mat3 homographie;

          growHomography(allSIFTFeaturesI, allSIFTfeaturesJ, putativeSIFTMatches, iMatch, planarMatchesIds, homographie);

          if (!planarMatchesIds.empty())
          {
            homographies.push_back(homographie);
            planarMatchesPerH.push_back(planarMatchesIds);
          }
        }
      }
    }

    // Check if resection has strong support
    const bool hasStrongSupport = true;
    return EstimationStatus(true, hasStrongSupport);
  }

  /**
   * @brief Geometry_guided_matching
   * @param sfm_data
   * @param regionsPerView
   * @param pairIndex
   * @param dDistanceRatio
   * @param matches
   * @return
   */
  bool Geometry_guided_matching
  (
    const sfm::SfMData * sfmData,
    const feature::RegionsPerView & regionsPerView,
    const Pair imageIdsPair,
    const double dDistanceRatio,
    matching::MatchesPerDescType & matches) override
  {

    /* ... */
    return matches.getNbAllMatches() != 0;
  }

private:

  // Growing a homography from one match ([F.Srajer, 2016] algo. 1, p. 20)
  //-- See: YASM/relative_pose.h
  void growHomography(const std::vector<feature::SIOPointFeature> & featuresI,
                      const std::vector<feature::SIOPointFeature> & featuresJ,
                      const matching::IndMatches & matches,
                      const IndexT & seedMatchId,
                      std::vector<IndexT> & planarMatchesIndices,
                      Mat3 & transformation)
  {

    assert(seedMatchId <= matches.size());
    planarMatchesIndices.clear();
    transformation = Mat3::Identity();

    const matching::IndMatch & seedMatch = matches.at(seedMatchId);
    const feature::SIOPointFeature & seedFeatureI = featuresI.at(seedMatch._i);
    const feature::SIOPointFeature & seedFeatureJ = featuresJ.at(seedMatch._j);

    std::size_t currTolerance;

    for (IndexT iRefineStep = 0; iRefineStep < _nbIterations; ++iRefineStep)
    {
      if (iRefineStep == 0)
      {
        computeSimilarityFromMatch(seedFeatureI, seedFeatureJ, transformation);
        std::cout << "featI: " << seedFeatureI << std::endl;
        std::cout << "featJ: " << seedFeatureJ << std::endl;
        std::cout << "S = " << transformation << std::endl;

        currTolerance = _similarityTolerance;
      }
      else if (iRefineStep <= 4)
      {
        estimateAffinity();
        currTolerance = _affinityTolerance;
      }
      else
      {
        estimateHomography();
        currTolerance = _homographyTolerance;
      }

      findTransformationInliers(featuresI, featuresJ, matches, transformation, currTolerance, planarMatchesIndices);

      std::cout << "#Inliers = " << planarMatchesIndices.size() << std::endl;
      std::cout << planarMatchesIndices << std::endl;
      getchar();
    }
  }
  /**
   * @brief findHomographyInliers Test the reprojection error
   */
  void findTransformationInliers(const std::vector<feature::SIOPointFeature> & featuresI,
                                 const std::vector<feature::SIOPointFeature> & featuresJ,
                                 const matching::IndMatches & matches,
                                 const Mat3 & transformation,
                                 const std::size_t tolerance,
                                 std::vector<IndexT> & planarMatchesIndices)
  {
    planarMatchesIndices.clear();

    for (IndexT iMatch = 0; iMatch < matches.size(); ++iMatch)
    {
      const feature::SIOPointFeature & featI = featuresI.at(matches.at(iMatch)._i);
      const feature::SIOPointFeature & featJ = featuresJ.at(matches.at(iMatch)._j);

      Vec2 ptI(featI.x(), featI.y());
      Vec2 ptJ(featJ.x(), featJ.y());

      Vec3 ptIp_hom = transformation * ptI.homogeneous();

      float dist = (ptJ - ptIp_hom.hnormalized()).squaredNorm();

      if (dist < tolerance * tolerance)
        planarMatchesIndices.push_back(iMatch);
    }
  }

  /**
   * @brief computeSimilarityFromMatch
   * see: alicevision::sfm::computeSimilarity() [sfm/utils/alignment.cpp]
   *      alicevision::geometry::ACRansac_FindRTS() [geometry/rigidTransformation3D(_test).hpp]
   */

  void computeSimilarityFromMatch(const feature::SIOPointFeature & feat1,
                                  const feature::SIOPointFeature & feat2,
                                  Mat3 & S)
  {
    computeSimilarityFromMatch(feat1.coords(), feat1.scale(), feat1.orientation(),
                               feat2.coords(), feat2.scale(), feat2.orientation(),
                               S);
  }

  /**
   * @brief computeSimilarityFromMatch
   * Source: https://github.com/fsrajer/yasfm/blob/master/YASFM/relative_pose.cpp#L1649
   * @param coord1
   * @param scale1
   * @param orientation1
   * @param coord2
   * @param scale2
   * @param orientation2
   * @param S
   */
  void computeSimilarityFromMatch(const Vec2f & coord1, double scale1, double orientation1,
                                  const Vec2f & coord2, double scale2, double orientation2,
                                  Mat3 & S)
  {
    double c1 = cos(orientation1),
        s1 = sin(orientation1),
        c2 = cos(orientation2),
        s2 = sin(orientation2);

    Mat3 A1,A2;
    A1 << scale1*c1,scale1*(-s1),coord1(0),
        scale1*s1,scale1*c1,coord1(1),
        0,0,1;
    A2 << scale2*c2,scale2*(-s2),coord2(0),
        scale2*s2,scale2*c2,coord2(1),
        0,0,1;

    S = A2*A1.inverse();
  }

  /**
   * @brief estimateAffinity
   * see: alicevision::Affine2DFromCorrespondencesLinear() [multiview/affineSolver(_test).hpp]
   */
  void estimateAffinity()
  {
//    std::cout << "estimateAffinity" << std::endl;
  }

  /**
   * @brief estimateHomography
   * see: by DLT: alicevision::homography::kernel::FourPointSolver::Solve() [multiview/homographyKernelSolver.hpp]
   *      by RANSAC: alicevision::matchingImageCOllection::geometricEstimation() [matchingImageCollection/GeometricFilterMatrix_H_AC.hpp]
   */
  void estimateHomography()
  {
//    std::cout << "estimateHomography" << std::endl;
  }

  //-- Stored data
  std::vector<Mat3> _Hs;

  //-- Options

  std::size_t _maxNbHomographies; // = MaxHoms
  std::size_t _minRemainingMatches; // = MinInsNum

  // growHomography function:
  std::size_t _similarityTolerance; // = SimTol
  std::size_t _affinityTolerance;   // = AffTol
  std::size_t _homographyTolerance; // = HomTol

  std::size_t _minNbPlanarMatches; // = MinIns
  std::size_t _nbIterations; // = RefIterNum
  std::size_t _maxFractionPlanarMatches; // = StopInsFrac

};

} // namespace matchingImageCollection
} // namespace aliceVision

<|endoftext|>


<commit_before>// Description for Color struct and example colors
// William Immendorf - 2016

#include <string>

#pragma once

namespace EquParser
{
	struct Color
	{
		std::string name = "";
		float red = 0.0f;
		float green = 0.0f;
		float blue = 0.0f;

		Color(std::string name, float red, float green, float blue) : name(name), red(red), green(green), blue(blue) { }
	};

	const Color Colors[3] =
	{
		{ "Black", 0.0f, 0.0f, 0.0f },
		{ "Red", 1.0f, 0.0f, 0.0f },
		{ "Green", 0.0f, 1.0f, 0.0f }
	};
}
<commit_msg>Add blue color<commit_after>// Description for Color struct and example colors
// William Immendorf - 2016

#include <string>

#pragma once

namespace EquParser
{
	struct Color
	{
		std::string name = "";
		float red = 0.0f;
		float green = 0.0f;
		float blue = 0.0f;

		Color(std::string name, float red, float green, float blue) : name(name), red(red), green(green), blue(blue) { }
	};

	const Color Colors[4] =
	{
		{ "Black", 0.0f, 0.0f, 0.0f },
		{ "Red", 1.0f, 0.0f, 0.0f },
		{ "Green", 0.0f, 1.0f, 0.0f },
		{ "Blue", 0.0f, 0.0f, 1.0f }
	};
}
<|endoftext|>


<commit_before>#include "Type.h"

// to avoid compiler confusion, python.hpp must be include before Halide headers
#include <boost/format.hpp>
#include <boost/python.hpp>
#include "no_compare_indexing_suite.h"

#include "../../src/Type.h"
#include "../../src/Expr.h"

#include <vector>
#include <string>

namespace h = Halide;

std::string type_code_to_string(const h::Type &t)
{
    std::string code_string = "unknown";
    switch(t.code())
    {
    case h::Type::UInt:
        code_string = "UInt";
        break;

    case h::Type::Int:
        code_string = "Int";
        break;

    case h::Type::Float:
        code_string = "Float";
        break;

    case h::Type::Handle:
        code_string = "Handle";
        break;

    default:
        code_string = "unknown";
    }

    return code_string;
}

std::string type_repr(const h::Type &t)
{
    auto message_format = boost::format("<halide.Type code '%s' with %i bits and %i lanes>");

    return boost::str(message_format % type_code_to_string(t) % t.bits() % t.lanes());
}

void defineType()
{

    using Halide::Type;
    namespace p = boost::python;

    bool (Type::*can_represent_other_type)(Type) const = &Type::can_represent;

    p::class_<Type>("Type",
                    "Default constructor initializes everything to predictable-but-unlikely values",
                    p::no_init)
            .def(p::init<halide_type_code_t, int, int>(p::args("code", "bits", "lanes")))
            .def(p::init<h::Type>(p::args("that"), "Copy constructor"))

            .def("bits", &Type::bits,
                 "The number of bits of precision of a single scalar value of this type.")
            .def("bytes", &Type::bytes,
                 "The number of bytes required to store a single scalar value of this type. Ignores vector width.")
            .def("lanes", &Type::lanes,
                 "How many elements (if a vector type). Should be 1 for scalar types.")
            .def("is_bool", &Type::is_bool, p::arg("self"),
                 "Is this type boolean (represented as UInt(1))?")
            .def("is_vector", &Type::is_vector, p::arg("self"),
                 "Is this type a vector type? (width > 1)")
            .def("is_scalar", &Type::is_scalar, p::arg("self"),
                 "Is this type a scalar type? (width == 1)")
            .def("is_float", &Type::is_float, p::arg("self"),
                 "Is this type a floating point type (float or double).")
            .def("is_int", &Type::is_int, p::arg("self"),
                 "Is this type a signed integer type?")
            .def("is_uint", &Type::is_uint, p::arg("self"),
                 "Is this type an unsigned integer type?")
            .def("is_handle", &Type::is_handle, p::arg("self"),
                 "Is this type an opaque handle type (void *)")
            .def(p::self == p::self)
            .def(p::self != p::self)
            .def("with_lanes", &Type::with_lanes, p::args("self", "w"),
                 "Produce a copy of this type, with 'lanes' vector lanes")
            .def("with_bits", &Type::with_bits, p::args("self", "w"),
                 "Produce a copy of this type, with 'bits' bits")
            .def("element_of", &Type::element_of, p::arg("self"),
                 "Produce the type of a single element of this vector type")
            .def("can_represent", can_represent_other_type, p::arg("other"),
                 "Can this type represent all values of another type?")
            .def("max", &Type::max, p::arg("self"),
                 "Return an expression which is the maximum value of this type")
            .def("min", &Type::min, p::arg("self"),
                 "Return an expression which is the minimum value of this type")
            .def("__repr__", &type_repr, p::arg("self"),
                 "Return a string containing a printable representation of a Type object.")
            ;

    p::def("Int", h::Int,
           (p::arg("bits"), p::arg("width")=1),
           "Constructing an signed integer type");

    p::def("UInt", h::UInt,
           (p::arg("bits"), p::arg("width")=1),
           "Constructing an unsigned integer type");

    p::def("Float", h::Float,
           (p::arg("bits"), p::arg("width")=1),
           "Constructing a floating-point type");

    p::def("Bool", h::Bool,
           (p::arg("width")=1),
           "Construct a boolean type");

    p::def("Handle", h::Handle,
           (p::arg("width")=1),
           "Construct a handle type");

    p::class_< std::vector<Type> >("TypesVector")
            .def( no_compare_indexing_suite< std::vector<Type> >() );

    return;
}
<commit_msg>Fix python bindings<commit_after>#include "Type.h"

// to avoid compiler confusion, python.hpp must be include before Halide headers
#include <boost/format.hpp>
#include <boost/python.hpp>
#include "no_compare_indexing_suite.h"

#include "../../src/Type.h"
#include "../../src/Expr.h"

#include <vector>
#include <string>

namespace h = Halide;

std::string type_code_to_string(const h::Type &t)
{
    std::string code_string = "unknown";
    switch(t.code())
    {
    case h::Type::UInt:
        code_string = "UInt";
        break;

    case h::Type::Int:
        code_string = "Int";
        break;

    case h::Type::Float:
        code_string = "Float";
        break;

    case h::Type::Handle:
        code_string = "Handle";
        break;

    default:
        code_string = "unknown";
    }

    return code_string;
}

Halide::Type make_handle(int lanes) {
    return Halide::Handle(lanes, nullptr);
}

std::string type_repr(const h::Type &t)
{
    auto message_format = boost::format("<halide.Type code '%s' with %i bits and %i lanes>");

    return boost::str(message_format % type_code_to_string(t) % t.bits() % t.lanes());
}

void defineType()
{

    using Halide::Type;
    namespace p = boost::python;

    bool (Type::*can_represent_other_type)(Type) const = &Type::can_represent;

    p::class_<Type>("Type",
                    "Default constructor initializes everything to predictable-but-unlikely values",
                    p::no_init)
            .def(p::init<halide_type_code_t, int, int>(p::args("code", "bits", "lanes")))
            .def(p::init<h::Type>(p::args("that"), "Copy constructor"))

            .def("bits", &Type::bits,
                 "The number of bits of precision of a single scalar value of this type.")
            .def("bytes", &Type::bytes,
                 "The number of bytes required to store a single scalar value of this type. Ignores vector lanes.")
            .def("lanes", &Type::lanes,
                 "How many elements (if a vector type). Should be 1 for scalar types.")
            .def("is_bool", &Type::is_bool, p::arg("self"),
                 "Is this type boolean (represented as UInt(1))?")
            .def("is_vector", &Type::is_vector, p::arg("self"),
                 "Is this type a vector type? (lanes > 1)")
            .def("is_scalar", &Type::is_scalar, p::arg("self"),
                 "Is this type a scalar type? (lanes == 1)")
            .def("is_float", &Type::is_float, p::arg("self"),
                 "Is this type a floating point type (float or double).")
            .def("is_int", &Type::is_int, p::arg("self"),
                 "Is this type a signed integer type?")
            .def("is_uint", &Type::is_uint, p::arg("self"),
                 "Is this type an unsigned integer type?")
            .def("is_handle", &Type::is_handle, p::arg("self"),
                 "Is this type an opaque handle type (void *)")
            .def(p::self == p::self)
            .def(p::self != p::self)
            .def("with_lanes", &Type::with_lanes, p::args("self", "w"),
                 "Produce a copy of this type, with 'lanes' vector lanes")
            .def("with_bits", &Type::with_bits, p::args("self", "w"),
                 "Produce a copy of this type, with 'bits' bits")
            .def("element_of", &Type::element_of, p::arg("self"),
                 "Produce the type of a single element of this vector type")
            .def("can_represent", can_represent_other_type, p::arg("other"),
                 "Can this type represent all values of another type?")
            .def("max", &Type::max, p::arg("self"),
                 "Return an expression which is the maximum value of this type")
            .def("min", &Type::min, p::arg("self"),
                 "Return an expression which is the minimum value of this type")
            .def("__repr__", &type_repr, p::arg("self"),
                 "Return a string containing a printable representation of a Type object.")
            ;

    p::def("Int", h::Int,
           (p::arg("bits"), p::arg("lanes")=1),
           "Constructing an signed integer type");

    p::def("UInt", h::UInt,
           (p::arg("bits"), p::arg("lanes")=1),
           "Constructing an unsigned integer type");

    p::def("Float", h::Float,
           (p::arg("bits"), p::arg("lanes")=1),
           "Constructing a floating-point type");

    p::def("Bool", h::Bool,
           (p::arg("lanes")=1),
           "Construct a boolean type");

    p::def("Handle", make_handle,
           (p::arg("lanes")=1),
           "Construct a handle type");

    p::class_< std::vector<Type> >("TypesVector")
            .def( no_compare_indexing_suite< std::vector<Type> >() );

    return;
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit_training.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

/// @file p9_mss_draminit_training.H
/// @brief Train DRAM
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP FW Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 1
// *HWP Consumed by: FSP:HB

#ifndef __P9_MSS_DRAMINIT_TRAINING__
#define __P9_MSS_DRAMINIT_TRAINING__

#include <fapi2.H>

typedef fapi2::ReturnCode (*p9_mss_draminit_training_FP_t) (const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>&);

extern "C"
{
///
/// @brief Train dram
/// @param[in] i_target, the McBIST of the ports of the dram you're training
/// @return FAPI2_RC_SUCCESS iff ok
///
    fapi2::ReturnCode p9_mss_draminit_training( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );
}

#endif
<commit_msg>Initial commit of memory subsystem<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit_training.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

/// @file p9_mss_draminit_training.H
/// @brief Train DRAM
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#ifndef __P9_MSS_DRAMINIT_TRAINING__
#define __P9_MSS_DRAMINIT_TRAINING__

#include <fapi2.H>

typedef fapi2::ReturnCode (*p9_mss_draminit_training_FP_t) (const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>&);

extern "C"
{

///
/// @brief Train dram, assumes effective config has run
/// @param[in] i_target, the McBIST of the ports of the dram you're training
/// @return FAPI2_RC_SUCCESS iff ok
///
    fapi2::ReturnCode p9_mss_draminit_training( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );
}

#endif
<|endoftext|>


<commit_before>//===- CoverageReport.cpp - Code coverage report -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class implements rendering of a code coverage report.
//
//===----------------------------------------------------------------------===//

#include "CoverageReport.h"
#include "RenderingSupport.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Path.h"
#include <numeric>

using namespace llvm;

namespace {

/// \brief Helper struct which prints trimmed and aligned columns.
struct Column {
  enum TrimKind { NoTrim, WidthTrim, RightTrim };

  enum AlignmentKind { LeftAlignment, RightAlignment };

  StringRef Str;
  unsigned Width;
  TrimKind Trim;
  AlignmentKind Alignment;

  Column(StringRef Str, unsigned Width)
      : Str(Str), Width(Width), Trim(WidthTrim), Alignment(LeftAlignment) {}

  Column &set(TrimKind Value) {
    Trim = Value;
    return *this;
  }

  Column &set(AlignmentKind Value) {
    Alignment = Value;
    return *this;
  }

  void render(raw_ostream &OS) const {
    if (Str.size() <= Width) {
      if (Alignment == RightAlignment) {
        OS.indent(Width - Str.size());
        OS << Str;
        return;
      }
      OS << Str;
      OS.indent(Width - Str.size());
      return;
    }

    switch (Trim) {
    case NoTrim:
      OS << Str;
      break;
    case WidthTrim:
      OS << Str.substr(0, Width);
      break;
    case RightTrim:
      OS << Str.substr(0, Width - 3) << "...";
      break;
    }
  }
};

raw_ostream &operator<<(raw_ostream &OS, const Column &Value) {
  Value.render(OS);
  return OS;
}

Column column(StringRef Str, unsigned Width) { return Column(Str, Width); }

template <typename T>
Column column(StringRef Str, unsigned Width, const T &Value) {
  return Column(Str, Width).set(Value);
}

// Specify the default column widths.
size_t FileReportColumns[] = {25, 12, 18, 10, 12, 18, 10,
                              16, 16, 10, 12, 18, 10};
size_t FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8};

/// \brief Adjust column widths to fit long file paths and function names.
void adjustColumnWidths(ArrayRef<StringRef> Files,
                        ArrayRef<StringRef> Functions) {
  for (StringRef Filename : Files)
    FileReportColumns[0] = std::max(FileReportColumns[0], Filename.size());
  for (StringRef Funcname : Functions)
    FunctionReportColumns[0] =
        std::max(FunctionReportColumns[0], Funcname.size());
}

/// \brief Prints a horizontal divider long enough to cover the given column
/// widths.
void renderDivider(ArrayRef<size_t> ColumnWidths, raw_ostream &OS) {
  size_t Length = std::accumulate(ColumnWidths.begin(), ColumnWidths.end(), 0);
  for (size_t I = 0; I < Length; ++I)
    OS << '-';
}

/// \brief Return the color which correponds to the coverage percentage of a
/// certain metric.
template <typename T>
raw_ostream::Colors determineCoveragePercentageColor(const T &Info) {
  if (Info.isFullyCovered())
    return raw_ostream::GREEN;
  return Info.getPercentCovered() >= 80.0 ? raw_ostream::YELLOW
                                          : raw_ostream::RED;
}

/// \brief Get the number of redundant path components in each path in \p Paths.
unsigned getNumRedundantPathComponents(ArrayRef<std::string> Paths) {
  // To start, set the number of redundant path components to the maximum
  // possible value.
  SmallVector<StringRef, 8> FirstPathComponents{sys::path::begin(Paths[0]),
                                                sys::path::end(Paths[0])};
  unsigned NumRedundant = FirstPathComponents.size();

  for (unsigned I = 1, E = Paths.size(); NumRedundant > 0 && I < E; ++I) {
    StringRef Path = Paths[I];
    for (const auto &Component :
         enumerate(make_range(sys::path::begin(Path), sys::path::end(Path)))) {
      // Do not increase the number of redundant components: that would remove
      // useful parts of already-visited paths.
      if (Component.Index >= NumRedundant)
        break;

      // Lower the number of redundant components when there's a mismatch
      // between the first path, and the path under consideration.
      if (FirstPathComponents[Component.Index] != Component.Value) {
        NumRedundant = Component.Index;
        break;
      }
    }
  }

  return NumRedundant;
}

/// \brief Determine the length of the longest redundant prefix of the paths in
/// \p Paths.
unsigned getRedundantPrefixLen(ArrayRef<std::string> Paths) {
  // If there's at most one path, no path components are redundant.
  if (Paths.size() <= 1)
    return 0;

  unsigned PrefixLen = 0;
  unsigned NumRedundant = getNumRedundantPathComponents(Paths);
  auto Component = sys::path::begin(Paths[0]);
  for (unsigned I = 0; I < NumRedundant; ++I) {
    auto LastComponent = Component;
    ++Component;
    PrefixLen += Component - LastComponent;
  }
  return PrefixLen;
}

} // end anonymous namespace

namespace llvm {

void CoverageReport::render(const FileCoverageSummary &File,
                            raw_ostream &OS) const {
  auto FileCoverageColor =
      determineCoveragePercentageColor(File.RegionCoverage);
  auto FuncCoverageColor =
      determineCoveragePercentageColor(File.FunctionCoverage);
  auto InstantiationCoverageColor =
      determineCoveragePercentageColor(File.InstantiationCoverage);
  auto LineCoverageColor = determineCoveragePercentageColor(File.LineCoverage);
  SmallString<256> FileName = File.Name;
  sys::path::remove_dots(FileName, /*remove_dot_dots=*/true);
  sys::path::native(FileName);
  OS << column(FileName, FileReportColumns[0], Column::NoTrim)
     << format("%*u", FileReportColumns[1],
               (unsigned)File.RegionCoverage.NumRegions);
  Options.colored_ostream(OS, FileCoverageColor) << format(
      "%*u", FileReportColumns[2], (unsigned)File.RegionCoverage.NotCovered);
  if (File.RegionCoverage.NumRegions)
    Options.colored_ostream(OS, FileCoverageColor)
        << format("%*.2f", FileReportColumns[3] - 1,
                  File.RegionCoverage.getPercentCovered())
        << '%';
  else
    OS << column("-", FileReportColumns[3], Column::RightAlignment);
  OS << format("%*u", FileReportColumns[4],
               (unsigned)File.FunctionCoverage.NumFunctions);
  OS << format("%*u", FileReportColumns[5],
               (unsigned)(File.FunctionCoverage.NumFunctions -
                          File.FunctionCoverage.Executed));
  if (File.FunctionCoverage.NumFunctions)
    Options.colored_ostream(OS, FuncCoverageColor)
        << format("%*.2f", FileReportColumns[6] - 1,
                  File.FunctionCoverage.getPercentCovered())
        << '%';
  else
    OS << column("-", FileReportColumns[6], Column::RightAlignment);
  OS << format("%*u", FileReportColumns[7],
               (unsigned)File.InstantiationCoverage.NumFunctions);
  OS << format("%*u", FileReportColumns[8],
               (unsigned)(File.InstantiationCoverage.NumFunctions -
                          File.InstantiationCoverage.Executed));
  if (File.InstantiationCoverage.NumFunctions)
    Options.colored_ostream(OS, InstantiationCoverageColor)
        << format("%*.2f", FileReportColumns[9] - 1,
                  File.InstantiationCoverage.getPercentCovered())
        << '%';
  else
    OS << column("-", FileReportColumns[9], Column::RightAlignment);
  OS << format("%*u", FileReportColumns[10],
               (unsigned)File.LineCoverage.NumLines);
  Options.colored_ostream(OS, LineCoverageColor) << format(
      "%*u", FileReportColumns[11], (unsigned)File.LineCoverage.NotCovered);
  if (File.LineCoverage.NumLines)
    Options.colored_ostream(OS, LineCoverageColor)
        << format("%*.2f", FileReportColumns[12] - 1,
                  File.LineCoverage.getPercentCovered())
        << '%';
  else
    OS << column("-", FileReportColumns[12], Column::RightAlignment);
  OS << "\n";
}

void CoverageReport::render(const FunctionCoverageSummary &Function,
                            const DemangleCache &DC,
                            raw_ostream &OS) const {
  auto FuncCoverageColor =
      determineCoveragePercentageColor(Function.RegionCoverage);
  auto LineCoverageColor =
      determineCoveragePercentageColor(Function.LineCoverage);
  OS << column(DC.demangle(Function.Name), FunctionReportColumns[0],
               Column::RightTrim)
     << format("%*u", FunctionReportColumns[1],
               (unsigned)Function.RegionCoverage.NumRegions);
  Options.colored_ostream(OS, FuncCoverageColor)
      << format("%*u", FunctionReportColumns[2],
                (unsigned)Function.RegionCoverage.NotCovered);
  Options.colored_ostream(
      OS, determineCoveragePercentageColor(Function.RegionCoverage))
      << format("%*.2f", FunctionReportColumns[3] - 1,
                Function.RegionCoverage.getPercentCovered())
      << '%';
  OS << format("%*u", FunctionReportColumns[4],
               (unsigned)Function.LineCoverage.NumLines);
  Options.colored_ostream(OS, LineCoverageColor)
      << format("%*u", FunctionReportColumns[5],
                (unsigned)Function.LineCoverage.NotCovered);
  Options.colored_ostream(
      OS, determineCoveragePercentageColor(Function.LineCoverage))
      << format("%*.2f", FunctionReportColumns[6] - 1,
                Function.LineCoverage.getPercentCovered())
      << '%';
  OS << "\n";
}

void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
                                           const DemangleCache &DC,
                                           raw_ostream &OS) {
  bool isFirst = true;
  for (StringRef Filename : Files) {
    auto Functions = Coverage.getCoveredFunctions(Filename);

    if (isFirst)
      isFirst = false;
    else
      OS << "\n";

    std::vector<StringRef> Funcnames;
    for (const auto &F : Functions)
      Funcnames.emplace_back(DC.demangle(F.Name));
    adjustColumnWidths({}, Funcnames);

    OS << "File '" << Filename << "':\n";
    OS << column("Name", FunctionReportColumns[0])
       << column("Regions", FunctionReportColumns[1], Column::RightAlignment)
       << column("Miss", FunctionReportColumns[2], Column::RightAlignment)
       << column("Cover", FunctionReportColumns[3], Column::RightAlignment)
       << column("Lines", FunctionReportColumns[4], Column::RightAlignment)
       << column("Miss", FunctionReportColumns[5], Column::RightAlignment)
       << column("Cover", FunctionReportColumns[6], Column::RightAlignment);
    OS << "\n";
    renderDivider(FunctionReportColumns, OS);
    OS << "\n";
    FunctionCoverageSummary Totals("TOTAL");
    for (const auto &F : Functions) {
      FunctionCoverageSummary Function = FunctionCoverageSummary::get(F);
      ++Totals.ExecutionCount;
      Totals.RegionCoverage += Function.RegionCoverage;
      Totals.LineCoverage += Function.LineCoverage;
      render(Function, DC, OS);
    }
    if (Totals.ExecutionCount) {
      renderDivider(FunctionReportColumns, OS);
      OS << "\n";
      render(Totals, DC, OS);
    }
  }
}

std::vector<FileCoverageSummary>
CoverageReport::prepareFileReports(const coverage::CoverageMapping &Coverage,
                                   FileCoverageSummary &Totals,
                                   ArrayRef<std::string> Files) {
  std::vector<FileCoverageSummary> FileReports;
  unsigned LCP = getRedundantPrefixLen(Files);

  for (StringRef Filename : Files) {
    FileCoverageSummary Summary(Filename.drop_front(LCP));

    // Map source locations to aggregate function coverage summaries.
    DenseMap<std::pair<unsigned, unsigned>, FunctionCoverageSummary> Summaries;

    for (const auto &F : Coverage.getCoveredFunctions(Filename)) {
      FunctionCoverageSummary Function = FunctionCoverageSummary::get(F);
      auto StartLoc = F.CountedRegions[0].startLoc();

      auto UniquedSummary = Summaries.insert({StartLoc, Function});
      if (!UniquedSummary.second)
        UniquedSummary.first->second.update(Function);

      Summary.addInstantiation(Function);
      Totals.addInstantiation(Function);
    }

    for (const auto &UniquedSummary : Summaries) {
      const FunctionCoverageSummary &FCS = UniquedSummary.second;
      Summary.addFunction(FCS);
      Totals.addFunction(FCS);
    }

    FileReports.push_back(Summary);
  }

  return FileReports;
}

void CoverageReport::renderFileReports(raw_ostream &OS) const {
  std::vector<std::string> UniqueSourceFiles;
  for (StringRef SF : Coverage.getUniqueSourceFiles())
    UniqueSourceFiles.emplace_back(SF.str());
  renderFileReports(OS, UniqueSourceFiles);
}

void CoverageReport::renderFileReports(raw_ostream &OS,
                                       ArrayRef<std::string> Files) const {
  FileCoverageSummary Totals("TOTAL");
  auto FileReports = prepareFileReports(Coverage, Totals, Files);

  std::vector<StringRef> Filenames;
  for (const FileCoverageSummary &FCS : FileReports)
    Filenames.emplace_back(FCS.Name);
  adjustColumnWidths(Filenames, {});

  OS << column("Filename", FileReportColumns[0])
     << column("Regions", FileReportColumns[1], Column::RightAlignment)
     << column("Missed Regions", FileReportColumns[2], Column::RightAlignment)
     << column("Cover", FileReportColumns[3], Column::RightAlignment)
     << column("Functions", FileReportColumns[4], Column::RightAlignment)
     << column("Missed Functions", FileReportColumns[5], Column::RightAlignment)
     << column("Executed", FileReportColumns[6], Column::RightAlignment)
     << column("Instantiations", FileReportColumns[7], Column::RightAlignment)
     << column("Missed Insts.", FileReportColumns[8], Column::RightAlignment)
     << column("Executed", FileReportColumns[9], Column::RightAlignment)
     << column("Lines", FileReportColumns[10], Column::RightAlignment)
     << column("Missed Lines", FileReportColumns[11], Column::RightAlignment)
     << column("Cover", FileReportColumns[12], Column::RightAlignment) << "\n";
  renderDivider(FileReportColumns, OS);
  OS << "\n";

  for (const FileCoverageSummary &FCS : FileReports)
    render(FCS, OS);

  renderDivider(FileReportColumns, OS);
  OS << "\n";
  render(Totals, OS);
}

} // end namespace llvm
<commit_msg>Use the new member accessors of llvm::enumerate.<commit_after>//===- CoverageReport.cpp - Code coverage report -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class implements rendering of a code coverage report.
//
//===----------------------------------------------------------------------===//

#include "CoverageReport.h"
#include "RenderingSupport.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Path.h"
#include <numeric>

using namespace llvm;

namespace {

/// \brief Helper struct which prints trimmed and aligned columns.
struct Column {
  enum TrimKind { NoTrim, WidthTrim, RightTrim };

  enum AlignmentKind { LeftAlignment, RightAlignment };

  StringRef Str;
  unsigned Width;
  TrimKind Trim;
  AlignmentKind Alignment;

  Column(StringRef Str, unsigned Width)
      : Str(Str), Width(Width), Trim(WidthTrim), Alignment(LeftAlignment) {}

  Column &set(TrimKind Value) {
    Trim = Value;
    return *this;
  }

  Column &set(AlignmentKind Value) {
    Alignment = Value;
    return *this;
  }

  void render(raw_ostream &OS) const {
    if (Str.size() <= Width) {
      if (Alignment == RightAlignment) {
        OS.indent(Width - Str.size());
        OS << Str;
        return;
      }
      OS << Str;
      OS.indent(Width - Str.size());
      return;
    }

    switch (Trim) {
    case NoTrim:
      OS << Str;
      break;
    case WidthTrim:
      OS << Str.substr(0, Width);
      break;
    case RightTrim:
      OS << Str.substr(0, Width - 3) << "...";
      break;
    }
  }
};

raw_ostream &operator<<(raw_ostream &OS, const Column &Value) {
  Value.render(OS);
  return OS;
}

Column column(StringRef Str, unsigned Width) { return Column(Str, Width); }

template <typename T>
Column column(StringRef Str, unsigned Width, const T &Value) {
  return Column(Str, Width).set(Value);
}

// Specify the default column widths.
size_t FileReportColumns[] = {25, 12, 18, 10, 12, 18, 10,
                              16, 16, 10, 12, 18, 10};
size_t FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8};

/// \brief Adjust column widths to fit long file paths and function names.
void adjustColumnWidths(ArrayRef<StringRef> Files,
                        ArrayRef<StringRef> Functions) {
  for (StringRef Filename : Files)
    FileReportColumns[0] = std::max(FileReportColumns[0], Filename.size());
  for (StringRef Funcname : Functions)
    FunctionReportColumns[0] =
        std::max(FunctionReportColumns[0], Funcname.size());
}

/// \brief Prints a horizontal divider long enough to cover the given column
/// widths.
void renderDivider(ArrayRef<size_t> ColumnWidths, raw_ostream &OS) {
  size_t Length = std::accumulate(ColumnWidths.begin(), ColumnWidths.end(), 0);
  for (size_t I = 0; I < Length; ++I)
    OS << '-';
}

/// \brief Return the color which correponds to the coverage percentage of a
/// certain metric.
template <typename T>
raw_ostream::Colors determineCoveragePercentageColor(const T &Info) {
  if (Info.isFullyCovered())
    return raw_ostream::GREEN;
  return Info.getPercentCovered() >= 80.0 ? raw_ostream::YELLOW
                                          : raw_ostream::RED;
}

/// \brief Get the number of redundant path components in each path in \p Paths.
unsigned getNumRedundantPathComponents(ArrayRef<std::string> Paths) {
  // To start, set the number of redundant path components to the maximum
  // possible value.
  SmallVector<StringRef, 8> FirstPathComponents{sys::path::begin(Paths[0]),
                                                sys::path::end(Paths[0])};
  unsigned NumRedundant = FirstPathComponents.size();

  for (unsigned I = 1, E = Paths.size(); NumRedundant > 0 && I < E; ++I) {
    StringRef Path = Paths[I];
    for (const auto &Component :
         enumerate(make_range(sys::path::begin(Path), sys::path::end(Path)))) {
      // Do not increase the number of redundant components: that would remove
      // useful parts of already-visited paths.
      if (Component.index() >= NumRedundant)
        break;

      // Lower the number of redundant components when there's a mismatch
      // between the first path, and the path under consideration.
      if (FirstPathComponents[Component.index()] != Component.value()) {
        NumRedundant = Component.index();
        break;
      }
    }
  }

  return NumRedundant;
}

/// \brief Determine the length of the longest redundant prefix of the paths in
/// \p Paths.
unsigned getRedundantPrefixLen(ArrayRef<std::string> Paths) {
  // If there's at most one path, no path components are redundant.
  if (Paths.size() <= 1)
    return 0;

  unsigned PrefixLen = 0;
  unsigned NumRedundant = getNumRedundantPathComponents(Paths);
  auto Component = sys::path::begin(Paths[0]);
  for (unsigned I = 0; I < NumRedundant; ++I) {
    auto LastComponent = Component;
    ++Component;
    PrefixLen += Component - LastComponent;
  }
  return PrefixLen;
}

} // end anonymous namespace

namespace llvm {

void CoverageReport::render(const FileCoverageSummary &File,
                            raw_ostream &OS) const {
  auto FileCoverageColor =
      determineCoveragePercentageColor(File.RegionCoverage);
  auto FuncCoverageColor =
      determineCoveragePercentageColor(File.FunctionCoverage);
  auto InstantiationCoverageColor =
      determineCoveragePercentageColor(File.InstantiationCoverage);
  auto LineCoverageColor = determineCoveragePercentageColor(File.LineCoverage);
  SmallString<256> FileName = File.Name;
  sys::path::remove_dots(FileName, /*remove_dot_dots=*/true);
  sys::path::native(FileName);
  OS << column(FileName, FileReportColumns[0], Column::NoTrim)
     << format("%*u", FileReportColumns[1],
               (unsigned)File.RegionCoverage.NumRegions);
  Options.colored_ostream(OS, FileCoverageColor) << format(
      "%*u", FileReportColumns[2], (unsigned)File.RegionCoverage.NotCovered);
  if (File.RegionCoverage.NumRegions)
    Options.colored_ostream(OS, FileCoverageColor)
        << format("%*.2f", FileReportColumns[3] - 1,
                  File.RegionCoverage.getPercentCovered())
        << '%';
  else
    OS << column("-", FileReportColumns[3], Column::RightAlignment);
  OS << format("%*u", FileReportColumns[4],
               (unsigned)File.FunctionCoverage.NumFunctions);
  OS << format("%*u", FileReportColumns[5],
               (unsigned)(File.FunctionCoverage.NumFunctions -
                          File.FunctionCoverage.Executed));
  if (File.FunctionCoverage.NumFunctions)
    Options.colored_ostream(OS, FuncCoverageColor)
        << format("%*.2f", FileReportColumns[6] - 1,
                  File.FunctionCoverage.getPercentCovered())
        << '%';
  else
    OS << column("-", FileReportColumns[6], Column::RightAlignment);
  OS << format("%*u", FileReportColumns[7],
               (unsigned)File.InstantiationCoverage.NumFunctions);
  OS << format("%*u", FileReportColumns[8],
               (unsigned)(File.InstantiationCoverage.NumFunctions -
                          File.InstantiationCoverage.Executed));
  if (File.InstantiationCoverage.NumFunctions)
    Options.colored_ostream(OS, InstantiationCoverageColor)
        << format("%*.2f", FileReportColumns[9] - 1,
                  File.InstantiationCoverage.getPercentCovered())
        << '%';
  else
    OS << column("-", FileReportColumns[9], Column::RightAlignment);
  OS << format("%*u", FileReportColumns[10],
               (unsigned)File.LineCoverage.NumLines);
  Options.colored_ostream(OS, LineCoverageColor) << format(
      "%*u", FileReportColumns[11], (unsigned)File.LineCoverage.NotCovered);
  if (File.LineCoverage.NumLines)
    Options.colored_ostream(OS, LineCoverageColor)
        << format("%*.2f", FileReportColumns[12] - 1,
                  File.LineCoverage.getPercentCovered())
        << '%';
  else
    OS << column("-", FileReportColumns[12], Column::RightAlignment);
  OS << "\n";
}

void CoverageReport::render(const FunctionCoverageSummary &Function,
                            const DemangleCache &DC,
                            raw_ostream &OS) const {
  auto FuncCoverageColor =
      determineCoveragePercentageColor(Function.RegionCoverage);
  auto LineCoverageColor =
      determineCoveragePercentageColor(Function.LineCoverage);
  OS << column(DC.demangle(Function.Name), FunctionReportColumns[0],
               Column::RightTrim)
     << format("%*u", FunctionReportColumns[1],
               (unsigned)Function.RegionCoverage.NumRegions);
  Options.colored_ostream(OS, FuncCoverageColor)
      << format("%*u", FunctionReportColumns[2],
                (unsigned)Function.RegionCoverage.NotCovered);
  Options.colored_ostream(
      OS, determineCoveragePercentageColor(Function.RegionCoverage))
      << format("%*.2f", FunctionReportColumns[3] - 1,
                Function.RegionCoverage.getPercentCovered())
      << '%';
  OS << format("%*u", FunctionReportColumns[4],
               (unsigned)Function.LineCoverage.NumLines);
  Options.colored_ostream(OS, LineCoverageColor)
      << format("%*u", FunctionReportColumns[5],
                (unsigned)Function.LineCoverage.NotCovered);
  Options.colored_ostream(
      OS, determineCoveragePercentageColor(Function.LineCoverage))
      << format("%*.2f", FunctionReportColumns[6] - 1,
                Function.LineCoverage.getPercentCovered())
      << '%';
  OS << "\n";
}

void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
                                           const DemangleCache &DC,
                                           raw_ostream &OS) {
  bool isFirst = true;
  for (StringRef Filename : Files) {
    auto Functions = Coverage.getCoveredFunctions(Filename);

    if (isFirst)
      isFirst = false;
    else
      OS << "\n";

    std::vector<StringRef> Funcnames;
    for (const auto &F : Functions)
      Funcnames.emplace_back(DC.demangle(F.Name));
    adjustColumnWidths({}, Funcnames);

    OS << "File '" << Filename << "':\n";
    OS << column("Name", FunctionReportColumns[0])
       << column("Regions", FunctionReportColumns[1], Column::RightAlignment)
       << column("Miss", FunctionReportColumns[2], Column::RightAlignment)
       << column("Cover", FunctionReportColumns[3], Column::RightAlignment)
       << column("Lines", FunctionReportColumns[4], Column::RightAlignment)
       << column("Miss", FunctionReportColumns[5], Column::RightAlignment)
       << column("Cover", FunctionReportColumns[6], Column::RightAlignment);
    OS << "\n";
    renderDivider(FunctionReportColumns, OS);
    OS << "\n";
    FunctionCoverageSummary Totals("TOTAL");
    for (const auto &F : Functions) {
      FunctionCoverageSummary Function = FunctionCoverageSummary::get(F);
      ++Totals.ExecutionCount;
      Totals.RegionCoverage += Function.RegionCoverage;
      Totals.LineCoverage += Function.LineCoverage;
      render(Function, DC, OS);
    }
    if (Totals.ExecutionCount) {
      renderDivider(FunctionReportColumns, OS);
      OS << "\n";
      render(Totals, DC, OS);
    }
  }
}

std::vector<FileCoverageSummary>
CoverageReport::prepareFileReports(const coverage::CoverageMapping &Coverage,
                                   FileCoverageSummary &Totals,
                                   ArrayRef<std::string> Files) {
  std::vector<FileCoverageSummary> FileReports;
  unsigned LCP = getRedundantPrefixLen(Files);

  for (StringRef Filename : Files) {
    FileCoverageSummary Summary(Filename.drop_front(LCP));

    // Map source locations to aggregate function coverage summaries.
    DenseMap<std::pair<unsigned, unsigned>, FunctionCoverageSummary> Summaries;

    for (const auto &F : Coverage.getCoveredFunctions(Filename)) {
      FunctionCoverageSummary Function = FunctionCoverageSummary::get(F);
      auto StartLoc = F.CountedRegions[0].startLoc();

      auto UniquedSummary = Summaries.insert({StartLoc, Function});
      if (!UniquedSummary.second)
        UniquedSummary.first->second.update(Function);

      Summary.addInstantiation(Function);
      Totals.addInstantiation(Function);
    }

    for (const auto &UniquedSummary : Summaries) {
      const FunctionCoverageSummary &FCS = UniquedSummary.second;
      Summary.addFunction(FCS);
      Totals.addFunction(FCS);
    }

    FileReports.push_back(Summary);
  }

  return FileReports;
}

void CoverageReport::renderFileReports(raw_ostream &OS) const {
  std::vector<std::string> UniqueSourceFiles;
  for (StringRef SF : Coverage.getUniqueSourceFiles())
    UniqueSourceFiles.emplace_back(SF.str());
  renderFileReports(OS, UniqueSourceFiles);
}

void CoverageReport::renderFileReports(raw_ostream &OS,
                                       ArrayRef<std::string> Files) const {
  FileCoverageSummary Totals("TOTAL");
  auto FileReports = prepareFileReports(Coverage, Totals, Files);

  std::vector<StringRef> Filenames;
  for (const FileCoverageSummary &FCS : FileReports)
    Filenames.emplace_back(FCS.Name);
  adjustColumnWidths(Filenames, {});

  OS << column("Filename", FileReportColumns[0])
     << column("Regions", FileReportColumns[1], Column::RightAlignment)
     << column("Missed Regions", FileReportColumns[2], Column::RightAlignment)
     << column("Cover", FileReportColumns[3], Column::RightAlignment)
     << column("Functions", FileReportColumns[4], Column::RightAlignment)
     << column("Missed Functions", FileReportColumns[5], Column::RightAlignment)
     << column("Executed", FileReportColumns[6], Column::RightAlignment)
     << column("Instantiations", FileReportColumns[7], Column::RightAlignment)
     << column("Missed Insts.", FileReportColumns[8], Column::RightAlignment)
     << column("Executed", FileReportColumns[9], Column::RightAlignment)
     << column("Lines", FileReportColumns[10], Column::RightAlignment)
     << column("Missed Lines", FileReportColumns[11], Column::RightAlignment)
     << column("Cover", FileReportColumns[12], Column::RightAlignment) << "\n";
  renderDivider(FileReportColumns, OS);
  OS << "\n";

  for (const FileCoverageSummary &FCS : FileReports)
    render(FCS, OS);

  renderDivider(FileReportColumns, OS);
  OS << "\n";
  render(Totals, OS);
}

} // end namespace llvm
<|endoftext|>


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

#include <string>

#include "base/logging.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_util.h"
#include "testing/gtest/include/gtest/gtest.h"

class DownloadManagerTest : public testing::Test {
 public:
  DownloadManagerTest() {
    download_manager_ = new DownloadManager();
    download_util::InitializeExeTypes(&download_manager_->exe_types_);
  }

  void GetGeneratedFilename(const std::string& content_disposition,
                            const std::wstring& url,
                            const std::string& mime_type,
                            std::wstring* generated_name_string) {
    DownloadCreateInfo info;
    info.content_disposition = content_disposition;
    info.url = url;
    info.mime_type = mime_type;
    FilePath generated_name;
    download_manager_->GenerateFilename(&info, &generated_name);
    *generated_name_string = generated_name.ToWStringHack();
  }

 protected:
  scoped_refptr<DownloadManager> download_manager_;
  MessageLoopForUI message_loop_;

  DISALLOW_EVIL_CONSTRUCTORS(DownloadManagerTest);
};

namespace {

const struct {
  const char* disposition;
  const wchar_t* url;
  const char* mime_type;
  const wchar_t* expected_name;
} kGeneratedFiles[] = {
  // No 'filename' keyword in the disposition, use the URL
  {"a_file_name.txt",
   L"http://www.evil.com/my_download.txt",
   "text/plain",
   L"my_download.txt"},

  // Disposition has relative paths, remove them
  {"filename=../../../../././../a_file_name.txt",
   L"http://www.evil.com/my_download.txt",
   "text/plain",
   L"a_file_name.txt"},

  // Disposition has parent directories, remove them
  {"filename=dir1/dir2/a_file_name.txt",
   L"http://www.evil.com/my_download.txt",
   "text/plain",
   L"a_file_name.txt"},

  // No useful information in disposition or URL, use default
  {"", L"http://www.truncated.com/path/", "text/plain", L"download.txt"},

  // Spaces in the disposition file name
  {"filename=My Downloaded File.exe",
   L"http://www.frontpagehacker.com/a_download.exe",
   "application/octet-stream",
   L"My Downloaded File.exe"},

  {"filename=my-cat",
   L"http://www.example.com/my-cat",
   "image/jpeg",
   L"my-cat.jpg"},

  {"filename=my-cat",
   L"http://www.example.com/my-cat",
   "text/plain",
   L"my-cat.txt"},

  {"filename=my-cat",
   L"http://www.example.com/my-cat",
   "text/html",
   L"my-cat.htm"},

  {"filename=my-cat",
   L"http://www.example.com/my-cat",
   "dance/party",
   L"my-cat"},

  {"filename=my-cat.jpg",
   L"http://www.example.com/my-cat.jpg",
   "text/plain",
   L"my-cat.jpg"},

  {"filename=evil.exe",
   L"http://www.goodguy.com/evil.exe",
   "image/jpeg",
   L"evil.jpg"},

  {"filename=ok.exe",
   L"http://www.goodguy.com/ok.exe",
   "binary/octet-stream",
   L"ok.exe"},

  {"filename=evil.exe.exe",
   L"http://www.goodguy.com/evil.exe.exe",
   "dance/party",
   L"evil.exe.download"},

  {"filename=evil.exe",
   L"http://www.goodguy.com/evil.exe",
   "application/xml",
   L"evil.xml"},

  {"filename=evil.exe",
   L"http://www.goodguy.com/evil.exe",
   "application/html+xml",
   L"evil.download"},

  {"filename=evil.exe",
   L"http://www.goodguy.com/evil.exe",
   "application/rss+xml",
   L"evil.download"},

  {"filename=utils.js",
   L"http://www.goodguy.com/utils.js",
   "application/x-javascript",
   L"utils.js"},

  {"filename=contacts.js",
   L"http://www.goodguy.com/contacts.js",
   "application/json",
   L"contacts.js"},

  {"filename=utils.js",
   L"http://www.goodguy.com/utils.js",
   "text/javascript",
   L"utils.js"},

  {"filename=utils.js",
   L"http://www.goodguy.com/utils.js",
   "text/javascript;version=2",
   L"utils.js"},

  {"filename=utils.js",
   L"http://www.goodguy.com/utils.js",
   "application/ecmascript",
   L"utils.js"},

  {"filename=utils.js",
   L"http://www.goodguy.com/utils.js",
   "application/ecmascript;version=4",
   L"utils.js"},

  {"filename=program.exe",
   L"http://www.goodguy.com/program.exe",
   "application/foo-bar",
   L"program.exe"},

  {"filename=../foo.txt",
   L"http://www.evil.com/../foo.txt",
   "text/plain",
   L"foo.txt"},

  {"filename=..\\foo.txt",
   L"http://www.evil.com/..\\foo.txt",
   "text/plain",
   L"foo.txt"},

  {"filename=.hidden",
   L"http://www.evil.com/.hidden",
   "text/plain",
   L"hidden.txt"},

  {"filename=trailing.",
   L"http://www.evil.com/trailing.",
   "dance/party",
   L"trailing"},

  {"filename=trailing.",
   L"http://www.evil.com/trailing.",
   "text/plain",
   L"trailing.txt"},

  {"filename=.",
   L"http://www.evil.com/.",
   "dance/party",
   L"download"},

  {"filename=..",
   L"http://www.evil.com/..",
   "dance/party",
   L"download"},

  {"filename=...",
   L"http://www.evil.com/...",
   "dance/party",
   L"download"},

  {"a_file_name.txt",
   L"http://www.evil.com/",
   "image/jpeg",
   L"download.jpg"},

  {"filename=",
   L"http://www.evil.com/",
   "image/jpeg",
   L"download.jpg"},

  {"filename=simple",
   L"http://www.example.com/simple",
   "application/octet-stream",
   L"simple"},

  {"filename=COM1",
   L"http://www.goodguy.com/COM1",
   "application/foo-bar",
   L"_COM1"},

  {"filename=COM4.txt",
   L"http://www.goodguy.com/COM4.txt",
   "text/plain",
   L"_COM4.txt"},

  {"filename=lpt1.TXT",
   L"http://www.goodguy.com/lpt1.TXT",
   "text/plain",
   L"_lpt1.TXT"},

  {"filename=clock$.txt",
   L"http://www.goodguy.com/clock$.txt",
   "text/plain",
   L"_clock$.txt"},

  {"filename=mycom1.foo",
   L"http://www.goodguy.com/mycom1.foo",
   "text/plain",
   L"mycom1.foo"},

  {"filename=Setup.exe.local",
   L"http://www.badguy.com/Setup.exe.local",
   "application/foo-bar",
   L"Setup.exe.download"},

  {"filename=Setup.exe.local.local",
   L"http://www.badguy.com/Setup.exe.local",
   "application/foo-bar",
   L"Setup.exe.local.download"},

  {"filename=Setup.exe.lnk",
   L"http://www.badguy.com/Setup.exe.lnk",
   "application/foo-bar",
   L"Setup.exe.download"},

  {"filename=Desktop.ini",
   L"http://www.badguy.com/Desktop.ini",
   "application/foo-bar",
   L"_Desktop.ini"},

  {"filename=Thumbs.db",
   L"http://www.badguy.com/Thumbs.db",
   "application/foo-bar",
   L"_Thumbs.db"},

  {"filename=source.srf",
   L"http://www.hotmail.com",
   "image/jpeg",
   L"source.srf.jpg"},

  {"filename=source.jpg",
   L"http://www.hotmail.com",
   "application/x-javascript",
   L"source.jpg"},

  // NetUtilTest.{GetSuggestedFilename, GetFileNameFromCD} test these
  // more thoroughly. Tested below are a small set of samples.
  {"attachment; filename=\"%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg\"",
   L"http://www.examples.com/",
   "image/jpeg",
   L"\uc608\uc220 \uc608\uc220.jpg"},

  {"attachment; name=abc de.pdf",
   L"http://www.examples.com/q.cgi?id=abc",
   "application/octet-stream",
   L"abc de.pdf"},

  {"filename=\"=?EUC-JP?Q?=B7=DD=BD=D13=2Epng?=\"",
   L"http://www.example.com/path",
   "image/png",
   L"\x82b8\x8853" L"3.png"},

  // The following two have invalid CD headers and filenames come
  // from the URL.
  {"attachment; filename==?iiso88591?Q?caf=EG?=",
   L"http://www.example.com/test%20123",
   "image/jpeg",
   L"test 123.jpg"},

  {"malformed_disposition",
   L"http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
   "image/jpeg",
   L"\uc608\uc220 \uc608\uc220.jpg"},

  // Invalid C-D. No filename from URL. Falls back to 'download'.
  {"attachment; filename==?iso88591?Q?caf=E3?",
   L"http://www.google.com/path1/path2/",
   "image/jpeg",
   L"download.jpg"},

  // TODO(darin): Add some raw 8-bit Content-Disposition tests.
};

}  // namespace

// Tests to ensure that the file names we generate from hints from the server
// (content-disposition, URL name, etc) don't cause security holes.
TEST_F(DownloadManagerTest, TestDownloadFilename) {
  for (int i = 0; i < arraysize(kGeneratedFiles); ++i) {
    std::wstring file_name;
    GetGeneratedFilename(kGeneratedFiles[i].disposition,
                         kGeneratedFiles[i].url,
                         kGeneratedFiles[i].mime_type,
                         &file_name);
    EXPECT_EQ(kGeneratedFiles[i].expected_name, file_name);
  }
}

namespace {

const struct {
  const FilePath::CharType* path;
  const char* mime_type;
  const FilePath::CharType* expected_path;
} kSafeFilenameCases[] = {
  { FILE_PATH_LITERAL("C:\\foo\\bar.htm"),
    "text/html",
    FILE_PATH_LITERAL("C:\\foo\\bar.htm") },
  { FILE_PATH_LITERAL("C:\\foo\\bar.html"),
    "text/html",
    FILE_PATH_LITERAL("C:\\foo\\bar.html") },
  { FILE_PATH_LITERAL("C:\\foo\\bar"),
    "text/html",
    FILE_PATH_LITERAL("C:\\foo\\bar.htm") },

  { FILE_PATH_LITERAL("C:\\bar.html"),
    "image/png",
    FILE_PATH_LITERAL("C:\\bar.png") },
  { FILE_PATH_LITERAL("C:\\bar"),
    "image/png",
    FILE_PATH_LITERAL("C:\\bar.png") },

  { FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
    "text/html",
    FILE_PATH_LITERAL("C:\\foo\\bar.htm") },
  { FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
    "image/gif",
    FILE_PATH_LITERAL("C:\\foo\\bar.gif") },

  { FILE_PATH_LITERAL("C:\\foo\\google.com"),
    "text/html",
    FILE_PATH_LITERAL("C:\\foo\\google.htm") },

  { FILE_PATH_LITERAL("C:\\foo\\con.htm"),
    "text/html",
    FILE_PATH_LITERAL("C:\\foo\\_con.htm") },
  { FILE_PATH_LITERAL("C:\\foo\\con"),
    "text/html",
    FILE_PATH_LITERAL("C:\\foo\\_con.htm") },
};

}  // namespace

TEST_F(DownloadManagerTest, GetSafeFilename) {
  for (int i = 0; i < arraysize(kSafeFilenameCases); ++i) {
    FilePath path(kSafeFilenameCases[i].path);
    download_manager_->GenerateSafeFilename(kSafeFilenameCases[i].mime_type,
        &path);
    EXPECT_EQ(kSafeFilenameCases[i].expected_path, path.value());
  }
}
<commit_msg>disable download test while sid fixes offline<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>

#include "base/logging.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_util.h"
#include "testing/gtest/include/gtest/gtest.h"

class DownloadManagerTest : public testing::Test {
 public:
  DownloadManagerTest() {
    download_manager_ = new DownloadManager();
    download_util::InitializeExeTypes(&download_manager_->exe_types_);
  }

  void GetGeneratedFilename(const std::string& content_disposition,
                            const std::wstring& url,
                            const std::string& mime_type,
                            std::wstring* generated_name_string) {
    DownloadCreateInfo info;
    info.content_disposition = content_disposition;
    info.url = url;
    info.mime_type = mime_type;
    FilePath generated_name;
    download_manager_->GenerateFilename(&info, &generated_name);
    *generated_name_string = generated_name.ToWStringHack();
  }

 protected:
  scoped_refptr<DownloadManager> download_manager_;
  MessageLoopForUI message_loop_;

  DISALLOW_EVIL_CONSTRUCTORS(DownloadManagerTest);
};

namespace {

const struct {
  const char* disposition;
  const wchar_t* url;
  const char* mime_type;
  const wchar_t* expected_name;
} kGeneratedFiles[] = {
  // No 'filename' keyword in the disposition, use the URL
  {"a_file_name.txt",
   L"http://www.evil.com/my_download.txt",
   "text/plain",
   L"my_download.txt"},

  // Disposition has relative paths, remove them
  {"filename=../../../../././../a_file_name.txt",
   L"http://www.evil.com/my_download.txt",
   "text/plain",
   L"a_file_name.txt"},

  // Disposition has parent directories, remove them
  {"filename=dir1/dir2/a_file_name.txt",
   L"http://www.evil.com/my_download.txt",
   "text/plain",
   L"a_file_name.txt"},

  // No useful information in disposition or URL, use default
  {"", L"http://www.truncated.com/path/", "text/plain", L"download.txt"},

  // Spaces in the disposition file name
  {"filename=My Downloaded File.exe",
   L"http://www.frontpagehacker.com/a_download.exe",
   "application/octet-stream",
   L"My Downloaded File.exe"},

  {"filename=my-cat",
   L"http://www.example.com/my-cat",
   "image/jpeg",
   L"my-cat.jpg"},

  {"filename=my-cat",
   L"http://www.example.com/my-cat",
   "text/plain",
   L"my-cat.txt"},

  {"filename=my-cat",
   L"http://www.example.com/my-cat",
   "text/html",
   L"my-cat.htm"},

  {"filename=my-cat",
   L"http://www.example.com/my-cat",
   "dance/party",
   L"my-cat"},

  {"filename=my-cat.jpg",
   L"http://www.example.com/my-cat.jpg",
   "text/plain",
   L"my-cat.jpg"},

  {"filename=evil.exe",
   L"http://www.goodguy.com/evil.exe",
   "image/jpeg",
   L"evil.jpg"},

  {"filename=ok.exe",
   L"http://www.goodguy.com/ok.exe",
   "binary/octet-stream",
   L"ok.exe"},

  {"filename=evil.exe.exe",
   L"http://www.goodguy.com/evil.exe.exe",
   "dance/party",
   L"evil.exe.download"},

  {"filename=evil.exe",
   L"http://www.goodguy.com/evil.exe",
   "application/xml",
   L"evil.xml"},

  {"filename=evil.exe",
   L"http://www.goodguy.com/evil.exe",
   "application/html+xml",
   L"evil.download"},

  {"filename=evil.exe",
   L"http://www.goodguy.com/evil.exe",
   "application/rss+xml",
   L"evil.download"},

  {"filename=utils.js",
   L"http://www.goodguy.com/utils.js",
   "application/x-javascript",
   L"utils.js"},

  {"filename=contacts.js",
   L"http://www.goodguy.com/contacts.js",
   "application/json",
   L"contacts.js"},

  {"filename=utils.js",
   L"http://www.goodguy.com/utils.js",
   "text/javascript",
   L"utils.js"},

  {"filename=utils.js",
   L"http://www.goodguy.com/utils.js",
   "text/javascript;version=2",
   L"utils.js"},

  {"filename=utils.js",
   L"http://www.goodguy.com/utils.js",
   "application/ecmascript",
   L"utils.js"},

  {"filename=utils.js",
   L"http://www.goodguy.com/utils.js",
   "application/ecmascript;version=4",
   L"utils.js"},

  {"filename=program.exe",
   L"http://www.goodguy.com/program.exe",
   "application/foo-bar",
   L"program.exe"},

  {"filename=../foo.txt",
   L"http://www.evil.com/../foo.txt",
   "text/plain",
   L"foo.txt"},

  {"filename=..\\foo.txt",
   L"http://www.evil.com/..\\foo.txt",
   "text/plain",
   L"foo.txt"},

  {"filename=.hidden",
   L"http://www.evil.com/.hidden",
   "text/plain",
   L"hidden.txt"},

  {"filename=trailing.",
   L"http://www.evil.com/trailing.",
   "dance/party",
   L"trailing"},

  {"filename=trailing.",
   L"http://www.evil.com/trailing.",
   "text/plain",
   L"trailing.txt"},

  {"filename=.",
   L"http://www.evil.com/.",
   "dance/party",
   L"download"},

  {"filename=..",
   L"http://www.evil.com/..",
   "dance/party",
   L"download"},

  {"filename=...",
   L"http://www.evil.com/...",
   "dance/party",
   L"download"},

  {"a_file_name.txt",
   L"http://www.evil.com/",
   "image/jpeg",
   L"download.jpg"},

  {"filename=",
   L"http://www.evil.com/",
   "image/jpeg",
   L"download.jpg"},

  {"filename=simple",
   L"http://www.example.com/simple",
   "application/octet-stream",
   L"simple"},

  {"filename=COM1",
   L"http://www.goodguy.com/COM1",
   "application/foo-bar",
   L"_COM1"},

  {"filename=COM4.txt",
   L"http://www.goodguy.com/COM4.txt",
   "text/plain",
   L"_COM4.txt"},

  {"filename=lpt1.TXT",
   L"http://www.goodguy.com/lpt1.TXT",
   "text/plain",
   L"_lpt1.TXT"},

  {"filename=clock$.txt",
   L"http://www.goodguy.com/clock$.txt",
   "text/plain",
   L"_clock$.txt"},

  {"filename=mycom1.foo",
   L"http://www.goodguy.com/mycom1.foo",
   "text/plain",
   L"mycom1.foo"},

  {"filename=Setup.exe.local",
   L"http://www.badguy.com/Setup.exe.local",
   "application/foo-bar",
   L"Setup.exe.download"},

  {"filename=Setup.exe.local.local",
   L"http://www.badguy.com/Setup.exe.local",
   "application/foo-bar",
   L"Setup.exe.local.download"},

  {"filename=Setup.exe.lnk",
   L"http://www.badguy.com/Setup.exe.lnk",
   "application/foo-bar",
   L"Setup.exe.download"},

  {"filename=Desktop.ini",
   L"http://www.badguy.com/Desktop.ini",
   "application/foo-bar",
   L"_Desktop.ini"},

  {"filename=Thumbs.db",
   L"http://www.badguy.com/Thumbs.db",
   "application/foo-bar",
   L"_Thumbs.db"},

  {"filename=source.srf",
   L"http://www.hotmail.com",
   "image/jpeg",
   L"source.srf.jpg"},

  {"filename=source.jpg",
   L"http://www.hotmail.com",
   "application/x-javascript",
   L"source.jpg"},

  // NetUtilTest.{GetSuggestedFilename, GetFileNameFromCD} test these
  // more thoroughly. Tested below are a small set of samples.
  {"attachment; filename=\"%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg\"",
   L"http://www.examples.com/",
   "image/jpeg",
   L"\uc608\uc220 \uc608\uc220.jpg"},

  {"attachment; name=abc de.pdf",
   L"http://www.examples.com/q.cgi?id=abc",
   "application/octet-stream",
   L"abc de.pdf"},

  {"filename=\"=?EUC-JP?Q?=B7=DD=BD=D13=2Epng?=\"",
   L"http://www.example.com/path",
   "image/png",
   L"\x82b8\x8853" L"3.png"},

  // The following two have invalid CD headers and filenames come
  // from the URL.
  {"attachment; filename==?iiso88591?Q?caf=EG?=",
   L"http://www.example.com/test%20123",
   "image/jpeg",
   L"test 123.jpg"},

  {"malformed_disposition",
   L"http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
   "image/jpeg",
   L"\uc608\uc220 \uc608\uc220.jpg"},

  // Invalid C-D. No filename from URL. Falls back to 'download'.
  {"attachment; filename==?iso88591?Q?caf=E3?",
   L"http://www.google.com/path1/path2/",
   "image/jpeg",
   L"download.jpg"},

  // TODO(darin): Add some raw 8-bit Content-Disposition tests.
};

}  // namespace

// Tests to ensure that the file names we generate from hints from the server
// (content-disposition, URL name, etc) don't cause security holes.
TEST_F(DownloadManagerTest, DISABLED_TestDownloadFilename) {
  for (int i = 0; i < arraysize(kGeneratedFiles); ++i) {
    std::wstring file_name;
    GetGeneratedFilename(kGeneratedFiles[i].disposition,
                         kGeneratedFiles[i].url,
                         kGeneratedFiles[i].mime_type,
                         &file_name);
    EXPECT_EQ(kGeneratedFiles[i].expected_name, file_name);
  }
}

namespace {

const struct {
  const FilePath::CharType* path;
  const char* mime_type;
  const FilePath::CharType* expected_path;
} kSafeFilenameCases[] = {
  { FILE_PATH_LITERAL("C:\\foo\\bar.htm"),
    "text/html",
    FILE_PATH_LITERAL("C:\\foo\\bar.htm") },
  { FILE_PATH_LITERAL("C:\\foo\\bar.html"),
    "text/html",
    FILE_PATH_LITERAL("C:\\foo\\bar.html") },
  { FILE_PATH_LITERAL("C:\\foo\\bar"),
    "text/html",
    FILE_PATH_LITERAL("C:\\foo\\bar.htm") },

  { FILE_PATH_LITERAL("C:\\bar.html"),
    "image/png",
    FILE_PATH_LITERAL("C:\\bar.png") },
  { FILE_PATH_LITERAL("C:\\bar"),
    "image/png",
    FILE_PATH_LITERAL("C:\\bar.png") },

  { FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
    "text/html",
    FILE_PATH_LITERAL("C:\\foo\\bar.htm") },
  { FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
    "image/gif",
    FILE_PATH_LITERAL("C:\\foo\\bar.gif") },

  { FILE_PATH_LITERAL("C:\\foo\\google.com"),
    "text/html",
    FILE_PATH_LITERAL("C:\\foo\\google.htm") },

  { FILE_PATH_LITERAL("C:\\foo\\con.htm"),
    "text/html",
    FILE_PATH_LITERAL("C:\\foo\\_con.htm") },
  { FILE_PATH_LITERAL("C:\\foo\\con"),
    "text/html",
    FILE_PATH_LITERAL("C:\\foo\\_con.htm") },
};

}  // namespace

TEST_F(DownloadManagerTest, GetSafeFilename) {
  for (int i = 0; i < arraysize(kSafeFilenameCases); ++i) {
    FilePath path(kSafeFilenameCases[i].path);
    download_manager_->GenerateSafeFilename(kSafeFilenameCases[i].mime_type,
        &path);
    EXPECT_EQ(kSafeFilenameCases[i].expected_path, path.value());
  }
}
<|endoftext|>